Begin experiment
This commit is contained in:
parent
9981ad1811
commit
644b6c9be0
@ -1,6 +1,5 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <torch/torch.h>
|
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <argparse/argparse.hpp>
|
#include <argparse/argparse.hpp>
|
||||||
@ -19,20 +18,6 @@ using namespace std;
|
|||||||
|
|
||||||
const string PATH = "../../data/";
|
const string PATH = "../../data/";
|
||||||
|
|
||||||
inline constexpr auto hash_conv(const std::string_view sv)
|
|
||||||
{
|
|
||||||
unsigned long hash{ 5381 };
|
|
||||||
for (unsigned char c : sv) {
|
|
||||||
hash = ((hash << 5) + hash) ^ c;
|
|
||||||
}
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline constexpr auto operator"" _sh(const char* str, size_t len)
|
|
||||||
{
|
|
||||||
return hash_conv(std::string_view{ str, len });
|
|
||||||
}
|
|
||||||
|
|
||||||
pair<vector<mdlp::labels_t>, map<string, int>> discretize(vector<mdlp::samples_t>& X, mdlp::labels_t& y, vector<string> features)
|
pair<vector<mdlp::labels_t>, map<string, int>> discretize(vector<mdlp::samples_t>& X, mdlp::labels_t& y, vector<string> features)
|
||||||
{
|
{
|
||||||
vector<mdlp::labels_t>Xd;
|
vector<mdlp::labels_t>Xd;
|
||||||
@ -98,15 +83,13 @@ int main(int argc, char** argv)
|
|||||||
throw runtime_error("Model must be one of {AODE, KDB, SPODE, TAN}");
|
throw runtime_error("Model must be one of {AODE, KDB, SPODE, TAN}");
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
program.add_argument("--discretize").default_value(false).implicit_value(true);
|
bool class_last;
|
||||||
bool class_last, discretize_dataset;
|
|
||||||
string model_name, file_name, path, complete_file_name;
|
string model_name, file_name, path, complete_file_name;
|
||||||
try {
|
try {
|
||||||
program.parse_args(argc, argv);
|
program.parse_args(argc, argv);
|
||||||
file_name = program.get<string>("file");
|
file_name = program.get<string>("file");
|
||||||
path = program.get<string>("path");
|
path = program.get<string>("path");
|
||||||
model_name = program.get<string>("model");
|
model_name = program.get<string>("model");
|
||||||
discretize_dataset = program.get<bool>("discretize");
|
|
||||||
complete_file_name = path + file_name + ".arff";
|
complete_file_name = path + file_name + ".arff";
|
||||||
class_last = datasets[file_name];
|
class_last = datasets[file_name];
|
||||||
if (!file_exists(complete_file_name)) {
|
if (!file_exists(complete_file_name)) {
|
||||||
@ -134,21 +117,21 @@ int main(int argc, char** argv)
|
|||||||
features.push_back(feature.first);
|
features.push_back(feature.first);
|
||||||
}
|
}
|
||||||
// Discretize Dataset
|
// Discretize Dataset
|
||||||
vector<mdlp::labels_t> Xd;
|
auto [Xd, maxes] = discretize(X, y, features);
|
||||||
map<string, int> maxes;
|
|
||||||
tie(Xd, maxes) = discretize(X, y, features);
|
|
||||||
maxes[className] = *max_element(y.begin(), y.end()) + 1;
|
maxes[className] = *max_element(y.begin(), y.end()) + 1;
|
||||||
map<string, vector<int>> states;
|
map<string, vector<int>> states;
|
||||||
for (auto feature : features) {
|
for (auto feature : features) {
|
||||||
states[feature] = vector<int>(maxes[feature]);
|
states[feature] = vector<int>(maxes[feature]);
|
||||||
}
|
}
|
||||||
states[className] = vector<int>(
|
states[className] = vector<int>(maxes[className]);
|
||||||
maxes[className]);
|
auto classifiers = map<string, bayesnet::BaseClassifier*>({
|
||||||
double score;
|
{ "AODE", new bayesnet::AODE() }, { "KDB", new bayesnet::KDB(2) },
|
||||||
auto classifiers = map<string, bayesnet::BaseClassifier*>({ { "AODE", new bayesnet::AODE() }, { "KDB", new bayesnet::KDB(2) }, { "SPODE", new bayesnet::SPODE(2) }, { "TAN", new bayesnet::TAN() } });
|
{ "SPODE", new bayesnet::SPODE(2) }, { "TAN", new bayesnet::TAN() }
|
||||||
|
}
|
||||||
|
);
|
||||||
bayesnet::BaseClassifier* clf = classifiers[model_name];
|
bayesnet::BaseClassifier* clf = classifiers[model_name];
|
||||||
clf->fit(Xd, y, features, className, states);
|
clf->fit(Xd, y, features, className, states);
|
||||||
score = clf->score(Xd, y);
|
auto score = clf->score(Xd, y);
|
||||||
auto lines = clf->show();
|
auto lines = clf->show();
|
||||||
auto graph = clf->graph();
|
auto graph = clf->graph();
|
||||||
for (auto line : lines) {
|
for (auto line : lines) {
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
#include "BayesMetrics.h"
|
#include "BayesMetrics.h"
|
||||||
#include "Mst.h"
|
#include "Mst.h"
|
||||||
using namespace std;
|
|
||||||
namespace bayesnet {
|
namespace bayesnet {
|
||||||
Metrics::Metrics(torch::Tensor& samples, vector<string>& features, string& className, int classNumStates)
|
Metrics::Metrics(torch::Tensor& samples, vector<string>& features, string& className, int classNumStates)
|
||||||
: samples(samples)
|
: samples(samples)
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
#include "bayesnetUtils.h"
|
#include "bayesnetUtils.h"
|
||||||
|
|
||||||
namespace bayesnet {
|
namespace bayesnet {
|
||||||
using namespace std;
|
|
||||||
using namespace torch;
|
using namespace torch;
|
||||||
|
|
||||||
Classifier::Classifier(Network model) : model(model), m(0), n(0), metrics(Metrics()), fitted(false) {}
|
Classifier::Classifier(Network model) : model(model), m(0), n(0), metrics(Metrics()), fitted(false) {}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
#include "Ensemble.h"
|
#include "Ensemble.h"
|
||||||
|
|
||||||
namespace bayesnet {
|
namespace bayesnet {
|
||||||
using namespace std;
|
|
||||||
using namespace torch;
|
using namespace torch;
|
||||||
|
|
||||||
Ensemble::Ensemble() : m(0), n(0), n_models(0), metrics(Metrics()), fitted(false) {}
|
Ensemble::Ensemble() : m(0), n(0), n_models(0), metrics(Metrics()), fitted(false) {}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
#include "KDB.h"
|
#include "KDB.h"
|
||||||
|
|
||||||
namespace bayesnet {
|
namespace bayesnet {
|
||||||
using namespace std;
|
|
||||||
using namespace torch;
|
using namespace torch;
|
||||||
|
|
||||||
KDB::KDB(int k, float theta) : Classifier(Network()), k(k), theta(theta) {}
|
KDB::KDB(int k, float theta) : Classifier(Network()), k(k), theta(theta) {}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
#include "TAN.h"
|
#include "TAN.h"
|
||||||
|
|
||||||
namespace bayesnet {
|
namespace bayesnet {
|
||||||
using namespace std;
|
|
||||||
using namespace torch;
|
using namespace torch;
|
||||||
|
|
||||||
TAN::TAN() : Classifier(Network()) {}
|
TAN::TAN() : Classifier(Network()) {}
|
||||||
|
@ -12,22 +12,25 @@
|
|||||||
#include "AODE.h"
|
#include "AODE.h"
|
||||||
#include "TAN.h"
|
#include "TAN.h"
|
||||||
#include "platformUtils.h"
|
#include "platformUtils.h"
|
||||||
|
#include "Folding.h"
|
||||||
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
inline constexpr auto hash_conv(const std::string_view sv)
|
pair<float, float> cross_validation(Fold* fold, bayesnet::BaseClassifier* model, Tensor& X, Tensor& y, int k)
|
||||||
{
|
{
|
||||||
unsigned long hash{ 5381 };
|
float accuracy = 0.0;
|
||||||
for (unsigned char c : sv) {
|
for (int i = 0; i < k; i++) {
|
||||||
hash = ((hash << 5) + hash) ^ c;
|
auto [train, test] = fold->getFold(i);
|
||||||
|
auto X_train = X.indices{ train };
|
||||||
|
auto y_train = y.indices{ train };
|
||||||
|
auto X_test = X.indices{ test };
|
||||||
|
auto y_test = y.indices{ test };
|
||||||
|
model->fit(X_train, y_train);
|
||||||
|
auto acc = model->score(X_test, y_test);
|
||||||
|
accuracy += acc;
|
||||||
}
|
}
|
||||||
return hash;
|
return { accuracy / k, 0 };
|
||||||
}
|
|
||||||
|
|
||||||
inline constexpr auto operator"" _sh(const char* str, size_t len)
|
|
||||||
{
|
|
||||||
return hash_conv(std::string_view{ str, len });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
@ -94,70 +97,18 @@ int main(int argc, char** argv)
|
|||||||
/*
|
/*
|
||||||
* Begin Processing
|
* Begin Processing
|
||||||
*/
|
*/
|
||||||
auto handler = ArffFiles();
|
auto [X, y, features] = loadDataset(file_name, discretize_dataset);
|
||||||
handler.load(complete_file_name, class_last);
|
if (discretize_dataset) {
|
||||||
// Get Dataset X, y
|
auto [discretized, maxes] = discretize(X, y, features);
|
||||||
vector<mdlp::samples_t>& X = handler.getX();
|
|
||||||
mdlp::labels_t& y = handler.getY();
|
|
||||||
// Get className & Features
|
|
||||||
auto className = handler.getClassName();
|
|
||||||
vector<string> features;
|
|
||||||
for (auto feature : handler.getAttributes()) {
|
|
||||||
features.push_back(feature.first);
|
|
||||||
}
|
}
|
||||||
// Discretize Dataset
|
auto fold = StratifiedKFold(5, y, -1);
|
||||||
vector<mdlp::labels_t> Xd;
|
auto classifiers = map<string, bayesnet::BaseClassifier*>({
|
||||||
map<string, int> maxes;
|
{ "AODE", new bayesnet::AODE() }, { "KDB", new bayesnet::KDB(2) },
|
||||||
tie(Xd, maxes) = discretize(X, y, features);
|
{ "SPODE", new bayesnet::SPODE(2) }, { "TAN", new bayesnet::TAN() }
|
||||||
maxes[className] = *max_element(y.begin(), y.end()) + 1;
|
}
|
||||||
map<string, vector<int>> states;
|
);
|
||||||
for (auto feature : features) {
|
bayesnet::BaseClassifier* model = classifiers[model_name];
|
||||||
states[feature] = vector<int>(maxes[feature]);
|
auto results = cross_validation(model, X, y, fold, 5);
|
||||||
}
|
cout << "Accuracy: " << results.first << endl;
|
||||||
states[className] = vector<int>(
|
|
||||||
maxes[className]);
|
|
||||||
double score;
|
|
||||||
vector<string> lines;
|
|
||||||
vector<string> graph;
|
|
||||||
auto kdb = bayesnet::KDB(2);
|
|
||||||
auto aode = bayesnet::AODE();
|
|
||||||
auto spode = bayesnet::SPODE(2);
|
|
||||||
auto tan = bayesnet::TAN();
|
|
||||||
switch (hash_conv(model_name)) {
|
|
||||||
case "AODE"_sh:
|
|
||||||
aode.fit(Xd, y, features, className, states);
|
|
||||||
lines = aode.show();
|
|
||||||
score = aode.score(Xd, y);
|
|
||||||
graph = aode.graph();
|
|
||||||
break;
|
|
||||||
case "KDB"_sh:
|
|
||||||
kdb.fit(Xd, y, features, className, states);
|
|
||||||
lines = kdb.show();
|
|
||||||
score = kdb.score(Xd, y);
|
|
||||||
graph = kdb.graph();
|
|
||||||
break;
|
|
||||||
case "SPODE"_sh:
|
|
||||||
spode.fit(Xd, y, features, className, states);
|
|
||||||
lines = spode.show();
|
|
||||||
score = spode.score(Xd, y);
|
|
||||||
graph = spode.graph();
|
|
||||||
break;
|
|
||||||
case "TAN"_sh:
|
|
||||||
tan.fit(Xd, y, features, className, states);
|
|
||||||
lines = tan.show();
|
|
||||||
score = tan.score(Xd, y);
|
|
||||||
graph = tan.graph();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
for (auto line : lines) {
|
|
||||||
cout << line << endl;
|
|
||||||
}
|
|
||||||
cout << "Score: " << score << endl;
|
|
||||||
auto dot_file = model_name + "_" + file_name;
|
|
||||||
ofstream file(dot_file + ".dot");
|
|
||||||
file << graph;
|
|
||||||
file.close();
|
|
||||||
cout << "Graph saved in " << model_name << "_" << file_name << ".dot" << endl;
|
|
||||||
cout << "dot -Tpng -o " + dot_file + ".png " + dot_file + ".dot " << endl;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
@ -2,10 +2,7 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <random>
|
#include <random>
|
||||||
|
KFold::KFold(int k, int n, int seed) : Fold(k, n, seed)
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
KFold::KFold(int k, int n, int seed) : k(k), n(n), seed(seed)
|
|
||||||
{
|
{
|
||||||
indices = vector<int>(n);
|
indices = vector<int>(n);
|
||||||
iota(begin(indices), end(indices), 0); // fill with 0, 1, ..., n - 1
|
iota(begin(indices), end(indices), 0); // fill with 0, 1, ..., n - 1
|
||||||
@ -31,8 +28,8 @@ pair<vector<int>, vector<int>> KFold::getFold(int nFold)
|
|||||||
}
|
}
|
||||||
return { train, test };
|
return { train, test };
|
||||||
}
|
}
|
||||||
StratifiedKFold::StratifiedKFold(int k, const vector<int>& y, int seed) :
|
StratifiedKFold::StratifiedKFold(int k, const vector<int>& y, int seed)
|
||||||
k(k), seed(seed)
|
: Fold(k, y.size(), seed)
|
||||||
{
|
{
|
||||||
n = y.size();
|
n = y.size();
|
||||||
stratified_indices = vector<vector<int>>(k);
|
stratified_indices = vector<vector<int>>(k);
|
||||||
|
@ -2,21 +2,25 @@
|
|||||||
#define FOLDING_H
|
#define FOLDING_H
|
||||||
#include <vector>
|
#include <vector>
|
||||||
using namespace std;
|
using namespace std;
|
||||||
class KFold {
|
|
||||||
private:
|
class Fold {
|
||||||
|
protected:
|
||||||
int k;
|
int k;
|
||||||
int n;
|
int n;
|
||||||
int seed;
|
int seed;
|
||||||
|
public:
|
||||||
|
Fold(int k, int n, int seed = -1) : k(k), n(n), seed(seed) {}
|
||||||
|
virtual pair<vector<int>, vector<int>> getFold(int nFold) = 0;
|
||||||
|
virtual ~Fold() = default;
|
||||||
|
};
|
||||||
|
class KFold : public Fold {
|
||||||
|
private:
|
||||||
vector<int> indices;
|
vector<int> indices;
|
||||||
public:
|
public:
|
||||||
KFold(int k, int n, int seed = -1);
|
KFold(int k, int n, int seed = -1);
|
||||||
pair<vector<int>, vector<int>> getFold(int nFold);
|
pair<vector<int>, vector<int>> getFold(int nFold);
|
||||||
};
|
};
|
||||||
class StratifiedKFold {
|
class StratifiedKFold : public Fold {
|
||||||
private:
|
|
||||||
int k;
|
|
||||||
int n;
|
|
||||||
int seed;
|
|
||||||
vector<vector<int>> stratified_indices;
|
vector<vector<int>> stratified_indices;
|
||||||
public:
|
public:
|
||||||
StratifiedKFold(int k, const vector<int>& y, int seed = -1);
|
StratifiedKFold(int k, const vector<int>& y, int seed = -1);
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
#include "platformUtils.h"
|
#include "platformUtils.h"
|
||||||
|
|
||||||
|
using namespace torch;
|
||||||
|
|
||||||
pair<vector<mdlp::labels_t>, map<string, int>> discretize(vector<mdlp::samples_t>& X, mdlp::labels_t& y, vector<string> features)
|
pair<vector<mdlp::labels_t>, map<string, int>> discretize(vector<mdlp::samples_t>& X, mdlp::labels_t& y, vector<string> features)
|
||||||
{
|
{
|
||||||
vector<mdlp::labels_t> Xd;
|
vector<mdlp::labels_t> Xd;
|
||||||
@ -14,6 +16,18 @@ pair<vector<mdlp::labels_t>, map<string, int>> discretize(vector<mdlp::samples_t
|
|||||||
return { Xd, maxes };
|
return { Xd, maxes };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vector<mdlp::labels_t> discretizeDataset(vector<mdlp::samples_t>& X, mdlp::labels_t& y)
|
||||||
|
{
|
||||||
|
vector<mdlp::labels_t> Xd;
|
||||||
|
auto fimdlp = mdlp::CPPFImdlp();
|
||||||
|
for (int i = 0; i < X.size(); i++) {
|
||||||
|
fimdlp.fit(X[i], y);
|
||||||
|
mdlp::labels_t& xd = fimdlp.transform(X[i]);
|
||||||
|
Xd.push_back(xd);
|
||||||
|
}
|
||||||
|
return Xd;
|
||||||
|
}
|
||||||
|
|
||||||
bool file_exists(const std::string& name)
|
bool file_exists(const std::string& name)
|
||||||
{
|
{
|
||||||
if (FILE* file = fopen(name.c_str(), "r")) {
|
if (FILE* file = fopen(name.c_str(), "r")) {
|
||||||
@ -24,6 +38,48 @@ bool file_exists(const std::string& name)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tuple < Tensor, Tensor, vector<string>> loadDataset(string name, bool discretize)
|
||||||
|
{
|
||||||
|
auto handler = ArffFiles();
|
||||||
|
handler.load(PATH + static_cast<string>(name) + ".arff");
|
||||||
|
// Get Dataset X, y
|
||||||
|
vector<mdlp::samples_t>& X = handler.getX();
|
||||||
|
mdlp::labels_t& y = handler.getY();
|
||||||
|
// Get className & Features
|
||||||
|
auto className = handler.getClassName();
|
||||||
|
vector<string> features;
|
||||||
|
for (auto feature : handler.getAttributes()) {
|
||||||
|
features.push_back(feature.first);
|
||||||
|
}
|
||||||
|
Tensor Xd;
|
||||||
|
if (discretize) {
|
||||||
|
auto Xr = discretizeDataset(X, y);
|
||||||
|
Xd = torch::zeros({ static_cast<int64_t>(Xr[0].size()), static_cast<int64_t>(Xr.size()) }, torch::kInt64);
|
||||||
|
for (int i = 0; i < features.size(); ++i) {
|
||||||
|
Xd.index_put_({ "...", i }, torch::tensor(Xr[i], torch::kInt64));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Xd = torch::zeros({ static_cast<int64_t>(X[0].size()), static_cast<int64_t>(X.size()) }, torch::kFloat64);
|
||||||
|
for (int i = 0; i < features.size(); ++i) {
|
||||||
|
Xd.index_put_({ "...", i }, torch::tensor(X[i], torch::kFloat64));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return { Xd, torch::tensor(y, torch::kInt64), features };
|
||||||
|
}
|
||||||
|
|
||||||
|
pair <map<string, int>, map<string, vector<int>>> discretize_info(Tensor& X, Tensor& y, vector<string> features, string className)
|
||||||
|
{
|
||||||
|
map<string, int> maxes;
|
||||||
|
map<string, vector<int>> states;
|
||||||
|
for (int i = 0; i < X.size(1); i++) {
|
||||||
|
maxes[features[i]] = X.select(1, i).max().item<int>() + 1;
|
||||||
|
states[features[i]] = vector<int>(maxes[features[i]]);
|
||||||
|
}
|
||||||
|
maxes[className] = y.max().item<int>() + 1;
|
||||||
|
states[className] = vector<int>(maxes[className]);
|
||||||
|
return { maxes, states };
|
||||||
|
}
|
||||||
|
|
||||||
tuple<vector<vector<int>>, vector<int>, vector<string>, string, map<string, vector<int>>> loadFile(string name)
|
tuple<vector<vector<int>>, vector<int>, vector<string>, string, map<string, vector<int>>> loadFile(string name)
|
||||||
{
|
{
|
||||||
auto handler = ArffFiles();
|
auto handler = ArffFiles();
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#ifndef PLATFORM_UTILS_H
|
#ifndef PLATFORM_UTILS_H
|
||||||
#define PLATFORM_UTILS_H
|
#define PLATFORM_UTILS_H
|
||||||
|
#include <torch/torch.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <map>
|
#include <map>
|
||||||
@ -12,4 +13,6 @@ const string PATH = "../../data/";
|
|||||||
bool file_exists(const std::string& name);
|
bool file_exists(const std::string& name);
|
||||||
pair<vector<mdlp::labels_t>, map<string, int>> discretize(vector<mdlp::samples_t>& X, mdlp::labels_t& y, vector<string> features);
|
pair<vector<mdlp::labels_t>, map<string, int>> discretize(vector<mdlp::samples_t>& X, mdlp::labels_t& y, vector<string> features);
|
||||||
tuple<vector<vector<int>>, vector<int>, vector<string>, string, map<string, vector<int>>> loadFile(string name);
|
tuple<vector<vector<int>>, vector<int>, vector<string>, string, map<string, vector<int>>> loadFile(string name);
|
||||||
|
tuple<torch::Tensor, torch::Tensor, vector<string>> loadDataset(string name, bool discretize);
|
||||||
|
pair <map<string, int>, map<string, vector<int>>> discretize_info(torch::Tensor& X, torch::Tensor& y);
|
||||||
#endif //PLATFORM_UTILS_H
|
#endif //PLATFORM_UTILS_H
|
||||||
|
Loading…
Reference in New Issue
Block a user