Remove using namespace from Library
This commit is contained in:
@@ -13,26 +13,25 @@
|
||||
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
// function ftime_to_string, Code taken from
|
||||
// function ftime_to_std::string, Code taken from
|
||||
// https://stackoverflow.com/a/58237530/1389271
|
||||
template <typename TP>
|
||||
std::string ftime_to_string(TP tp)
|
||||
{
|
||||
using namespace std::chrono;
|
||||
auto sctp = time_point_cast<system_clock::duration>(tp - TP::clock::now()
|
||||
+ system_clock::now());
|
||||
auto tt = system_clock::to_time_t(sctp);
|
||||
auto sctp = std::chrono::time_point_cast<std::chrono::system_clock::duration>(tp - TP::clock::now()
|
||||
+ std::chrono::system_clock::now());
|
||||
auto tt = std::chrono::system_clock::to_time_t(sctp);
|
||||
std::tm* gmt = std::gmtime(&tt);
|
||||
std::stringstream buffer;
|
||||
buffer << std::put_time(gmt, "%Y-%m-%d %H:%M");
|
||||
return buffer.str();
|
||||
}
|
||||
namespace platform {
|
||||
string BestResults::build()
|
||||
std::string BestResults::build()
|
||||
{
|
||||
auto files = loadResultFiles();
|
||||
if (files.size() == 0) {
|
||||
cerr << Colors::MAGENTA() << "No result files were found!" << Colors::RESET() << endl;
|
||||
std::cerr << Colors::MAGENTA() << "No result files were found!" << Colors::RESET() << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
json bests;
|
||||
@@ -42,7 +41,7 @@ namespace platform {
|
||||
for (auto const& item : data.at("results")) {
|
||||
bool update = false;
|
||||
// Check if results file contains only one dataset
|
||||
auto datasetName = item.at("dataset").get<string>();
|
||||
auto datasetName = item.at("dataset").get<std::string>();
|
||||
if (bests.contains(datasetName)) {
|
||||
if (item.at("score").get<double>() > bests[datasetName].at(0).get<double>()) {
|
||||
update = true;
|
||||
@@ -55,39 +54,39 @@ namespace platform {
|
||||
}
|
||||
}
|
||||
}
|
||||
string bestFileName = path + bestResultFile();
|
||||
std::string bestFileName = path + bestResultFile();
|
||||
if (FILE* fileTest = fopen(bestFileName.c_str(), "r")) {
|
||||
fclose(fileTest);
|
||||
cout << Colors::MAGENTA() << "File " << bestFileName << " already exists and it shall be overwritten." << Colors::RESET() << endl;
|
||||
std::cout << Colors::MAGENTA() << "File " << bestFileName << " already exists and it shall be overwritten." << Colors::RESET() << std::endl;
|
||||
}
|
||||
ofstream file(bestFileName);
|
||||
std::ofstream file(bestFileName);
|
||||
file << bests;
|
||||
file.close();
|
||||
return bestFileName;
|
||||
}
|
||||
string BestResults::bestResultFile()
|
||||
std::string BestResults::bestResultFile()
|
||||
{
|
||||
return "best_results_" + score + "_" + model + ".json";
|
||||
}
|
||||
pair<string, string> getModelScore(string name)
|
||||
std::pair<std::string, std::string> getModelScore(std::string name)
|
||||
{
|
||||
// results_accuracy_BoostAODE_MacBookpro16_2023-09-06_12:27:00_1.json
|
||||
int i = 0;
|
||||
auto pos = name.find("_");
|
||||
auto pos2 = name.find("_", pos + 1);
|
||||
string score = name.substr(pos + 1, pos2 - pos - 1);
|
||||
std::string score = name.substr(pos + 1, pos2 - pos - 1);
|
||||
pos = name.find("_", pos2 + 1);
|
||||
string model = name.substr(pos2 + 1, pos - pos2 - 1);
|
||||
std::string model = name.substr(pos2 + 1, pos - pos2 - 1);
|
||||
return { model, score };
|
||||
}
|
||||
vector<string> BestResults::loadResultFiles()
|
||||
std::vector<std::string> BestResults::loadResultFiles()
|
||||
{
|
||||
vector<string> files;
|
||||
std::vector<std::string> files;
|
||||
using std::filesystem::directory_iterator;
|
||||
string fileModel, fileScore;
|
||||
std::string fileModel, fileScore;
|
||||
for (const auto& file : directory_iterator(path)) {
|
||||
auto fileName = file.path().filename().string();
|
||||
if (fileName.find(".json") != string::npos && fileName.find("results_") == 0) {
|
||||
if (fileName.find(".json") != std::string::npos && fileName.find("results_") == 0) {
|
||||
tie(fileModel, fileScore) = getModelScore(fileName);
|
||||
if (score == fileScore && (model == fileModel || model == "any")) {
|
||||
files.push_back(fileName);
|
||||
@@ -96,37 +95,37 @@ namespace platform {
|
||||
}
|
||||
return files;
|
||||
}
|
||||
json BestResults::loadFile(const string& fileName)
|
||||
json BestResults::loadFile(const std::string& fileName)
|
||||
{
|
||||
ifstream resultData(fileName);
|
||||
std::ifstream resultData(fileName);
|
||||
if (resultData.is_open()) {
|
||||
json data = json::parse(resultData);
|
||||
return data;
|
||||
}
|
||||
throw invalid_argument("Unable to open result file. [" + fileName + "]");
|
||||
throw std::invalid_argument("Unable to open result file. [" + fileName + "]");
|
||||
}
|
||||
vector<string> BestResults::getModels()
|
||||
std::vector<std::string> BestResults::getModels()
|
||||
{
|
||||
set<string> models;
|
||||
vector<string> result;
|
||||
std::set<std::string> models;
|
||||
std::vector<std::string> result;
|
||||
auto files = loadResultFiles();
|
||||
if (files.size() == 0) {
|
||||
cerr << Colors::MAGENTA() << "No result files were found!" << Colors::RESET() << endl;
|
||||
std::cerr << Colors::MAGENTA() << "No result files were found!" << Colors::RESET() << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
string fileModel, fileScore;
|
||||
std::string fileModel, fileScore;
|
||||
for (const auto& file : files) {
|
||||
// extract the model from the file name
|
||||
tie(fileModel, fileScore) = getModelScore(file);
|
||||
// add the model to the vector of models
|
||||
// add the model to the std::vector of models
|
||||
models.insert(fileModel);
|
||||
}
|
||||
result = vector<string>(models.begin(), models.end());
|
||||
result = std::vector<std::string>(models.begin(), models.end());
|
||||
return result;
|
||||
}
|
||||
vector<string> BestResults::getDatasets(json table)
|
||||
std::vector<std::string> BestResults::getDatasets(json table)
|
||||
{
|
||||
vector<string> datasets;
|
||||
std::vector<std::string> datasets;
|
||||
for (const auto& dataset : table.items()) {
|
||||
datasets.push_back(dataset.key());
|
||||
}
|
||||
@@ -136,7 +135,7 @@ namespace platform {
|
||||
{
|
||||
auto models = getModels();
|
||||
for (const auto& model : models) {
|
||||
cout << "Building best results for model: " << model << endl;
|
||||
std::cout << "Building best results for model: " << model << std::endl;
|
||||
this->model = model;
|
||||
build();
|
||||
}
|
||||
@@ -144,62 +143,62 @@ namespace platform {
|
||||
}
|
||||
void BestResults::listFile()
|
||||
{
|
||||
string bestFileName = path + bestResultFile();
|
||||
std::string bestFileName = path + bestResultFile();
|
||||
if (FILE* fileTest = fopen(bestFileName.c_str(), "r")) {
|
||||
fclose(fileTest);
|
||||
} else {
|
||||
cerr << Colors::MAGENTA() << "File " << bestFileName << " doesn't exist." << Colors::RESET() << endl;
|
||||
std::cerr << Colors::MAGENTA() << "File " << bestFileName << " doesn't exist." << Colors::RESET() << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
auto temp = ConfigLocale();
|
||||
auto date = ftime_to_string(filesystem::last_write_time(bestFileName));
|
||||
auto date = ftime_to_string(std::filesystem::last_write_time(bestFileName));
|
||||
auto data = loadFile(bestFileName);
|
||||
auto datasets = getDatasets(data);
|
||||
int maxDatasetName = (*max_element(datasets.begin(), datasets.end(), [](const string& a, const string& b) { return a.size() < b.size(); })).size();
|
||||
int maxDatasetName = (*max_element(datasets.begin(), datasets.end(), [](const std::string& a, const std::string& b) { return a.size() < b.size(); })).size();
|
||||
int maxFileName = 0;
|
||||
int maxHyper = 15;
|
||||
for (auto const& item : data.items()) {
|
||||
maxHyper = max(maxHyper, (int)item.value().at(1).dump().size());
|
||||
maxFileName = max(maxFileName, (int)item.value().at(2).get<string>().size());
|
||||
maxHyper = std::max(maxHyper, (int)item.value().at(1).dump().size());
|
||||
maxFileName = std::max(maxFileName, (int)item.value().at(2).get<std::string>().size());
|
||||
}
|
||||
stringstream oss;
|
||||
oss << Colors::GREEN() << "Best results for " << model << " as of " << date << endl;
|
||||
cout << oss.str();
|
||||
cout << string(oss.str().size() - 8, '-') << endl;
|
||||
cout << Colors::GREEN() << " # " << setw(maxDatasetName + 1) << left << "Dataset" << "Score " << setw(maxFileName) << "File" << " Hyperparameters" << endl;
|
||||
cout << "=== " << string(maxDatasetName, '=') << " =========== " << string(maxFileName, '=') << " " << string(maxHyper, '=') << endl;
|
||||
std::stringstream oss;
|
||||
oss << Colors::GREEN() << "Best results for " << model << " as of " << date << std::endl;
|
||||
std::cout << oss.str();
|
||||
std::cout << std::string(oss.str().size() - 8, '-') << std::endl;
|
||||
std::cout << Colors::GREEN() << " # " << std::setw(maxDatasetName + 1) << std::left << "Dataset" << "Score " << std::setw(maxFileName) << "File" << " Hyperparameters" << std::endl;
|
||||
std::cout << "=== " << std::string(maxDatasetName, '=') << " =========== " << std::string(maxFileName, '=') << " " << std::string(maxHyper, '=') << std::endl;
|
||||
auto i = 0;
|
||||
bool odd = true;
|
||||
double total = 0;
|
||||
for (auto const& item : data.items()) {
|
||||
auto color = odd ? Colors::BLUE() : Colors::CYAN();
|
||||
double value = item.value().at(0).get<double>();
|
||||
cout << color << setw(3) << fixed << right << i++ << " ";
|
||||
cout << setw(maxDatasetName) << left << item.key() << " ";
|
||||
cout << setw(11) << setprecision(9) << fixed << value << " ";
|
||||
cout << setw(maxFileName) << item.value().at(2).get<string>() << " ";
|
||||
cout << item.value().at(1) << " ";
|
||||
cout << endl;
|
||||
std::cout << color << std::setw(3) << std::fixed << std::right << i++ << " ";
|
||||
std::cout << std::setw(maxDatasetName) << std::left << item.key() << " ";
|
||||
std::cout << std::setw(11) << std::setprecision(9) << std::fixed << value << " ";
|
||||
std::cout << std::setw(maxFileName) << item.value().at(2).get<std::string>() << " ";
|
||||
std::cout << item.value().at(1) << " ";
|
||||
std::cout << std::endl;
|
||||
total += value;
|
||||
odd = !odd;
|
||||
}
|
||||
cout << Colors::GREEN() << "=== " << string(maxDatasetName, '=') << " ===========" << endl;
|
||||
cout << setw(5 + maxDatasetName) << "Total.................. " << setw(11) << setprecision(8) << fixed << total << endl;
|
||||
std::cout << Colors::GREEN() << "=== " << std::string(maxDatasetName, '=') << " ===========" << std::endl;
|
||||
std::cout << std::setw(5 + maxDatasetName) << "Total.................. " << std::setw(11) << std::setprecision(8) << std::fixed << total << std::endl;
|
||||
}
|
||||
json BestResults::buildTableResults(vector<string> models)
|
||||
json BestResults::buildTableResults(std::vector<std::string> models)
|
||||
{
|
||||
json table;
|
||||
auto maxDate = filesystem::file_time_type::max();
|
||||
auto maxDate = std::filesystem::file_time_type::max();
|
||||
for (const auto& model : models) {
|
||||
this->model = model;
|
||||
string bestFileName = path + bestResultFile();
|
||||
std::string bestFileName = path + bestResultFile();
|
||||
if (FILE* fileTest = fopen(bestFileName.c_str(), "r")) {
|
||||
fclose(fileTest);
|
||||
} else {
|
||||
cerr << Colors::MAGENTA() << "File " << bestFileName << " doesn't exist." << Colors::RESET() << endl;
|
||||
std::cerr << Colors::MAGENTA() << "File " << bestFileName << " doesn't exist." << Colors::RESET() << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
auto dateWrite = filesystem::last_write_time(bestFileName);
|
||||
auto dateWrite = std::filesystem::last_write_time(bestFileName);
|
||||
if (dateWrite < maxDate) {
|
||||
maxDate = dateWrite;
|
||||
}
|
||||
@@ -209,25 +208,25 @@ namespace platform {
|
||||
table["dateTable"] = ftime_to_string(maxDate);
|
||||
return table;
|
||||
}
|
||||
void BestResults::printTableResults(vector<string> models, json table)
|
||||
void BestResults::printTableResults(std::vector<std::string> models, json table)
|
||||
{
|
||||
stringstream oss;
|
||||
oss << Colors::GREEN() << "Best results for " << score << " as of " << table.at("dateTable").get<string>() << endl;
|
||||
cout << oss.str();
|
||||
cout << string(oss.str().size() - 8, '-') << endl;
|
||||
cout << Colors::GREEN() << " # " << setw(maxDatasetName + 1) << left << string("Dataset");
|
||||
std::stringstream oss;
|
||||
oss << Colors::GREEN() << "Best results for " << score << " as of " << table.at("dateTable").get<std::string>() << std::endl;
|
||||
std::cout << oss.str();
|
||||
std::cout << std::string(oss.str().size() - 8, '-') << std::endl;
|
||||
std::cout << Colors::GREEN() << " # " << std::setw(maxDatasetName + 1) << std::left << std::string("Dataset");
|
||||
for (const auto& model : models) {
|
||||
cout << setw(maxModelName) << left << model << " ";
|
||||
std::cout << std::setw(maxModelName) << std::left << model << " ";
|
||||
}
|
||||
cout << endl;
|
||||
cout << "=== " << string(maxDatasetName, '=') << " ";
|
||||
std::cout << std::endl;
|
||||
std::cout << "=== " << std::string(maxDatasetName, '=') << " ";
|
||||
for (const auto& model : models) {
|
||||
cout << string(maxModelName, '=') << " ";
|
||||
std::cout << std::string(maxModelName, '=') << " ";
|
||||
}
|
||||
cout << endl;
|
||||
std::cout << std::endl;
|
||||
auto i = 0;
|
||||
bool odd = true;
|
||||
map<string, double> totals;
|
||||
std::map<std::string, double> totals;
|
||||
int nDatasets = table.begin().value().size();
|
||||
for (const auto& model : models) {
|
||||
totals[model] = 0.0;
|
||||
@@ -235,8 +234,8 @@ namespace platform {
|
||||
auto datasets = getDatasets(table.begin().value());
|
||||
for (auto const& dataset : datasets) {
|
||||
auto color = odd ? Colors::BLUE() : Colors::CYAN();
|
||||
cout << color << setw(3) << fixed << right << i++ << " ";
|
||||
cout << setw(maxDatasetName) << left << dataset << " ";
|
||||
std::cout << color << std::setw(3) << std::fixed << std::right << i++ << " ";
|
||||
std::cout << std::setw(maxDatasetName) << std::left << dataset << " ";
|
||||
double maxValue = 0;
|
||||
// Find out the max value for this dataset
|
||||
for (const auto& model : models) {
|
||||
@@ -247,23 +246,23 @@ namespace platform {
|
||||
}
|
||||
// Print the row with red colors on max values
|
||||
for (const auto& model : models) {
|
||||
string efectiveColor = color;
|
||||
std::string efectiveColor = color;
|
||||
double value = table[model].at(dataset).at(0).get<double>();
|
||||
if (value == maxValue) {
|
||||
efectiveColor = Colors::RED();
|
||||
}
|
||||
totals[model] += value;
|
||||
cout << efectiveColor << setw(maxModelName) << setprecision(maxModelName - 2) << fixed << value << " ";
|
||||
std::cout << efectiveColor << std::setw(maxModelName) << std::setprecision(maxModelName - 2) << std::fixed << value << " ";
|
||||
}
|
||||
cout << endl;
|
||||
std::cout << std::endl;
|
||||
odd = !odd;
|
||||
}
|
||||
cout << Colors::GREEN() << "=== " << string(maxDatasetName, '=') << " ";
|
||||
std::cout << Colors::GREEN() << "=== " << std::string(maxDatasetName, '=') << " ";
|
||||
for (const auto& model : models) {
|
||||
cout << string(maxModelName, '=') << " ";
|
||||
std::cout << std::string(maxModelName, '=') << " ";
|
||||
}
|
||||
cout << endl;
|
||||
cout << Colors::GREEN() << setw(5 + maxDatasetName) << " Totals...................";
|
||||
std::cout << std::endl;
|
||||
std::cout << Colors::GREEN() << std::setw(5 + maxDatasetName) << " Totals...................";
|
||||
double max = 0.0;
|
||||
for (const auto& total : totals) {
|
||||
if (total.second > max) {
|
||||
@@ -271,13 +270,13 @@ namespace platform {
|
||||
}
|
||||
}
|
||||
for (const auto& model : models) {
|
||||
string efectiveColor = Colors::GREEN();
|
||||
std::string efectiveColor = Colors::GREEN();
|
||||
if (totals[model] == max) {
|
||||
efectiveColor = Colors::RED();
|
||||
}
|
||||
cout << efectiveColor << right << setw(maxModelName) << setprecision(maxModelName - 4) << fixed << totals[model] << " ";
|
||||
std::cout << efectiveColor << std::right << std::setw(maxModelName) << std::setprecision(maxModelName - 4) << std::fixed << totals[model] << " ";
|
||||
}
|
||||
cout << endl;
|
||||
std::cout << std::endl;
|
||||
}
|
||||
void BestResults::reportSingle(bool excel)
|
||||
{
|
||||
@@ -286,7 +285,7 @@ namespace platform {
|
||||
auto models = getModels();
|
||||
// Build the table of results
|
||||
json table = buildTableResults(models);
|
||||
vector<string> datasets = getDatasets(table.begin().value());
|
||||
std::vector<std::string> datasets = getDatasets(table.begin().value());
|
||||
BestResultsExcel excel(score, datasets);
|
||||
excel.reportSingle(model, path + bestResultFile());
|
||||
messageExcelFile(excel.getFileName());
|
||||
@@ -297,15 +296,15 @@ namespace platform {
|
||||
auto models = getModels();
|
||||
// Build the table of results
|
||||
json table = buildTableResults(models);
|
||||
vector<string> datasets = getDatasets(table.begin().value());
|
||||
maxModelName = (*max_element(models.begin(), models.end(), [](const string& a, const string& b) { return a.size() < b.size(); })).size();
|
||||
maxModelName = max(12, maxModelName);
|
||||
maxDatasetName = (*max_element(datasets.begin(), datasets.end(), [](const string& a, const string& b) { return a.size() < b.size(); })).size();
|
||||
maxDatasetName = max(25, maxDatasetName);
|
||||
std::vector<std::string> datasets = getDatasets(table.begin().value());
|
||||
maxModelName = (*max_element(models.begin(), models.end(), [](const std::string& a, const std::string& b) { return a.size() < b.size(); })).size();
|
||||
maxModelName = std::max(12, maxModelName);
|
||||
maxDatasetName = (*max_element(datasets.begin(), datasets.end(), [](const std::string& a, const std::string& b) { return a.size() < b.size(); })).size();
|
||||
maxDatasetName = std::max(25, maxDatasetName);
|
||||
// Print the table of results
|
||||
printTableResults(models, table);
|
||||
// Compute the Friedman test
|
||||
map<string, map<string, float>> ranksModels;
|
||||
std::map<std::string, std::map<std::string, float>> ranksModels;
|
||||
if (friedman) {
|
||||
Statistics stats(models, datasets, table, significance);
|
||||
auto result = stats.friedmanTest();
|
||||
@@ -319,7 +318,7 @@ namespace platform {
|
||||
int idx = -1;
|
||||
double min = 2000;
|
||||
// Find out the control model
|
||||
auto totals = vector<double>(models.size(), 0.0);
|
||||
auto totals = std::vector<double>(models.size(), 0.0);
|
||||
for (const auto& dataset : datasets) {
|
||||
for (int i = 0; i < models.size(); ++i) {
|
||||
totals[i] += ranksModels[dataset][models[i]];
|
||||
@@ -337,8 +336,8 @@ namespace platform {
|
||||
messageExcelFile(excel.getFileName());
|
||||
}
|
||||
}
|
||||
void BestResults::messageExcelFile(const string& fileName)
|
||||
void BestResults::messageExcelFile(const std::string& fileName)
|
||||
{
|
||||
cout << Colors::YELLOW() << "** Excel file generated: " << fileName << Colors::RESET() << endl;
|
||||
std::cout << Colors::YELLOW() << "** Excel file generated: " << fileName << Colors::RESET() << std::endl;
|
||||
}
|
||||
}
|
@@ -2,32 +2,31 @@
|
||||
#define BESTRESULTS_H
|
||||
#include <string>
|
||||
#include <nlohmann/json.hpp>
|
||||
using namespace std;
|
||||
using json = nlohmann::json;
|
||||
namespace platform {
|
||||
class BestResults {
|
||||
public:
|
||||
explicit BestResults(const string& path, const string& score, const string& model, bool friedman, double significance = 0.05)
|
||||
explicit BestResults(const std::string& path, const std::string& score, const std::string& model, bool friedman, double significance = 0.05)
|
||||
: path(path), score(score), model(model), friedman(friedman), significance(significance)
|
||||
{
|
||||
}
|
||||
string build();
|
||||
std::string build();
|
||||
void reportSingle(bool excel);
|
||||
void reportAll(bool excel);
|
||||
void buildAll();
|
||||
private:
|
||||
vector<string> getModels();
|
||||
vector<string> getDatasets(json table);
|
||||
vector<string> loadResultFiles();
|
||||
void messageExcelFile(const string& fileName);
|
||||
json buildTableResults(vector<string> models);
|
||||
void printTableResults(vector<string> models, json table);
|
||||
string bestResultFile();
|
||||
json loadFile(const string& fileName);
|
||||
std::vector<std::string> getModels();
|
||||
std::vector<std::string> getDatasets(json table);
|
||||
std::vector<std::string> loadResultFiles();
|
||||
void messageExcelFile(const std::string& fileName);
|
||||
json buildTableResults(std::vector<std::string> models);
|
||||
void printTableResults(std::vector<std::string> models, json table);
|
||||
std::string bestResultFile();
|
||||
json loadFile(const std::string& fileName);
|
||||
void listFile();
|
||||
string path;
|
||||
string score;
|
||||
string model;
|
||||
std::string path;
|
||||
std::string score;
|
||||
std::string model;
|
||||
bool friedman;
|
||||
double significance;
|
||||
int maxModelName = 0;
|
||||
|
@@ -7,20 +7,20 @@
|
||||
#include "ReportExcel.h"
|
||||
|
||||
namespace platform {
|
||||
json loadResultData(const string& fileName)
|
||||
json loadResultData(const std::string& fileName)
|
||||
{
|
||||
json data;
|
||||
ifstream resultData(fileName);
|
||||
std::ifstream resultData(fileName);
|
||||
if (resultData.is_open()) {
|
||||
data = json::parse(resultData);
|
||||
} else {
|
||||
throw invalid_argument("Unable to open result file. [" + fileName + "]");
|
||||
throw std::invalid_argument("Unable to open result file. [" + fileName + "]");
|
||||
}
|
||||
return data;
|
||||
}
|
||||
string getColumnName(int colNum)
|
||||
std::string getColumnName(int colNum)
|
||||
{
|
||||
string columnName = "";
|
||||
std::string columnName = "";
|
||||
if (colNum == 0)
|
||||
return "A";
|
||||
while (colNum > 0) {
|
||||
@@ -30,15 +30,15 @@ namespace platform {
|
||||
}
|
||||
return columnName;
|
||||
}
|
||||
BestResultsExcel::BestResultsExcel(const string& score, const vector<string>& datasets) : score(score), datasets(datasets)
|
||||
BestResultsExcel::BestResultsExcel(const std::string& score, const std::vector<std::string>& datasets) : score(score), datasets(datasets)
|
||||
{
|
||||
workbook = workbook_new((Paths::excel() + fileName).c_str());
|
||||
setProperties("Best Results");
|
||||
int maxDatasetName = (*max_element(datasets.begin(), datasets.end(), [](const string& a, const string& b) { return a.size() < b.size(); })).size();
|
||||
datasetNameSize = max(datasetNameSize, maxDatasetName);
|
||||
int maxDatasetName = (*max_element(datasets.begin(), datasets.end(), [](const std::string& a, const std::string& b) { return a.size() < b.size(); })).size();
|
||||
datasetNameSize = std::max(datasetNameSize, maxDatasetName);
|
||||
createFormats();
|
||||
}
|
||||
void BestResultsExcel::reportAll(const vector<string>& models, const json& table, const map<string, map<string, float>>& ranks, bool friedman, double significance)
|
||||
void BestResultsExcel::reportAll(const std::vector<std::string>& models, const json& table, const std::map<std::string, std::map<std::string, float>>& ranks, bool friedman, double significance)
|
||||
{
|
||||
this->table = table;
|
||||
this->models = models;
|
||||
@@ -46,23 +46,23 @@ namespace platform {
|
||||
this->friedman = friedman;
|
||||
this->significance = significance;
|
||||
worksheet = workbook_add_worksheet(workbook, "Best Results");
|
||||
int maxModelName = (*max_element(models.begin(), models.end(), [](const string& a, const string& b) { return a.size() < b.size(); })).size();
|
||||
modelNameSize = max(modelNameSize, maxModelName);
|
||||
int maxModelName = (*std::max_element(models.begin(), models.end(), [](const std::string& a, const std::string& b) { return a.size() < b.size(); })).size();
|
||||
modelNameSize = std::max(modelNameSize, maxModelName);
|
||||
formatColumns();
|
||||
build();
|
||||
}
|
||||
void BestResultsExcel::reportSingle(const string& model, const string& fileName)
|
||||
void BestResultsExcel::reportSingle(const std::string& model, const std::string& fileName)
|
||||
{
|
||||
worksheet = workbook_add_worksheet(workbook, "Report");
|
||||
if (FILE* fileTest = fopen(fileName.c_str(), "r")) {
|
||||
fclose(fileTest);
|
||||
} else {
|
||||
cerr << "File " << fileName << " doesn't exist." << endl;
|
||||
std::cerr << "File " << fileName << " doesn't exist." << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
json data = loadResultData(fileName);
|
||||
|
||||
string title = "Best results for " + model;
|
||||
std::string title = "Best results for " + model;
|
||||
worksheet_merge_range(worksheet, 0, 0, 0, 4, title.c_str(), styles["headerFirst"]);
|
||||
// Body header
|
||||
row = 3;
|
||||
@@ -73,30 +73,30 @@ namespace platform {
|
||||
writeString(row, 3, "File", "bodyHeader");
|
||||
writeString(row, 4, "Hyperparameters", "bodyHeader");
|
||||
auto i = 0;
|
||||
string hyperparameters;
|
||||
std::string hyperparameters;
|
||||
int hypSize = 22;
|
||||
map<string, string> files; // map of files imported and their tabs
|
||||
std::map<std::string, std::string> files; // map of files imported and their tabs
|
||||
for (auto const& item : data.items()) {
|
||||
row++;
|
||||
writeInt(row, 0, i++, "ints");
|
||||
writeString(row, 1, item.key().c_str(), "text");
|
||||
writeDouble(row, 2, item.value().at(0).get<double>(), "result");
|
||||
auto fileName = item.value().at(2).get<string>();
|
||||
string hyperlink = "";
|
||||
auto fileName = item.value().at(2).get<std::string>();
|
||||
std::string hyperlink = "";
|
||||
try {
|
||||
hyperlink = files.at(fileName);
|
||||
}
|
||||
catch (const out_of_range& oor) {
|
||||
auto tabName = "table_" + to_string(i);
|
||||
catch (const std::out_of_range& oor) {
|
||||
auto tabName = "table_" + std::to_string(i);
|
||||
auto worksheetNew = workbook_add_worksheet(workbook, tabName.c_str());
|
||||
json data = loadResultData(Paths::results() + fileName);
|
||||
auto report = ReportExcel(data, false, workbook, worksheetNew);
|
||||
report.show();
|
||||
hyperlink = "#table_" + to_string(i);
|
||||
hyperlink = "#table_" + std::to_string(i);
|
||||
files[fileName] = hyperlink;
|
||||
}
|
||||
hyperlink += "!H" + to_string(i + 6);
|
||||
string fileNameText = "=HYPERLINK(\"" + hyperlink + "\",\"" + fileName + "\")";
|
||||
hyperlink += "!H" + std::to_string(i + 6);
|
||||
std::string fileNameText = "=HYPERLINK(\"" + hyperlink + "\",\"" + fileName + "\")";
|
||||
worksheet_write_formula(worksheet, row, 3, fileNameText.c_str(), efectiveStyle("text"));
|
||||
hyperparameters = item.value().at(1).dump();
|
||||
if (hyperparameters.size() > hypSize) {
|
||||
@@ -107,13 +107,13 @@ namespace platform {
|
||||
row++;
|
||||
// Set Totals
|
||||
writeString(row, 1, "Total", "bodyHeader");
|
||||
stringstream oss;
|
||||
std::stringstream oss;
|
||||
auto colName = getColumnName(2);
|
||||
oss << "=sum(" << colName << "5:" << colName << row << ")";
|
||||
worksheet_write_formula(worksheet, row, 2, oss.str().c_str(), styles["bodyHeader_odd"]);
|
||||
// Set format
|
||||
worksheet_freeze_panes(worksheet, 4, 2);
|
||||
vector<int> columns_sizes = { 5, datasetNameSize, modelNameSize, 66, hypSize + 1 };
|
||||
std::vector<int> columns_sizes = { 5, datasetNameSize, modelNameSize, 66, hypSize + 1 };
|
||||
for (int i = 0; i < columns_sizes.size(); ++i) {
|
||||
worksheet_set_column(worksheet, i, i, columns_sizes.at(i), NULL);
|
||||
}
|
||||
@@ -125,7 +125,7 @@ namespace platform {
|
||||
void BestResultsExcel::formatColumns()
|
||||
{
|
||||
worksheet_freeze_panes(worksheet, 4, 2);
|
||||
vector<int> columns_sizes = { 5, datasetNameSize };
|
||||
std::vector<int> columns_sizes = { 5, datasetNameSize };
|
||||
for (int i = 0; i < models.size(); ++i) {
|
||||
columns_sizes.push_back(modelNameSize);
|
||||
}
|
||||
@@ -133,7 +133,7 @@ namespace platform {
|
||||
worksheet_set_column(worksheet, i, i, columns_sizes.at(i), NULL);
|
||||
}
|
||||
}
|
||||
void BestResultsExcel::addConditionalFormat(string formula)
|
||||
void BestResultsExcel::addConditionalFormat(std::string formula)
|
||||
{
|
||||
// Add conditional format for max/min values in scores/ranks sheets
|
||||
lxw_format* custom_format = workbook_add_format(workbook);
|
||||
@@ -142,8 +142,8 @@ namespace platform {
|
||||
// Create a conditional format object. A static object would also work.
|
||||
lxw_conditional_format* conditional_format = (lxw_conditional_format*)calloc(1, sizeof(lxw_conditional_format));
|
||||
conditional_format->type = LXW_CONDITIONAL_TYPE_FORMULA;
|
||||
string col = getColumnName(models.size() + 1);
|
||||
stringstream oss;
|
||||
std::string col = getColumnName(models.size() + 1);
|
||||
std::stringstream oss;
|
||||
oss << "=C5=" << formula << "($C5:$" << col << "5)";
|
||||
auto formulaValue = oss.str();
|
||||
conditional_format->value_string = formulaValue.c_str();
|
||||
@@ -170,14 +170,14 @@ namespace platform {
|
||||
doFriedman();
|
||||
}
|
||||
}
|
||||
string BestResultsExcel::getFileName()
|
||||
std::string BestResultsExcel::getFileName()
|
||||
{
|
||||
return Paths::excel() + fileName;
|
||||
}
|
||||
void BestResultsExcel::header(bool ranks)
|
||||
{
|
||||
row = 0;
|
||||
string message = ranks ? "Ranks for score " + score : "Best results for " + score;
|
||||
std::string message = ranks ? "Ranks for score " + score : "Best results for " + score;
|
||||
worksheet_merge_range(worksheet, 0, 0, 0, 1 + models.size(), message.c_str(), styles["headerFirst"]);
|
||||
// Body header
|
||||
row = 3;
|
||||
@@ -210,7 +210,7 @@ namespace platform {
|
||||
writeString(row, 1, "Total", "bodyHeader");
|
||||
int col = 1;
|
||||
for (const auto& model : models) {
|
||||
stringstream oss;
|
||||
std::stringstream oss;
|
||||
auto colName = getColumnName(col + 1);
|
||||
oss << "=SUM(" << colName << "5:" << colName << row << ")";
|
||||
worksheet_write_formula(worksheet, row, ++col, oss.str().c_str(), styles["bodyHeader_odd"]);
|
||||
@@ -221,7 +221,7 @@ namespace platform {
|
||||
int col = 1;
|
||||
for (const auto& model : models) {
|
||||
auto colName = getColumnName(col + 1);
|
||||
stringstream oss;
|
||||
std::stringstream oss;
|
||||
oss << "=SUM(" << colName << "5:" << colName << row - 1 << ")/" << datasets.size();
|
||||
worksheet_write_formula(worksheet, row, ++col, oss.str().c_str(), styles["bodyHeader_odd"]);
|
||||
}
|
||||
@@ -230,7 +230,7 @@ namespace platform {
|
||||
void BestResultsExcel::doFriedman()
|
||||
{
|
||||
worksheet = workbook_add_worksheet(workbook, "Friedman");
|
||||
vector<int> columns_sizes = { 5, datasetNameSize };
|
||||
std::vector<int> columns_sizes = { 5, datasetNameSize };
|
||||
for (int i = 0; i < models.size(); ++i) {
|
||||
columns_sizes.push_back(modelNameSize);
|
||||
}
|
||||
@@ -262,7 +262,7 @@ namespace platform {
|
||||
row += 2;
|
||||
worksheet_merge_range(worksheet, row, 0, row, 1 + models.size(), "Null hypothesis: H0 'There is no significant differences between the control model and the other models.'", styles["headerSmall"]);
|
||||
row += 2;
|
||||
string controlModel = "Control Model: " + holmResult.model;
|
||||
std::string controlModel = "Control Model: " + holmResult.model;
|
||||
worksheet_merge_range(worksheet, row, 1, row, 7, controlModel.c_str(), styles["bodyHeader_odd"]);
|
||||
row++;
|
||||
writeString(row, 1, "Model", "bodyHeader");
|
||||
|
@@ -5,18 +5,17 @@
|
||||
#include <map>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using namespace std;
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace platform {
|
||||
|
||||
class BestResultsExcel : ExcelFile {
|
||||
public:
|
||||
BestResultsExcel(const string& score, const vector<string>& datasets);
|
||||
BestResultsExcel(const std::string& score, const std::vector<std::string>& datasets);
|
||||
~BestResultsExcel();
|
||||
void reportAll(const vector<string>& models, const json& table, const map<string, map<string, float>>& ranks, bool friedman, double significance);
|
||||
void reportSingle(const string& model, const string& fileName);
|
||||
string getFileName();
|
||||
void reportAll(const std::vector<std::string>& models, const json& table, const std::map<std::string, std::map<std::string, float>>& ranks, bool friedman, double significance);
|
||||
void reportSingle(const std::string& model, const std::string& fileName);
|
||||
std::string getFileName();
|
||||
private:
|
||||
void build();
|
||||
void header(bool ranks);
|
||||
@@ -24,13 +23,13 @@ namespace platform {
|
||||
void footer(bool ranks);
|
||||
void formatColumns();
|
||||
void doFriedman();
|
||||
void addConditionalFormat(string formula);
|
||||
const string fileName = "BestResults.xlsx";
|
||||
string score;
|
||||
vector<string> models;
|
||||
vector<string> datasets;
|
||||
void addConditionalFormat(std::string formula);
|
||||
const std::string fileName = "BestResults.xlsx";
|
||||
std::string score;
|
||||
std::vector<std::string> models;
|
||||
std::vector<std::string> datasets;
|
||||
json table;
|
||||
map<string, map<string, float>> ranksModels;
|
||||
std::map<std::string, std::map<std::string, float>> ranksModels;
|
||||
bool friedman;
|
||||
double significance;
|
||||
int modelNameSize = 12; // Min size of the column
|
||||
|
@@ -7,14 +7,14 @@
|
||||
namespace platform {
|
||||
class BestScore {
|
||||
public:
|
||||
static pair<string, double> getScore(const std::string& metric)
|
||||
static std::pair<std::string, double> getScore(const std::string& metric)
|
||||
{
|
||||
static map<pair<string, string>, pair<string, double>> data = {
|
||||
static std::map<std::pair<std::string, std::string>, std::pair<std::string, double>> data = {
|
||||
{{"discretiz", "accuracy"}, {"STree_default (linear-ovo)", 22.109799}},
|
||||
{{"odte", "accuracy"}, {"STree_default (linear-ovo)", 22.109799}},
|
||||
};
|
||||
auto env = platform::DotEnv();
|
||||
string experiment = env.get("experiment");
|
||||
std::string experiment = env.get("experiment");
|
||||
try {
|
||||
return data[{experiment, metric}];
|
||||
}
|
||||
|
@@ -2,22 +2,20 @@
|
||||
#define LOCALE_H
|
||||
#include <locale>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
using namespace std;
|
||||
namespace platform {
|
||||
struct separation : numpunct<char> {
|
||||
struct separation : std::numpunct<char> {
|
||||
char do_decimal_point() const { return ','; }
|
||||
char do_thousands_sep() const { return '.'; }
|
||||
string do_grouping() const { return "\03"; }
|
||||
std::string do_grouping() const { return "\03"; }
|
||||
};
|
||||
class ConfigLocale {
|
||||
public:
|
||||
explicit ConfigLocale()
|
||||
{
|
||||
locale mylocale(cout.getloc(), new separation);
|
||||
locale::global(mylocale);
|
||||
cout.imbue(mylocale);
|
||||
std::locale mylocale(std::cout.getloc(), new separation);
|
||||
std::locale::global(mylocale);
|
||||
std::cout.imbue(mylocale);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@@ -6,16 +6,16 @@
|
||||
#include "Utils.h"
|
||||
|
||||
namespace platform {
|
||||
void CommandParser::messageError(const string& message)
|
||||
void CommandParser::messageError(const std::string& message)
|
||||
{
|
||||
cout << Colors::RED() << message << Colors::RESET() << endl;
|
||||
std::cout << Colors::RED() << message << Colors::RESET() << std::endl;
|
||||
}
|
||||
pair<char, int> CommandParser::parse(const string& color, const vector<tuple<string, char, bool>>& options, const char defaultCommand, const int maxIndex)
|
||||
std::pair<char, int> CommandParser::parse(const std::string& color, const std::vector<std::tuple<std::string, char, bool>>& options, const char defaultCommand, const int maxIndex)
|
||||
{
|
||||
bool finished = false;
|
||||
while (!finished) {
|
||||
stringstream oss;
|
||||
string line;
|
||||
std::stringstream oss;
|
||||
std::string line;
|
||||
oss << color << "Choose option (";
|
||||
bool first = true;
|
||||
for (auto& option : options) {
|
||||
@@ -24,12 +24,12 @@ namespace platform {
|
||||
} else {
|
||||
oss << ", ";
|
||||
}
|
||||
oss << get<char>(option) << "=" << get<string>(option);
|
||||
oss << std::get<char>(option) << "=" << std::get<std::string>(option);
|
||||
}
|
||||
oss << "): ";
|
||||
cout << oss.str();
|
||||
getline(cin, line);
|
||||
cout << Colors::RESET();
|
||||
std::cout << oss.str();
|
||||
getline(std::cin, line);
|
||||
std::cout << Colors::RESET();
|
||||
line = trim(line);
|
||||
if (line.size() == 0)
|
||||
continue;
|
||||
@@ -45,15 +45,15 @@ namespace platform {
|
||||
}
|
||||
bool found = false;
|
||||
for (auto& option : options) {
|
||||
if (line[0] == get<char>(option)) {
|
||||
if (line[0] == std::get<char>(option)) {
|
||||
found = true;
|
||||
// it's a match
|
||||
line.erase(line.begin());
|
||||
line = trim(line);
|
||||
if (get<bool>(option)) {
|
||||
if (std::get<bool>(option)) {
|
||||
// The option requires a value
|
||||
if (line.size() == 0) {
|
||||
messageError("Option " + get<string>(option) + " requires a value");
|
||||
messageError("Option " + std::get<std::string>(option) + " requires a value");
|
||||
break;
|
||||
}
|
||||
try {
|
||||
@@ -69,11 +69,11 @@ namespace platform {
|
||||
}
|
||||
} else {
|
||||
if (line.size() > 0) {
|
||||
messageError("option " + get<string>(option) + " doesn't accept values");
|
||||
messageError("option " + std::get<std::string>(option) + " doesn't accept values");
|
||||
break;
|
||||
}
|
||||
}
|
||||
command = get<char>(option);
|
||||
command = std::get<char>(option);
|
||||
finished = true;
|
||||
break;
|
||||
}
|
||||
|
@@ -3,17 +3,16 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <tuple>
|
||||
using namespace std;
|
||||
|
||||
namespace platform {
|
||||
class CommandParser {
|
||||
public:
|
||||
CommandParser() = default;
|
||||
pair<char, int> parse(const string& color, const vector<tuple<string, char, bool>>& options, const char defaultCommand, const int maxIndex);
|
||||
std::pair<char, int> parse(const std::string& color, const std::vector<std::tuple<std::string, char, bool>>& options, const char defaultCommand, const int maxIndex);
|
||||
char getCommand() const { return command; };
|
||||
int getIndex() const { return index; };
|
||||
private:
|
||||
void messageError(const string& message);
|
||||
void messageError(const std::string& message);
|
||||
char command;
|
||||
int index;
|
||||
};
|
||||
|
@@ -5,20 +5,20 @@ namespace platform {
|
||||
Dataset::Dataset(const Dataset& dataset) : path(dataset.path), name(dataset.name), className(dataset.className), n_samples(dataset.n_samples), n_features(dataset.n_features), features(dataset.features), states(dataset.states), loaded(dataset.loaded), discretize(dataset.discretize), X(dataset.X), y(dataset.y), Xv(dataset.Xv), Xd(dataset.Xd), yv(dataset.yv), fileType(dataset.fileType)
|
||||
{
|
||||
}
|
||||
string Dataset::getName() const
|
||||
std::string Dataset::getName() const
|
||||
{
|
||||
return name;
|
||||
}
|
||||
string Dataset::getClassName() const
|
||||
std::string Dataset::getClassName() const
|
||||
{
|
||||
return className;
|
||||
}
|
||||
vector<string> Dataset::getFeatures() const
|
||||
std::vector<std::string> Dataset::getFeatures() const
|
||||
{
|
||||
if (loaded) {
|
||||
return features;
|
||||
} else {
|
||||
throw invalid_argument("Dataset not loaded.");
|
||||
throw std::invalid_argument("Dataset not loaded.");
|
||||
}
|
||||
}
|
||||
int Dataset::getNFeatures() const
|
||||
@@ -26,7 +26,7 @@ namespace platform {
|
||||
if (loaded) {
|
||||
return n_features;
|
||||
} else {
|
||||
throw invalid_argument("Dataset not loaded.");
|
||||
throw std::invalid_argument("Dataset not loaded.");
|
||||
}
|
||||
}
|
||||
int Dataset::getNSamples() const
|
||||
@@ -34,31 +34,31 @@ namespace platform {
|
||||
if (loaded) {
|
||||
return n_samples;
|
||||
} else {
|
||||
throw invalid_argument("Dataset not loaded.");
|
||||
throw std::invalid_argument("Dataset not loaded.");
|
||||
}
|
||||
}
|
||||
map<string, vector<int>> Dataset::getStates() const
|
||||
std::map<std::string, std::vector<int>> Dataset::getStates() const
|
||||
{
|
||||
if (loaded) {
|
||||
return states;
|
||||
} else {
|
||||
throw invalid_argument("Dataset not loaded.");
|
||||
throw std::invalid_argument("Dataset not loaded.");
|
||||
}
|
||||
}
|
||||
pair<vector<vector<float>>&, vector<int>&> Dataset::getVectors()
|
||||
pair<std::vector<std::vector<float>>&, std::vector<int>&> Dataset::getVectors()
|
||||
{
|
||||
if (loaded) {
|
||||
return { Xv, yv };
|
||||
} else {
|
||||
throw invalid_argument("Dataset not loaded.");
|
||||
throw std::invalid_argument("Dataset not loaded.");
|
||||
}
|
||||
}
|
||||
pair<vector<vector<int>>&, vector<int>&> Dataset::getVectorsDiscretized()
|
||||
pair<std::vector<std::vector<int>>&, std::vector<int>&> Dataset::getVectorsDiscretized()
|
||||
{
|
||||
if (loaded) {
|
||||
return { Xd, yv };
|
||||
} else {
|
||||
throw invalid_argument("Dataset not loaded.");
|
||||
throw std::invalid_argument("Dataset not loaded.");
|
||||
}
|
||||
}
|
||||
pair<torch::Tensor&, torch::Tensor&> Dataset::getTensors()
|
||||
@@ -67,22 +67,22 @@ namespace platform {
|
||||
buildTensors();
|
||||
return { X, y };
|
||||
} else {
|
||||
throw invalid_argument("Dataset not loaded.");
|
||||
throw std::invalid_argument("Dataset not loaded.");
|
||||
}
|
||||
}
|
||||
void Dataset::load_csv()
|
||||
{
|
||||
ifstream file(path + "/" + name + ".csv");
|
||||
if (file.is_open()) {
|
||||
string line;
|
||||
std::string line;
|
||||
getline(file, line);
|
||||
vector<string> tokens = split(line, ',');
|
||||
features = vector<string>(tokens.begin(), tokens.end() - 1);
|
||||
std::vector<std::string> tokens = split(line, ',');
|
||||
features = std::vector<std::string>(tokens.begin(), tokens.end() - 1);
|
||||
if (className == "-1") {
|
||||
className = tokens.back();
|
||||
}
|
||||
for (auto i = 0; i < features.size(); ++i) {
|
||||
Xv.push_back(vector<float>());
|
||||
Xv.push_back(std::vector<float>());
|
||||
}
|
||||
while (getline(file, line)) {
|
||||
tokens = split(line, ',');
|
||||
@@ -93,17 +93,17 @@ namespace platform {
|
||||
}
|
||||
file.close();
|
||||
} else {
|
||||
throw invalid_argument("Unable to open dataset file.");
|
||||
throw std::invalid_argument("Unable to open dataset file.");
|
||||
}
|
||||
}
|
||||
void Dataset::computeStates()
|
||||
{
|
||||
for (int i = 0; i < features.size(); ++i) {
|
||||
states[features[i]] = vector<int>(*max_element(Xd[i].begin(), Xd[i].end()) + 1);
|
||||
states[features[i]] = std::vector<int>(*max_element(Xd[i].begin(), Xd[i].end()) + 1);
|
||||
auto item = states.at(features[i]);
|
||||
iota(begin(item), end(item), 0);
|
||||
}
|
||||
states[className] = vector<int>(*max_element(yv.begin(), yv.end()) + 1);
|
||||
states[className] = std::vector<int>(*max_element(yv.begin(), yv.end()) + 1);
|
||||
iota(begin(states.at(className)), end(states.at(className)), 0);
|
||||
}
|
||||
void Dataset::load_arff()
|
||||
@@ -118,12 +118,12 @@ namespace platform {
|
||||
auto attributes = arff.getAttributes();
|
||||
transform(attributes.begin(), attributes.end(), back_inserter(features), [](const auto& attribute) { return attribute.first; });
|
||||
}
|
||||
vector<string> tokenize(string line)
|
||||
std::vector<std::string> tokenize(std::string line)
|
||||
{
|
||||
vector<string> tokens;
|
||||
std::vector<std::string> tokens;
|
||||
for (auto i = 0; i < line.size(); ++i) {
|
||||
if (line[i] == ' ' || line[i] == '\t' || line[i] == '\n') {
|
||||
string token = line.substr(0, i);
|
||||
std::string token = line.substr(0, i);
|
||||
tokens.push_back(token);
|
||||
line.erase(line.begin(), line.begin() + i + 1);
|
||||
i = 0;
|
||||
@@ -140,16 +140,16 @@ namespace platform {
|
||||
{
|
||||
ifstream file(path + "/" + name + "_R.dat");
|
||||
if (file.is_open()) {
|
||||
string line;
|
||||
std::string line;
|
||||
getline(file, line);
|
||||
line = ArffFiles::trim(line);
|
||||
vector<string> tokens = tokenize(line);
|
||||
std::vector<std::string> tokens = tokenize(line);
|
||||
transform(tokens.begin(), tokens.end() - 1, back_inserter(features), [](const auto& attribute) { return ArffFiles::trim(attribute); });
|
||||
if (className == "-1") {
|
||||
className = ArffFiles::trim(tokens.back());
|
||||
}
|
||||
for (auto i = 0; i < features.size(); ++i) {
|
||||
Xv.push_back(vector<float>());
|
||||
Xv.push_back(std::vector<float>());
|
||||
}
|
||||
while (getline(file, line)) {
|
||||
tokens = tokenize(line);
|
||||
@@ -162,7 +162,7 @@ namespace platform {
|
||||
}
|
||||
file.close();
|
||||
} else {
|
||||
throw invalid_argument("Unable to open dataset file.");
|
||||
throw std::invalid_argument("Unable to open dataset file.");
|
||||
}
|
||||
}
|
||||
void Dataset::load()
|
||||
@@ -201,9 +201,9 @@ namespace platform {
|
||||
}
|
||||
y = torch::tensor(yv, torch::kInt32);
|
||||
}
|
||||
vector<mdlp::labels_t> Dataset::discretizeDataset(vector<mdlp::samples_t>& X, mdlp::labels_t& y)
|
||||
std::vector<mdlp::labels_t> Dataset::discretizeDataset(std::vector<mdlp::samples_t>& X, mdlp::labels_t& y)
|
||||
{
|
||||
vector<mdlp::labels_t> Xd;
|
||||
std::vector<mdlp::labels_t> Xd;
|
||||
auto fimdlp = mdlp::CPPFImdlp();
|
||||
for (int i = 0; i < X.size(); i++) {
|
||||
fimdlp.fit(X[i], y);
|
||||
|
@@ -7,12 +7,10 @@
|
||||
#include "CPPFImdlp.h"
|
||||
#include "Utils.h"
|
||||
namespace platform {
|
||||
using namespace std;
|
||||
|
||||
enum fileType_t { CSV, ARFF, RDATA };
|
||||
class SourceData {
|
||||
public:
|
||||
SourceData(string source)
|
||||
SourceData(std::string source)
|
||||
{
|
||||
if (source == "Surcov") {
|
||||
path = "datasets/";
|
||||
@@ -24,10 +22,10 @@ namespace platform {
|
||||
path = "data/";
|
||||
fileType = RDATA;
|
||||
} else {
|
||||
throw invalid_argument("Unknown source.");
|
||||
throw std::invalid_argument("Unknown source.");
|
||||
}
|
||||
}
|
||||
string getPath()
|
||||
std::string getPath()
|
||||
{
|
||||
return path;
|
||||
}
|
||||
@@ -36,40 +34,40 @@ namespace platform {
|
||||
return fileType;
|
||||
}
|
||||
private:
|
||||
string path;
|
||||
std::string path;
|
||||
fileType_t fileType;
|
||||
};
|
||||
class Dataset {
|
||||
private:
|
||||
string path;
|
||||
string name;
|
||||
std::string path;
|
||||
std::string name;
|
||||
fileType_t fileType;
|
||||
string className;
|
||||
std::string className;
|
||||
int n_samples{ 0 }, n_features{ 0 };
|
||||
vector<string> features;
|
||||
map<string, vector<int>> states;
|
||||
std::vector<std::string> features;
|
||||
std::map<std::string, std::vector<int>> states;
|
||||
bool loaded;
|
||||
bool discretize;
|
||||
torch::Tensor X, y;
|
||||
vector<vector<float>> Xv;
|
||||
vector<vector<int>> Xd;
|
||||
vector<int> yv;
|
||||
std::vector<std::vector<float>> Xv;
|
||||
std::vector<std::vector<int>> Xd;
|
||||
std::vector<int> yv;
|
||||
void buildTensors();
|
||||
void load_csv();
|
||||
void load_arff();
|
||||
void load_rdata();
|
||||
void computeStates();
|
||||
vector<mdlp::labels_t> discretizeDataset(vector<mdlp::samples_t>& X, mdlp::labels_t& y);
|
||||
std::vector<mdlp::labels_t> discretizeDataset(std::vector<mdlp::samples_t>& X, mdlp::labels_t& y);
|
||||
public:
|
||||
Dataset(const string& path, const string& name, const string& className, bool discretize, fileType_t fileType) : path(path), name(name), className(className), discretize(discretize), loaded(false), fileType(fileType) {};
|
||||
Dataset(const std::string& path, const std::string& name, const std::string& className, bool discretize, fileType_t fileType) : path(path), name(name), className(className), discretize(discretize), loaded(false), fileType(fileType) {};
|
||||
explicit Dataset(const Dataset&);
|
||||
string getName() const;
|
||||
string getClassName() const;
|
||||
vector<string> getFeatures() const;
|
||||
map<string, vector<int>> getStates() const;
|
||||
pair<vector<vector<float>>&, vector<int>&> getVectors();
|
||||
pair<vector<vector<int>>&, vector<int>&> getVectorsDiscretized();
|
||||
pair<torch::Tensor&, torch::Tensor&> getTensors();
|
||||
std::string getName() const;
|
||||
std::string getClassName() const;
|
||||
std::vector<string> getFeatures() const;
|
||||
std::map<std::string, std::vector<int>> getStates() const;
|
||||
std::pair<vector<std::vector<float>>&, std::vector<int>&> getVectors();
|
||||
std::pair<vector<std::vector<int>>&, std::vector<int>&> getVectorsDiscretized();
|
||||
std::pair<torch::Tensor&, torch::Tensor&> getTensors();
|
||||
int getNFeatures() const;
|
||||
int getNSamples() const;
|
||||
void load();
|
||||
|
@@ -8,14 +8,14 @@ namespace platform {
|
||||
path = sd.getPath();
|
||||
ifstream catalog(path + "all.txt");
|
||||
if (catalog.is_open()) {
|
||||
string line;
|
||||
std::string line;
|
||||
while (getline(catalog, line)) {
|
||||
if (line.empty() || line[0] == '#') {
|
||||
continue;
|
||||
}
|
||||
vector<string> tokens = split(line, ',');
|
||||
string name = tokens[0];
|
||||
string className;
|
||||
std::vector<std::string> tokens = split(line, ',');
|
||||
std::string name = tokens[0];
|
||||
std::string className;
|
||||
if (tokens.size() == 1) {
|
||||
className = "-1";
|
||||
} else {
|
||||
@@ -25,32 +25,32 @@ namespace platform {
|
||||
}
|
||||
catalog.close();
|
||||
} else {
|
||||
throw invalid_argument("Unable to open catalog file. [" + path + "all.txt" + "]");
|
||||
throw std::invalid_argument("Unable to open catalog file. [" + path + "all.txt" + "]");
|
||||
}
|
||||
}
|
||||
vector<string> Datasets::getNames()
|
||||
std::vector<std::string> Datasets::getNames()
|
||||
{
|
||||
vector<string> result;
|
||||
std::vector<std::string> result;
|
||||
transform(datasets.begin(), datasets.end(), back_inserter(result), [](const auto& d) { return d.first; });
|
||||
return result;
|
||||
}
|
||||
vector<string> Datasets::getFeatures(const string& name) const
|
||||
std::vector<std::string> Datasets::getFeatures(const std::string& name) const
|
||||
{
|
||||
if (datasets.at(name)->isLoaded()) {
|
||||
return datasets.at(name)->getFeatures();
|
||||
} else {
|
||||
throw invalid_argument("Dataset not loaded.");
|
||||
throw std::invalid_argument("Dataset not loaded.");
|
||||
}
|
||||
}
|
||||
map<string, vector<int>> Datasets::getStates(const string& name) const
|
||||
map<std::string, std::vector<int>> Datasets::getStates(const std::string& name) const
|
||||
{
|
||||
if (datasets.at(name)->isLoaded()) {
|
||||
return datasets.at(name)->getStates();
|
||||
} else {
|
||||
throw invalid_argument("Dataset not loaded.");
|
||||
throw std::invalid_argument("Dataset not loaded.");
|
||||
}
|
||||
}
|
||||
void Datasets::loadDataset(const string& name) const
|
||||
void Datasets::loadDataset(const std::string& name) const
|
||||
{
|
||||
if (datasets.at(name)->isLoaded()) {
|
||||
return;
|
||||
@@ -58,23 +58,23 @@ namespace platform {
|
||||
datasets.at(name)->load();
|
||||
}
|
||||
}
|
||||
string Datasets::getClassName(const string& name) const
|
||||
std::string Datasets::getClassName(const std::string& name) const
|
||||
{
|
||||
if (datasets.at(name)->isLoaded()) {
|
||||
return datasets.at(name)->getClassName();
|
||||
} else {
|
||||
throw invalid_argument("Dataset not loaded.");
|
||||
throw std::invalid_argument("Dataset not loaded.");
|
||||
}
|
||||
}
|
||||
int Datasets::getNSamples(const string& name) const
|
||||
int Datasets::getNSamples(const std::string& name) const
|
||||
{
|
||||
if (datasets.at(name)->isLoaded()) {
|
||||
return datasets.at(name)->getNSamples();
|
||||
} else {
|
||||
throw invalid_argument("Dataset not loaded.");
|
||||
throw std::invalid_argument("Dataset not loaded.");
|
||||
}
|
||||
}
|
||||
int Datasets::getNClasses(const string& name)
|
||||
int Datasets::getNClasses(const std::string& name)
|
||||
{
|
||||
if (datasets.at(name)->isLoaded()) {
|
||||
auto className = datasets.at(name)->getClassName();
|
||||
@@ -83,46 +83,46 @@ namespace platform {
|
||||
return states.at(className).size();
|
||||
}
|
||||
auto [Xv, yv] = getVectors(name);
|
||||
return *max_element(yv.begin(), yv.end()) + 1;
|
||||
return *std::max_element(yv.begin(), yv.end()) + 1;
|
||||
} else {
|
||||
throw invalid_argument("Dataset not loaded.");
|
||||
throw std::invalid_argument("Dataset not loaded.");
|
||||
}
|
||||
}
|
||||
vector<int> Datasets::getClassesCounts(const string& name) const
|
||||
std::vector<int> Datasets::getClassesCounts(const std::string& name) const
|
||||
{
|
||||
if (datasets.at(name)->isLoaded()) {
|
||||
auto [Xv, yv] = datasets.at(name)->getVectors();
|
||||
vector<int> counts(*max_element(yv.begin(), yv.end()) + 1);
|
||||
std::vector<int> counts(*std::max_element(yv.begin(), yv.end()) + 1);
|
||||
for (auto y : yv) {
|
||||
counts[y]++;
|
||||
}
|
||||
return counts;
|
||||
} else {
|
||||
throw invalid_argument("Dataset not loaded.");
|
||||
throw std::invalid_argument("Dataset not loaded.");
|
||||
}
|
||||
}
|
||||
pair<vector<vector<float>>&, vector<int>&> Datasets::getVectors(const string& name)
|
||||
pair<std::vector<std::vector<float>>&, std::vector<int>&> Datasets::getVectors(const std::string& name)
|
||||
{
|
||||
if (!datasets[name]->isLoaded()) {
|
||||
datasets[name]->load();
|
||||
}
|
||||
return datasets[name]->getVectors();
|
||||
}
|
||||
pair<vector<vector<int>>&, vector<int>&> Datasets::getVectorsDiscretized(const string& name)
|
||||
pair<std::vector<std::vector<int>>&, std::vector<int>&> Datasets::getVectorsDiscretized(const std::string& name)
|
||||
{
|
||||
if (!datasets[name]->isLoaded()) {
|
||||
datasets[name]->load();
|
||||
}
|
||||
return datasets[name]->getVectorsDiscretized();
|
||||
}
|
||||
pair<torch::Tensor&, torch::Tensor&> Datasets::getTensors(const string& name)
|
||||
pair<torch::Tensor&, torch::Tensor&> Datasets::getTensors(const std::string& name)
|
||||
{
|
||||
if (!datasets[name]->isLoaded()) {
|
||||
datasets[name]->load();
|
||||
}
|
||||
return datasets[name]->getTensors();
|
||||
}
|
||||
bool Datasets::isDataset(const string& name) const
|
||||
bool Datasets::isDataset(const std::string& name) const
|
||||
{
|
||||
return datasets.find(name) != datasets.end();
|
||||
}
|
||||
|
@@ -2,29 +2,28 @@
|
||||
#define DATASETS_H
|
||||
#include "Dataset.h"
|
||||
namespace platform {
|
||||
using namespace std;
|
||||
class Datasets {
|
||||
private:
|
||||
string path;
|
||||
std::string path;
|
||||
fileType_t fileType;
|
||||
string sfileType;
|
||||
map<string, unique_ptr<Dataset>> datasets;
|
||||
std::string sfileType;
|
||||
std::map<std::string, std::unique_ptr<Dataset>> datasets;
|
||||
bool discretize;
|
||||
void load(); // Loads the list of datasets
|
||||
public:
|
||||
explicit Datasets(bool discretize, string sfileType) : discretize(discretize), sfileType(sfileType) { load(); };
|
||||
vector<string> getNames();
|
||||
vector<string> getFeatures(const string& name) const;
|
||||
int getNSamples(const string& name) const;
|
||||
string getClassName(const string& name) const;
|
||||
int getNClasses(const string& name);
|
||||
vector<int> getClassesCounts(const string& name) const;
|
||||
map<string, vector<int>> getStates(const string& name) const;
|
||||
pair<vector<vector<float>>&, vector<int>&> getVectors(const string& name);
|
||||
pair<vector<vector<int>>&, vector<int>&> getVectorsDiscretized(const string& name);
|
||||
pair<torch::Tensor&, torch::Tensor&> getTensors(const string& name);
|
||||
bool isDataset(const string& name) const;
|
||||
void loadDataset(const string& name) const;
|
||||
explicit Datasets(bool discretize, std::string sfileType) : discretize(discretize), sfileType(sfileType) { load(); };
|
||||
std::vector<string> getNames();
|
||||
std::vector<string> getFeatures(const std::string& name) const;
|
||||
int getNSamples(const std::string& name) const;
|
||||
std::string getClassName(const std::string& name) const;
|
||||
int getNClasses(const std::string& name);
|
||||
std::vector<int> getClassesCounts(const std::string& name) const;
|
||||
std::map<std::string, std::vector<int>> getStates(const std::string& name) const;
|
||||
std::pair<std::vector<std::vector<float>>&, std::vector<int>&> getVectors(const std::string& name);
|
||||
std::pair<std::vector<std::vector<int>>&, std::vector<int>&> getVectorsDiscretized(const std::string& name);
|
||||
std::pair<torch::Tensor&, torch::Tensor&> getTensors(const std::string& name);
|
||||
bool isDataset(const std::string& name) const;
|
||||
void loadDataset(const std::string& name) const;
|
||||
};
|
||||
};
|
||||
|
||||
|
@@ -26,7 +26,7 @@ namespace platform {
|
||||
{
|
||||
return workbook;
|
||||
}
|
||||
void ExcelFile::setProperties(string title)
|
||||
void ExcelFile::setProperties(std::string title)
|
||||
{
|
||||
char line[title.size() + 1];
|
||||
strcpy(line, title.c_str());
|
||||
@@ -40,34 +40,34 @@ namespace platform {
|
||||
};
|
||||
workbook_set_properties(workbook, &properties);
|
||||
}
|
||||
lxw_format* ExcelFile::efectiveStyle(const string& style)
|
||||
lxw_format* ExcelFile::efectiveStyle(const std::string& style)
|
||||
{
|
||||
lxw_format* efectiveStyle = NULL;
|
||||
if (style != "") {
|
||||
string suffix = row % 2 ? "_odd" : "_even";
|
||||
std::string suffix = row % 2 ? "_odd" : "_even";
|
||||
try {
|
||||
efectiveStyle = styles.at(style + suffix);
|
||||
}
|
||||
catch (const out_of_range& oor) {
|
||||
catch (const std::out_of_range& oor) {
|
||||
try {
|
||||
efectiveStyle = styles.at(style);
|
||||
}
|
||||
catch (const out_of_range& oor) {
|
||||
throw invalid_argument("Style " + style + " not found");
|
||||
catch (const std::out_of_range& oor) {
|
||||
throw std::invalid_argument("Style " + style + " not found");
|
||||
}
|
||||
}
|
||||
}
|
||||
return efectiveStyle;
|
||||
}
|
||||
void ExcelFile::writeString(int row, int col, const string& text, const string& style)
|
||||
void ExcelFile::writeString(int row, int col, const std::string& text, const std::string& style)
|
||||
{
|
||||
worksheet_write_string(worksheet, row, col, text.c_str(), efectiveStyle(style));
|
||||
}
|
||||
void ExcelFile::writeInt(int row, int col, const int number, const string& style)
|
||||
void ExcelFile::writeInt(int row, int col, const int number, const std::string& style)
|
||||
{
|
||||
worksheet_write_number(worksheet, row, col, number, efectiveStyle(style));
|
||||
}
|
||||
void ExcelFile::writeDouble(int row, int col, const double number, const string& style)
|
||||
void ExcelFile::writeDouble(int row, int col, const double number, const std::string& style)
|
||||
{
|
||||
worksheet_write_number(worksheet, row, col, number, efectiveStyle(style));
|
||||
}
|
||||
@@ -76,7 +76,7 @@ namespace platform {
|
||||
uint32_t efectiveColor = odd ? colorEven : colorOdd;
|
||||
format_set_bg_color(style, lxw_color_t(efectiveColor));
|
||||
}
|
||||
void ExcelFile::createStyle(const string& name, lxw_format* style, bool odd)
|
||||
void ExcelFile::createStyle(const std::string& name, lxw_format* style, bool odd)
|
||||
{
|
||||
addColor(style, odd);
|
||||
if (name == "textCentered") {
|
||||
@@ -116,7 +116,7 @@ namespace platform {
|
||||
{
|
||||
auto styleNames = { "text", "textCentered", "bodyHeader", "result", "time", "ints", "floats" };
|
||||
lxw_format* style;
|
||||
for (string name : styleNames) {
|
||||
for (std::string name : styleNames) {
|
||||
lxw_format* style = workbook_add_format(workbook);
|
||||
style = workbook_add_format(workbook);
|
||||
createStyle(name, style, true);
|
||||
|
@@ -5,14 +5,13 @@
|
||||
#include <map>
|
||||
#include "xlsxwriter.h"
|
||||
|
||||
using namespace std;
|
||||
namespace platform {
|
||||
struct separated : numpunct<char> {
|
||||
struct separated : std::numpunct<char> {
|
||||
char do_decimal_point() const { return ','; }
|
||||
|
||||
char do_thousands_sep() const { return '.'; }
|
||||
|
||||
string do_grouping() const { return "\03"; }
|
||||
std::string do_grouping() const { return "\03"; }
|
||||
};
|
||||
class ExcelFile {
|
||||
public:
|
||||
@@ -21,17 +20,17 @@ namespace platform {
|
||||
ExcelFile(lxw_workbook* workbook, lxw_worksheet* worksheet);
|
||||
lxw_workbook* getWorkbook();
|
||||
protected:
|
||||
void setProperties(string title);
|
||||
void writeString(int row, int col, const string& text, const string& style = "");
|
||||
void writeInt(int row, int col, const int number, const string& style = "");
|
||||
void writeDouble(int row, int col, const double number, const string& style = "");
|
||||
void setProperties(std::string title);
|
||||
void writeString(int row, int col, const std::string& text, const std::string& style = "");
|
||||
void writeInt(int row, int col, const int number, const std::string& style = "");
|
||||
void writeDouble(int row, int col, const double number, const std::string& style = "");
|
||||
void createFormats();
|
||||
void createStyle(const string& name, lxw_format* style, bool odd);
|
||||
void createStyle(const std::string& name, lxw_format* style, bool odd);
|
||||
void addColor(lxw_format* style, bool odd);
|
||||
lxw_format* efectiveStyle(const string& name);
|
||||
lxw_format* efectiveStyle(const std::string& name);
|
||||
lxw_workbook* workbook;
|
||||
lxw_worksheet* worksheet;
|
||||
map<string, lxw_format*> styles;
|
||||
std::map<std::string, lxw_format*> styles;
|
||||
int row;
|
||||
int normalSize; //font size for report body
|
||||
uint32_t colorTitle;
|
||||
|
@@ -6,7 +6,7 @@
|
||||
#include "Paths.h"
|
||||
namespace platform {
|
||||
using json = nlohmann::json;
|
||||
string get_date()
|
||||
std::string get_date()
|
||||
{
|
||||
time_t rawtime;
|
||||
tm* timeinfo;
|
||||
@@ -16,7 +16,7 @@ namespace platform {
|
||||
oss << std::put_time(timeinfo, "%Y-%m-%d");
|
||||
return oss.str();
|
||||
}
|
||||
string get_time()
|
||||
std::string get_time()
|
||||
{
|
||||
time_t rawtime;
|
||||
tm* timeinfo;
|
||||
@@ -27,9 +27,9 @@ namespace platform {
|
||||
return oss.str();
|
||||
}
|
||||
Experiment::Experiment() : hyperparameters(json::parse("{}")) {}
|
||||
string Experiment::get_file_name()
|
||||
std::string Experiment::get_file_name()
|
||||
{
|
||||
string result = "results_" + score_name + "_" + model + "_" + platform + "_" + get_date() + "_" + get_time() + "_" + (stratified ? "1" : "0") + ".json";
|
||||
std::string result = "results_" + score_name + "_" + model + "_" + platform + "_" + get_date() + "_" + get_time() + "_" + (stratified ? "1" : "0") + ".json";
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ namespace platform {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
void Experiment::save(const string& path)
|
||||
void Experiment::save(const std::string& path)
|
||||
{
|
||||
json data = build_json();
|
||||
ofstream file(path + "/" + get_file_name());
|
||||
@@ -99,20 +99,20 @@ namespace platform {
|
||||
void Experiment::show()
|
||||
{
|
||||
json data = build_json();
|
||||
cout << data.dump(4) << endl;
|
||||
std::cout << data.dump(4) << std::endl;
|
||||
}
|
||||
|
||||
void Experiment::go(vector<string> filesToProcess, bool quiet)
|
||||
void Experiment::go(std::vector<std::string> filesToProcess, bool quiet)
|
||||
{
|
||||
cout << "*** Starting experiment: " << title << " ***" << endl;
|
||||
std::cout << "*** Starting experiment: " << title << " ***" << std::endl;
|
||||
for (auto fileName : filesToProcess) {
|
||||
cout << "- " << setw(20) << left << fileName << " " << right << flush;
|
||||
std::cout << "- " << setw(20) << left << fileName << " " << right << flush;
|
||||
cross_validation(fileName, quiet);
|
||||
cout << endl;
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
string getColor(bayesnet::status_t status)
|
||||
std::string getColor(bayesnet::status_t status)
|
||||
{
|
||||
switch (status) {
|
||||
case bayesnet::NORMAL:
|
||||
@@ -126,13 +126,13 @@ namespace platform {
|
||||
}
|
||||
}
|
||||
|
||||
void showProgress(int fold, const string& color, const string& phase)
|
||||
void showProgress(int fold, const std::string& color, const std::string& phase)
|
||||
{
|
||||
string prefix = phase == "a" ? "" : "\b\b\b\b";
|
||||
cout << prefix << color << fold << Colors::RESET() << "(" << color << phase << Colors::RESET() << ")" << flush;
|
||||
std::string prefix = phase == "a" ? "" : "\b\b\b\b";
|
||||
std::cout << prefix << color << fold << Colors::RESET() << "(" << color << phase << Colors::RESET() << ")" << flush;
|
||||
|
||||
}
|
||||
void Experiment::cross_validation(const string& fileName, bool quiet)
|
||||
void Experiment::cross_validation(const std::string& fileName, bool quiet)
|
||||
{
|
||||
auto datasets = platform::Datasets(discretized, Paths::datasets());
|
||||
// Get dataset
|
||||
@@ -142,14 +142,14 @@ namespace platform {
|
||||
auto samples = datasets.getNSamples(fileName);
|
||||
auto className = datasets.getClassName(fileName);
|
||||
if (!quiet) {
|
||||
cout << " (" << setw(5) << samples << "," << setw(3) << features.size() << ") " << flush;
|
||||
std::cout << " (" << setw(5) << samples << "," << setw(3) << features.size() << ") " << flush;
|
||||
}
|
||||
// Prepare Result
|
||||
auto result = Result();
|
||||
auto [values, counts] = at::_unique(y);
|
||||
result.setSamples(X.size(1)).setFeatures(X.size(0)).setClasses(values.size(0));
|
||||
result.setHyperparameters(hyperparameters);
|
||||
// Initialize results vectors
|
||||
// Initialize results std::vectors
|
||||
int nResults = nfolds * static_cast<int>(randomSeeds.size());
|
||||
auto accuracy_test = torch::zeros({ nResults }, torch::kFloat64);
|
||||
auto accuracy_train = torch::zeros({ nResults }, torch::kFloat64);
|
||||
@@ -162,7 +162,7 @@ namespace platform {
|
||||
int item = 0;
|
||||
for (auto seed : randomSeeds) {
|
||||
if (!quiet)
|
||||
cout << "(" << seed << ") doing Fold: " << flush;
|
||||
std::cout << "(" << seed << ") doing Fold: " << flush;
|
||||
Fold* fold;
|
||||
if (stratified)
|
||||
fold = new StratifiedKFold(nfolds, y, seed);
|
||||
@@ -204,8 +204,8 @@ namespace platform {
|
||||
accuracy_train[item] = accuracy_train_value;
|
||||
accuracy_test[item] = accuracy_test_value;
|
||||
if (!quiet)
|
||||
cout << "\b\b\b, " << flush;
|
||||
// Store results and times in vector
|
||||
std::cout << "\b\b\b, " << flush;
|
||||
// Store results and times in std::vector
|
||||
result.addScoreTrain(accuracy_train_value);
|
||||
result.addScoreTest(accuracy_test_value);
|
||||
result.addTimeTrain(train_time[item].item<double>());
|
||||
@@ -214,7 +214,7 @@ namespace platform {
|
||||
clf.reset();
|
||||
}
|
||||
if (!quiet)
|
||||
cout << "end. " << flush;
|
||||
std::cout << "end. " << flush;
|
||||
delete fold;
|
||||
}
|
||||
result.setScoreTest(torch::mean(accuracy_test).item<double>()).setScoreTrain(torch::mean(accuracy_train).item<double>());
|
||||
|
@@ -10,34 +10,33 @@
|
||||
#include "KDB.h"
|
||||
#include "AODE.h"
|
||||
|
||||
using namespace std;
|
||||
namespace platform {
|
||||
using json = nlohmann::json;
|
||||
class Timer {
|
||||
private:
|
||||
chrono::high_resolution_clock::time_point begin;
|
||||
std::chrono::high_resolution_clock::time_point begin;
|
||||
public:
|
||||
Timer() = default;
|
||||
~Timer() = default;
|
||||
void start() { begin = chrono::high_resolution_clock::now(); }
|
||||
void start() { begin = std::chrono::high_resolution_clock::now(); }
|
||||
double getDuration()
|
||||
{
|
||||
chrono::high_resolution_clock::time_point end = chrono::high_resolution_clock::now();
|
||||
chrono::duration<double> time_span = chrono::duration_cast<chrono::duration<double>>(end - begin);
|
||||
std::chrono::high_resolution_clock::time_point end = std::chrono::high_resolution_clock::now();
|
||||
std::chrono::duration<double> time_span = std::chrono::duration_cast<std::chrono::duration<double >> (end - begin);
|
||||
return time_span.count();
|
||||
}
|
||||
};
|
||||
class Result {
|
||||
private:
|
||||
string dataset, model_version;
|
||||
std::string dataset, model_version;
|
||||
json hyperparameters;
|
||||
int samples{ 0 }, features{ 0 }, classes{ 0 };
|
||||
double score_train{ 0 }, score_test{ 0 }, score_train_std{ 0 }, score_test_std{ 0 }, train_time{ 0 }, train_time_std{ 0 }, test_time{ 0 }, test_time_std{ 0 };
|
||||
float nodes{ 0 }, leaves{ 0 }, depth{ 0 };
|
||||
vector<double> scores_train, scores_test, times_train, times_test;
|
||||
std::vector<double> scores_train, scores_test, times_train, times_test;
|
||||
public:
|
||||
Result() = default;
|
||||
Result& setDataset(const string& dataset) { this->dataset = dataset; return *this; }
|
||||
Result& setDataset(const std::string& dataset) { this->dataset = dataset; return *this; }
|
||||
Result& setHyperparameters(const json& hyperparameters) { this->hyperparameters = hyperparameters; return *this; }
|
||||
Result& setSamples(int samples) { this->samples = samples; return *this; }
|
||||
Result& setFeatures(int features) { this->features = features; return *this; }
|
||||
@@ -59,7 +58,7 @@ namespace platform {
|
||||
Result& addTimeTest(double time) { times_test.push_back(time); return *this; }
|
||||
const float get_score_train() const { return score_train; }
|
||||
float get_score_test() { return score_test; }
|
||||
const string& getDataset() const { return dataset; }
|
||||
const std::string& getDataset() const { return dataset; }
|
||||
const json& getHyperparameters() const { return hyperparameters; }
|
||||
const int getSamples() const { return samples; }
|
||||
const int getFeatures() const { return features; }
|
||||
@@ -75,30 +74,30 @@ namespace platform {
|
||||
const float getNodes() const { return nodes; }
|
||||
const float getLeaves() const { return leaves; }
|
||||
const float getDepth() const { return depth; }
|
||||
const vector<double>& getScoresTrain() const { return scores_train; }
|
||||
const vector<double>& getScoresTest() const { return scores_test; }
|
||||
const vector<double>& getTimesTrain() const { return times_train; }
|
||||
const vector<double>& getTimesTest() const { return times_test; }
|
||||
const std::vector<double>& getScoresTrain() const { return scores_train; }
|
||||
const std::vector<double>& getScoresTest() const { return scores_test; }
|
||||
const std::vector<double>& getTimesTrain() const { return times_train; }
|
||||
const std::vector<double>& getTimesTest() const { return times_test; }
|
||||
};
|
||||
class Experiment {
|
||||
private:
|
||||
string title, model, platform, score_name, model_version, language_version, language;
|
||||
std::string title, model, platform, score_name, model_version, language_version, language;
|
||||
bool discretized{ false }, stratified{ false };
|
||||
vector<Result> results;
|
||||
vector<int> randomSeeds;
|
||||
std::vector<Result> results;
|
||||
std::vector<int> randomSeeds;
|
||||
json hyperparameters = "{}";
|
||||
int nfolds{ 0 };
|
||||
float duration{ 0 };
|
||||
json build_json();
|
||||
public:
|
||||
Experiment();
|
||||
Experiment& setTitle(const string& title) { this->title = title; return *this; }
|
||||
Experiment& setModel(const string& model) { this->model = model; return *this; }
|
||||
Experiment& setPlatform(const string& platform) { this->platform = platform; return *this; }
|
||||
Experiment& setScoreName(const string& score_name) { this->score_name = score_name; return *this; }
|
||||
Experiment& setModelVersion(const string& model_version) { this->model_version = model_version; return *this; }
|
||||
Experiment& setLanguage(const string& language) { this->language = language; return *this; }
|
||||
Experiment& setLanguageVersion(const string& language_version) { this->language_version = language_version; return *this; }
|
||||
Experiment& setTitle(const std::string& title) { this->title = title; return *this; }
|
||||
Experiment& setModel(const std::string& model) { this->model = model; return *this; }
|
||||
Experiment& setPlatform(const std::string& platform) { this->platform = platform; return *this; }
|
||||
Experiment& setScoreName(const std::string& score_name) { this->score_name = score_name; return *this; }
|
||||
Experiment& setModelVersion(const std::string& model_version) { this->model_version = model_version; return *this; }
|
||||
Experiment& setLanguage(const std::string& language) { this->language = language; return *this; }
|
||||
Experiment& setLanguageVersion(const std::string& language_version) { this->language_version = language_version; return *this; }
|
||||
Experiment& setDiscretized(bool discretized) { this->discretized = discretized; return *this; }
|
||||
Experiment& setStratified(bool stratified) { this->stratified = stratified; return *this; }
|
||||
Experiment& setNFolds(int nfolds) { this->nfolds = nfolds; return *this; }
|
||||
@@ -106,10 +105,10 @@ namespace platform {
|
||||
Experiment& addRandomSeed(int randomSeed) { randomSeeds.push_back(randomSeed); return *this; }
|
||||
Experiment& setDuration(float duration) { this->duration = duration; return *this; }
|
||||
Experiment& setHyperparameters(const json& hyperparameters) { this->hyperparameters = hyperparameters; return *this; }
|
||||
string get_file_name();
|
||||
void save(const string& path);
|
||||
void cross_validation(const string& fileName, bool quiet);
|
||||
void go(vector<string> filesToProcess, bool quiet);
|
||||
std::string get_file_name();
|
||||
void save(const std::string& path);
|
||||
void cross_validation(const std::string& fileName, bool quiet);
|
||||
void go(std::vector<std::string> filesToProcess, bool quiet);
|
||||
void show();
|
||||
void report();
|
||||
};
|
||||
|
@@ -4,23 +4,23 @@
|
||||
namespace platform {
|
||||
Fold::Fold(int k, int n, int seed) : k(k), n(n), seed(seed)
|
||||
{
|
||||
random_device rd;
|
||||
random_seed = default_random_engine(seed == -1 ? rd() : seed);
|
||||
srand(seed == -1 ? time(0) : seed);
|
||||
std::random_device rd;
|
||||
random_seed = std::default_random_engine(seed == -1 ? rd() : seed);
|
||||
std::srand(seed == -1 ? time(0) : seed);
|
||||
}
|
||||
KFold::KFold(int k, int n, int seed) : Fold(k, n, seed), indices(vector<int>(n))
|
||||
KFold::KFold(int k, int n, int seed) : Fold(k, n, seed), indices(std::vector<int>(n))
|
||||
{
|
||||
iota(begin(indices), end(indices), 0); // fill with 0, 1, ..., n - 1
|
||||
std::iota(begin(indices), end(indices), 0); // fill with 0, 1, ..., n - 1
|
||||
shuffle(indices.begin(), indices.end(), random_seed);
|
||||
}
|
||||
pair<vector<int>, vector<int>> KFold::getFold(int nFold)
|
||||
std::pair<std::vector<int>, std::vector<int>> KFold::getFold(int nFold)
|
||||
{
|
||||
if (nFold >= k || nFold < 0) {
|
||||
throw out_of_range("nFold (" + to_string(nFold) + ") must be less than k (" + to_string(k) + ")");
|
||||
throw std::out_of_range("nFold (" + std::to_string(nFold) + ") must be less than k (" + std::to_string(k) + ")");
|
||||
}
|
||||
int nTest = n / k;
|
||||
auto train = vector<int>();
|
||||
auto test = vector<int>();
|
||||
auto train = std::vector<int>();
|
||||
auto test = std::vector<int>();
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (i >= nTest * nFold && i < nTest * (nFold + 1)) {
|
||||
test.push_back(indices[i]);
|
||||
@@ -33,10 +33,10 @@ namespace platform {
|
||||
StratifiedKFold::StratifiedKFold(int k, torch::Tensor& y, int seed) : Fold(k, y.numel(), seed)
|
||||
{
|
||||
n = y.numel();
|
||||
this->y = vector<int>(y.data_ptr<int>(), y.data_ptr<int>() + n);
|
||||
this->y = std::vector<int>(y.data_ptr<int>(), y.data_ptr<int>() + n);
|
||||
build();
|
||||
}
|
||||
StratifiedKFold::StratifiedKFold(int k, const vector<int>& y, int seed)
|
||||
StratifiedKFold::StratifiedKFold(int k, const std::vector<int>& y, int seed)
|
||||
: Fold(k, y.size(), seed)
|
||||
{
|
||||
this->y = y;
|
||||
@@ -45,12 +45,12 @@ namespace platform {
|
||||
}
|
||||
void StratifiedKFold::build()
|
||||
{
|
||||
stratified_indices = vector<vector<int>>(k);
|
||||
stratified_indices = std::vector<std::vector<int>>(k);
|
||||
int fold_size = n / k;
|
||||
|
||||
// Compute class counts and indices
|
||||
auto class_indices = map<int, vector<int>>();
|
||||
vector<int> class_counts(*max_element(y.begin(), y.end()) + 1, 0);
|
||||
auto class_indices = std::map<int, std::vector<int>>();
|
||||
std::vector<int> class_counts(*max_element(y.begin(), y.end()) + 1, 0);
|
||||
for (auto i = 0; i < n; ++i) {
|
||||
class_counts[y[i]]++;
|
||||
class_indices[y[i]].push_back(i);
|
||||
@@ -63,8 +63,8 @@ namespace platform {
|
||||
for (auto label = 0; label < class_counts.size(); ++label) {
|
||||
auto num_samples_to_take = class_counts.at(label) / k;
|
||||
if (num_samples_to_take == 0) {
|
||||
cerr << "Warning! The number of samples in class " << label << " (" << class_counts.at(label)
|
||||
<< ") is less than the number of folds (" << k << ")." << endl;
|
||||
std::cerr << "Warning! The number of samples in class " << label << " (" << class_counts.at(label)
|
||||
<< ") is less than the number of folds (" << k << ")." << std::endl;
|
||||
faulty = true;
|
||||
continue;
|
||||
}
|
||||
@@ -74,7 +74,7 @@ namespace platform {
|
||||
move(class_indices[label].begin(), it, back_inserter(stratified_indices[fold])); // ##
|
||||
class_indices[label].erase(class_indices[label].begin(), it);
|
||||
}
|
||||
auto chosen = vector<bool>(k, false);
|
||||
auto chosen = std::vector<bool>(k, false);
|
||||
while (remainder_samples_to_take > 0) {
|
||||
int fold = (rand() % static_cast<int>(k));
|
||||
if (chosen.at(fold)) {
|
||||
@@ -88,13 +88,13 @@ namespace platform {
|
||||
}
|
||||
}
|
||||
}
|
||||
pair<vector<int>, vector<int>> StratifiedKFold::getFold(int nFold)
|
||||
std::pair<std::vector<int>, std::vector<int>> StratifiedKFold::getFold(int nFold)
|
||||
{
|
||||
if (nFold >= k || nFold < 0) {
|
||||
throw out_of_range("nFold (" + to_string(nFold) + ") must be less than k (" + to_string(k) + ")");
|
||||
throw std::out_of_range("nFold (" + std::to_string(nFold) + ") must be less than k (" + std::to_string(k) + ")");
|
||||
}
|
||||
vector<int> test_indices = stratified_indices[nFold];
|
||||
vector<int> train_indices;
|
||||
std::vector<int> test_indices = stratified_indices[nFold];
|
||||
std::vector<int> train_indices;
|
||||
for (int i = 0; i < k; ++i) {
|
||||
if (i == nFold) continue;
|
||||
train_indices.insert(train_indices.end(), stratified_indices[i].begin(), stratified_indices[i].end());
|
||||
|
@@ -3,37 +3,36 @@
|
||||
#include <torch/torch.h>
|
||||
#include <vector>
|
||||
#include <random>
|
||||
using namespace std;
|
||||
namespace platform {
|
||||
class Fold {
|
||||
protected:
|
||||
int k;
|
||||
int n;
|
||||
int seed;
|
||||
default_random_engine random_seed;
|
||||
std::default_random_engine random_seed;
|
||||
public:
|
||||
Fold(int k, int n, int seed = -1);
|
||||
virtual pair<vector<int>, vector<int>> getFold(int nFold) = 0;
|
||||
virtual std::pair<std::vector<int>, std::vector<int>> getFold(int nFold) = 0;
|
||||
virtual ~Fold() = default;
|
||||
int getNumberOfFolds() { return k; }
|
||||
};
|
||||
class KFold : public Fold {
|
||||
private:
|
||||
vector<int> indices;
|
||||
std::vector<int> indices;
|
||||
public:
|
||||
KFold(int k, int n, int seed = -1);
|
||||
pair<vector<int>, vector<int>> getFold(int nFold) override;
|
||||
std::pair<std::vector<int>, std::vector<int>> getFold(int nFold) override;
|
||||
};
|
||||
class StratifiedKFold : public Fold {
|
||||
private:
|
||||
vector<int> y;
|
||||
vector<vector<int>> stratified_indices;
|
||||
std::vector<int> y;
|
||||
std::vector<std::vector<int>> stratified_indices;
|
||||
void build();
|
||||
bool faulty = false; // Only true if the number of samples of any class is less than the number of folds.
|
||||
public:
|
||||
StratifiedKFold(int k, const vector<int>& y, int seed = -1);
|
||||
StratifiedKFold(int k, const std::vector<int>& y, int seed = -1);
|
||||
StratifiedKFold(int k, torch::Tensor& y, int seed = -1);
|
||||
pair<vector<int>, vector<int>> getFold(int nFold) override;
|
||||
std::pair<std::vector<int>, std::vector<int>> getFold(int nFold) override;
|
||||
bool isFaulty() { return faulty; }
|
||||
};
|
||||
}
|
||||
|
@@ -10,7 +10,7 @@
|
||||
|
||||
namespace platform {
|
||||
|
||||
ManageResults::ManageResults(int numFiles, const string& model, const string& score, bool complete, bool partial, bool compare) :
|
||||
ManageResults::ManageResults(int numFiles, const std::string& model, const std::string& score, bool complete, bool partial, bool compare) :
|
||||
numFiles{ numFiles }, complete{ complete }, partial{ partial }, compare{ compare }, results(Results(Paths::results(), model, score, complete, partial))
|
||||
{
|
||||
indexList = true;
|
||||
@@ -23,7 +23,7 @@ namespace platform {
|
||||
void ManageResults::doMenu()
|
||||
{
|
||||
if (results.empty()) {
|
||||
cout << Colors::MAGENTA() << "No results found!" << Colors::RESET() << endl;
|
||||
std::cout << Colors::MAGENTA() << "No results found!" << Colors::RESET() << std::endl;
|
||||
return;
|
||||
}
|
||||
results.sortDate();
|
||||
@@ -32,68 +32,68 @@ namespace platform {
|
||||
if (openExcel) {
|
||||
workbook_close(workbook);
|
||||
}
|
||||
cout << Colors::RESET() << "Done!" << endl;
|
||||
std::cout << Colors::RESET() << "Done!" << std::endl;
|
||||
}
|
||||
void ManageResults::list()
|
||||
{
|
||||
auto temp = ConfigLocale();
|
||||
string suffix = numFiles != results.size() ? " of " + to_string(results.size()) : "";
|
||||
stringstream oss;
|
||||
std::string suffix = numFiles != results.size() ? " of " + std::to_string(results.size()) : "";
|
||||
std::stringstream oss;
|
||||
oss << "Results on screen: " << numFiles << suffix;
|
||||
cout << Colors::GREEN() << oss.str() << endl;
|
||||
cout << string(oss.str().size(), '-') << endl;
|
||||
std::cout << Colors::GREEN() << oss.str() << std::endl;
|
||||
std::cout << std::string(oss.str().size(), '-') << std::endl;
|
||||
if (complete) {
|
||||
cout << Colors::MAGENTA() << "Only listing complete results" << endl;
|
||||
std::cout << Colors::MAGENTA() << "Only listing complete results" << std::endl;
|
||||
}
|
||||
if (partial) {
|
||||
cout << Colors::MAGENTA() << "Only listing partial results" << endl;
|
||||
std::cout << Colors::MAGENTA() << "Only listing partial results" << std::endl;
|
||||
}
|
||||
auto i = 0;
|
||||
int maxModel = results.maxModelSize();
|
||||
cout << Colors::GREEN() << " # Date " << setw(maxModel) << left << "Model" << " Score Name Score C/P Duration Title" << endl;
|
||||
cout << "=== ========== " << string(maxModel, '=') << " =========== =========== === ========= =============================================================" << endl;
|
||||
std::cout << Colors::GREEN() << " # Date " << std::setw(maxModel) << std::left << "Model" << " Score Name Score C/P Duration Title" << std::endl;
|
||||
std::cout << "=== ========== " << std::string(maxModel, '=') << " =========== =========== === ========= =============================================================" << std::endl;
|
||||
bool odd = true;
|
||||
for (auto& result : results) {
|
||||
auto color = odd ? Colors::BLUE() : Colors::CYAN();
|
||||
cout << color << setw(3) << fixed << right << i++ << " ";
|
||||
cout << result.to_string(maxModel) << endl;
|
||||
std::cout << color << std::setw(3) << std::fixed << std::right << i++ << " ";
|
||||
std::cout << result.to_string(maxModel) << std::endl;
|
||||
if (i == numFiles) {
|
||||
break;
|
||||
}
|
||||
odd = !odd;
|
||||
}
|
||||
}
|
||||
bool ManageResults::confirmAction(const string& intent, const string& fileName) const
|
||||
bool ManageResults::confirmAction(const std::string& intent, const std::string& fileName) const
|
||||
{
|
||||
string color;
|
||||
std::string color;
|
||||
if (intent == "delete") {
|
||||
color = Colors::RED();
|
||||
} else {
|
||||
color = Colors::YELLOW();
|
||||
}
|
||||
string line;
|
||||
std::string line;
|
||||
bool finished = false;
|
||||
while (!finished) {
|
||||
cout << color << "Really want to " << intent << " " << fileName << "? (y/n): ";
|
||||
getline(cin, line);
|
||||
std::cout << color << "Really want to " << intent << " " << fileName << "? (y/n): ";
|
||||
getline(std::cin, line);
|
||||
finished = line.size() == 1 && (tolower(line[0]) == 'y' || tolower(line[0] == 'n'));
|
||||
}
|
||||
if (tolower(line[0]) == 'y') {
|
||||
return true;
|
||||
}
|
||||
cout << "Not done!" << endl;
|
||||
std::cout << "Not done!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
void ManageResults::report(const int index, const bool excelReport)
|
||||
{
|
||||
cout << Colors::YELLOW() << "Reporting " << results.at(index).getFilename() << endl;
|
||||
std::cout << Colors::YELLOW() << "Reporting " << results.at(index).getFilename() << std::endl;
|
||||
auto data = results.at(index).load();
|
||||
if (excelReport) {
|
||||
ReportExcel reporter(data, compare, workbook);
|
||||
reporter.show();
|
||||
openExcel = true;
|
||||
workbook = reporter.getWorkbook();
|
||||
cout << "Adding sheet to " << Paths::excel() + Paths::excelResults() << endl;
|
||||
std::cout << "Adding sheet to " << Paths::excel() + Paths::excelResults() << std::endl;
|
||||
} else {
|
||||
ReportConsole reporter(data, compare);
|
||||
reporter.show();
|
||||
@@ -103,20 +103,20 @@ namespace platform {
|
||||
{
|
||||
// Show a dataset result inside a report
|
||||
auto data = results.at(index).load();
|
||||
cout << Colors::YELLOW() << "Showing " << results.at(index).getFilename() << endl;
|
||||
std::cout << Colors::YELLOW() << "Showing " << results.at(index).getFilename() << std::endl;
|
||||
ReportConsole reporter(data, compare, idx);
|
||||
reporter.show();
|
||||
}
|
||||
void ManageResults::sortList()
|
||||
{
|
||||
cout << Colors::YELLOW() << "Choose sorting field (date='d', score='s', duration='u', model='m'): ";
|
||||
string line;
|
||||
std::cout << Colors::YELLOW() << "Choose sorting field (date='d', score='s', duration='u', model='m'): ";
|
||||
std::string line;
|
||||
char option;
|
||||
getline(cin, line);
|
||||
getline(std::cin, line);
|
||||
if (line.size() == 0)
|
||||
return;
|
||||
if (line.size() > 1) {
|
||||
cout << "Invalid option" << endl;
|
||||
std::cout << "Invalid option" << std::endl;
|
||||
return;
|
||||
}
|
||||
option = line[0];
|
||||
@@ -134,7 +134,7 @@ namespace platform {
|
||||
results.sortModel();
|
||||
break;
|
||||
default:
|
||||
cout << "Invalid option" << endl;
|
||||
std::cout << "Invalid option" << std::endl;
|
||||
}
|
||||
}
|
||||
void ManageResults::menu()
|
||||
@@ -142,9 +142,9 @@ namespace platform {
|
||||
char option;
|
||||
int index, subIndex;
|
||||
bool finished = false;
|
||||
string filename;
|
||||
std::string filename;
|
||||
// tuple<Option, digit, requires value>
|
||||
vector<tuple<string, char, bool>> mainOptions = {
|
||||
std::vector<std::tuple<std::string, char, bool>> mainOptions = {
|
||||
{"quit", 'q', false},
|
||||
{"list", 'l', false},
|
||||
{"delete", 'd', true},
|
||||
@@ -153,7 +153,7 @@ namespace platform {
|
||||
{"report", 'r', true},
|
||||
{"excel", 'e', true}
|
||||
};
|
||||
vector<tuple<string, char, bool>> listOptions = {
|
||||
std::vector<std::tuple<std::string, char, bool>> listOptions = {
|
||||
{"report", 'r', true},
|
||||
{"list", 'l', false},
|
||||
{"quit", 'q', false}
|
||||
@@ -161,9 +161,9 @@ namespace platform {
|
||||
auto parser = CommandParser();
|
||||
while (!finished) {
|
||||
if (indexList) {
|
||||
tie(option, index) = parser.parse(Colors::GREEN(), mainOptions, 'r', numFiles - 1);
|
||||
std::tie(option, index) = parser.parse(Colors::GREEN(), mainOptions, 'r', numFiles - 1);
|
||||
} else {
|
||||
tie(option, subIndex) = parser.parse(Colors::MAGENTA(), listOptions, 'r', results.at(index).load()["results"].size() - 1);
|
||||
std::tie(option, subIndex) = parser.parse(Colors::MAGENTA(), listOptions, 'r', results.at(index).load()["results"].size() - 1);
|
||||
}
|
||||
switch (option) {
|
||||
case 'q':
|
||||
@@ -177,9 +177,9 @@ namespace platform {
|
||||
filename = results.at(index).getFilename();
|
||||
if (!confirmAction("delete", filename))
|
||||
break;
|
||||
cout << "Deleting " << filename << endl;
|
||||
std::cout << "Deleting " << filename << std::endl;
|
||||
results.deleteResult(index);
|
||||
cout << "File: " + filename + " deleted!" << endl;
|
||||
std::cout << "File: " + filename + " deleted!" << std::endl;
|
||||
list();
|
||||
break;
|
||||
case 'h':
|
||||
@@ -187,9 +187,9 @@ namespace platform {
|
||||
if (!confirmAction("hide", filename))
|
||||
break;
|
||||
filename = results.at(index).getFilename();
|
||||
cout << "Hiding " << filename << endl;
|
||||
std::cout << "Hiding " << filename << std::endl;
|
||||
results.hideResult(index, Paths::hiddenResults());
|
||||
cout << "File: " + filename + " hidden! (moved to " << Paths::hiddenResults() << ")" << endl;
|
||||
std::cout << "File: " + filename + " hidden! (moved to " << Paths::hiddenResults() << ")" << std::endl;
|
||||
list();
|
||||
break;
|
||||
case 's':
|
||||
|
@@ -6,12 +6,12 @@
|
||||
namespace platform {
|
||||
class ManageResults {
|
||||
public:
|
||||
ManageResults(int numFiles, const string& model, const string& score, bool complete, bool partial, bool compare);
|
||||
ManageResults(int numFiles, const std::string& model, const std::string& score, bool complete, bool partial, bool compare);
|
||||
~ManageResults() = default;
|
||||
void doMenu();
|
||||
private:
|
||||
void list();
|
||||
bool confirmAction(const string& intent, const string& fileName) const;
|
||||
bool confirmAction(const std::string& intent, const std::string& fileName) const;
|
||||
void report(const int index, const bool excelReport);
|
||||
void showIndex(const int index, const int idx);
|
||||
void sortList();
|
||||
|
@@ -1,6 +1,5 @@
|
||||
#include "Models.h"
|
||||
namespace platform {
|
||||
using namespace std;
|
||||
// Idea from: https://www.codeproject.com/Articles/567242/AplusC-2b-2bplusObjectplusFactory
|
||||
Models* Models::factory = nullptr;;
|
||||
Models* Models::instance()
|
||||
@@ -10,13 +9,13 @@ namespace platform {
|
||||
factory = new Models();
|
||||
return factory;
|
||||
}
|
||||
void Models::registerFactoryFunction(const string& name,
|
||||
void Models::registerFactoryFunction(const std::string& name,
|
||||
function<bayesnet::BaseClassifier* (void)> classFactoryFunction)
|
||||
{
|
||||
// register the class factory function
|
||||
functionRegistry[name] = classFactoryFunction;
|
||||
}
|
||||
shared_ptr<bayesnet::BaseClassifier> Models::create(const string& name)
|
||||
shared_ptr<bayesnet::BaseClassifier> Models::create(const std::string& name)
|
||||
{
|
||||
bayesnet::BaseClassifier* instance = nullptr;
|
||||
|
||||
@@ -30,23 +29,22 @@ namespace platform {
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
vector<string> Models::getNames()
|
||||
std::vector<std::string> Models::getNames()
|
||||
{
|
||||
vector<string> names;
|
||||
std::vector<std::string> names;
|
||||
transform(functionRegistry.begin(), functionRegistry.end(), back_inserter(names),
|
||||
[](const pair<string, function<bayesnet::BaseClassifier* (void)>>& pair) { return pair.first; });
|
||||
[](const pair<std::string, function<bayesnet::BaseClassifier* (void)>>& pair) { return pair.first; });
|
||||
return names;
|
||||
}
|
||||
string Models::toString()
|
||||
std::string Models::tostring()
|
||||
{
|
||||
string result = "";
|
||||
std::string result = "";
|
||||
for (const auto& pair : functionRegistry) {
|
||||
result += pair.first + ", ";
|
||||
}
|
||||
return "{" + result.substr(0, result.size() - 2) + "}";
|
||||
}
|
||||
|
||||
Registrar::Registrar(const string& name, function<bayesnet::BaseClassifier* (void)> classFactoryFunction)
|
||||
Registrar::Registrar(const std::string& name, function<bayesnet::BaseClassifier* (void)> classFactoryFunction)
|
||||
{
|
||||
// register the class factory function
|
||||
Models::instance()->registerFactoryFunction(name, classFactoryFunction);
|
||||
|
@@ -14,7 +14,7 @@
|
||||
namespace platform {
|
||||
class Models {
|
||||
private:
|
||||
map<string, function<bayesnet::BaseClassifier* (void)>> functionRegistry;
|
||||
map<std::string, function<bayesnet::BaseClassifier* (void)>> functionRegistry;
|
||||
static Models* factory; //singleton
|
||||
Models() {};
|
||||
public:
|
||||
@@ -22,16 +22,16 @@ namespace platform {
|
||||
void operator=(const Models&) = delete;
|
||||
// Idea from: https://www.codeproject.com/Articles/567242/AplusC-2b-2bplusObjectplusFactory
|
||||
static Models* instance();
|
||||
shared_ptr<bayesnet::BaseClassifier> create(const string& name);
|
||||
void registerFactoryFunction(const string& name,
|
||||
shared_ptr<bayesnet::BaseClassifier> create(const std::string& name);
|
||||
void registerFactoryFunction(const std::string& name,
|
||||
function<bayesnet::BaseClassifier* (void)> classFactoryFunction);
|
||||
vector<string> getNames();
|
||||
string toString();
|
||||
std::vector<string> getNames();
|
||||
std::string tostring();
|
||||
|
||||
};
|
||||
class Registrar {
|
||||
public:
|
||||
Registrar(const string& className, function<bayesnet::BaseClassifier* (void)> classFactoryFunction);
|
||||
Registrar(const std::string& className, function<bayesnet::BaseClassifier* (void)> classFactoryFunction);
|
||||
};
|
||||
}
|
||||
#endif
|
@@ -7,8 +7,8 @@
|
||||
namespace platform {
|
||||
ReportBase::ReportBase(json data_, bool compare) : data(data_), compare(compare), margin(0.1)
|
||||
{
|
||||
stringstream oss;
|
||||
oss << "Better than ZeroR + " << setprecision(1) << fixed << margin * 100 << "%";
|
||||
std::stringstream oss;
|
||||
oss << "Better than ZeroR + " << std::setprecision(1) << fixed << margin * 100 << "%";
|
||||
meaning = {
|
||||
{Symbols::equal_best, "Equal to best"},
|
||||
{Symbols::better_best, "Better than best"},
|
||||
@@ -16,10 +16,10 @@ namespace platform {
|
||||
{Symbols::upward_arrow, oss.str()}
|
||||
};
|
||||
}
|
||||
string ReportBase::fromVector(const string& key)
|
||||
std::string ReportBase::fromVector(const std::string& key)
|
||||
{
|
||||
stringstream oss;
|
||||
string sep = "";
|
||||
std::stringstream oss;
|
||||
std::string sep = "";
|
||||
oss << "[";
|
||||
for (auto& item : data[key]) {
|
||||
oss << sep << item.get<double>();
|
||||
@@ -28,13 +28,13 @@ namespace platform {
|
||||
oss << "]";
|
||||
return oss.str();
|
||||
}
|
||||
string ReportBase::fVector(const string& title, const json& data, const int width, const int precision)
|
||||
std::string ReportBase::fVector(const std::string& title, const json& data, const int width, const int precision)
|
||||
{
|
||||
stringstream oss;
|
||||
string sep = "";
|
||||
std::stringstream oss;
|
||||
std::string sep = "";
|
||||
oss << title << "[";
|
||||
for (const auto& item : data) {
|
||||
oss << sep << fixed << setw(width) << setprecision(precision) << item.get<double>();
|
||||
oss << sep << fixed << setw(width) << std::setprecision(precision) << item.get<double>();
|
||||
sep = ", ";
|
||||
}
|
||||
oss << "]";
|
||||
@@ -45,25 +45,25 @@ namespace platform {
|
||||
header();
|
||||
body();
|
||||
}
|
||||
string ReportBase::compareResult(const string& dataset, double result)
|
||||
std::string ReportBase::compareResult(const std::string& dataset, double result)
|
||||
{
|
||||
string status = " ";
|
||||
std::string status = " ";
|
||||
if (compare) {
|
||||
double best = bestResult(dataset, data["model"].get<string>());
|
||||
double best = bestResult(dataset, data["model"].get<std::string>());
|
||||
if (result == best) {
|
||||
status = Symbols::equal_best;
|
||||
} else if (result > best) {
|
||||
status = Symbols::better_best;
|
||||
}
|
||||
} else {
|
||||
if (data["score_name"].get<string>() == "accuracy") {
|
||||
if (data["score_name"].get<std::string>() == "accuracy") {
|
||||
auto dt = Datasets(false, Paths::datasets());
|
||||
dt.loadDataset(dataset);
|
||||
auto numClasses = dt.getNClasses(dataset);
|
||||
if (numClasses == 2) {
|
||||
vector<int> distribution = dt.getClassesCounts(dataset);
|
||||
std::vector<int> distribution = dt.getClassesCounts(dataset);
|
||||
double nSamples = dt.getNSamples(dataset);
|
||||
vector<int>::iterator maxValue = max_element(distribution.begin(), distribution.end());
|
||||
std::vector<int>::iterator maxValue = max_element(distribution.begin(), distribution.end());
|
||||
double mark = *maxValue / nSamples * (1 + margin);
|
||||
if (mark > 1) {
|
||||
mark = 0.9995;
|
||||
@@ -82,14 +82,14 @@ namespace platform {
|
||||
}
|
||||
return status;
|
||||
}
|
||||
double ReportBase::bestResult(const string& dataset, const string& model)
|
||||
double ReportBase::bestResult(const std::string& dataset, const std::string& model)
|
||||
{
|
||||
double value = 0.0;
|
||||
if (bestResults.size() == 0) {
|
||||
// try to load the best results
|
||||
string score = data["score_name"];
|
||||
std::string score = data["score_name"];
|
||||
replace(score.begin(), score.end(), '_', '-');
|
||||
string fileName = "best_results_" + score + "_" + model + ".json";
|
||||
std::string fileName = "best_results_" + score + "_" + model + ".json";
|
||||
ifstream resultData(Paths::results() + "/" + fileName);
|
||||
if (resultData.is_open()) {
|
||||
bestResults = json::parse(resultData);
|
||||
|
@@ -8,7 +8,6 @@
|
||||
|
||||
using json = nlohmann::json;
|
||||
namespace platform {
|
||||
using namespace std;
|
||||
|
||||
class ReportBase {
|
||||
public:
|
||||
@@ -17,19 +16,19 @@ namespace platform {
|
||||
void show();
|
||||
protected:
|
||||
json data;
|
||||
string fromVector(const string& key);
|
||||
string fVector(const string& title, const json& data, const int width, const int precision);
|
||||
std::string fromVector(const std::string& key);
|
||||
std::string fVector(const std::string& title, const json& data, const int width, const int precision);
|
||||
bool getExistBestFile();
|
||||
virtual void header() = 0;
|
||||
virtual void body() = 0;
|
||||
virtual void showSummary() = 0;
|
||||
string compareResult(const string& dataset, double result);
|
||||
map<string, int> summary;
|
||||
std::string compareResult(const std::string& dataset, double result);
|
||||
std::map<std::string, int> summary;
|
||||
double margin;
|
||||
map<string, string> meaning;
|
||||
std::map<std::string, std::string> meaning;
|
||||
bool compare;
|
||||
private:
|
||||
double bestResult(const string& dataset, const string& model);
|
||||
double bestResult(const std::string& dataset, const std::string& model);
|
||||
json bestResults;
|
||||
bool existBestFile = true;
|
||||
};
|
||||
|
@@ -6,25 +6,30 @@
|
||||
#include "CLocale.h"
|
||||
|
||||
namespace platform {
|
||||
string ReportConsole::headerLine(const string& text, int utf = 0)
|
||||
std::string ReportConsole::headerLine(const std::string& text, int utf = 0)
|
||||
{
|
||||
int n = MAXL - text.length() - 3;
|
||||
n = n < 0 ? 0 : n;
|
||||
return "* " + text + string(n + utf, ' ') + "*\n";
|
||||
return "* " + text + std::string(n + utf, ' ') + "*\n";
|
||||
}
|
||||
|
||||
void ReportConsole::header()
|
||||
{
|
||||
stringstream oss;
|
||||
cout << Colors::MAGENTA() << string(MAXL, '*') << endl;
|
||||
cout << headerLine("Report " + data["model"].get<string>() + " ver. " + data["version"].get<string>() + " with " + to_string(data["folds"].get<int>()) + " Folds cross validation and " + to_string(data["seeds"].size()) + " random seeds. " + data["date"].get<string>() + " " + data["time"].get<string>());
|
||||
cout << headerLine(data["title"].get<string>());
|
||||
cout << headerLine("Random seeds: " + fromVector("seeds") + " Stratified: " + (data["stratified"].get<bool>() ? "True" : "False"));
|
||||
oss << "Execution took " << setprecision(2) << fixed << data["duration"].get<float>() << " seconds, " << data["duration"].get<float>() / 3600 << " hours, on " << data["platform"].get<string>();
|
||||
cout << headerLine(oss.str());
|
||||
cout << headerLine("Score is " + data["score_name"].get<string>());
|
||||
cout << string(MAXL, '*') << endl;
|
||||
cout << endl;
|
||||
std::stringstream oss;
|
||||
std::cout << Colors::MAGENTA() << std::string(MAXL, '*') << std::endl;
|
||||
std::cout << headerLine(
|
||||
"Report " + data["model"].get<std::string>() + " ver. " + data["version"].get<std::string>()
|
||||
+ " with " + std::to_string(data["folds"].get<int>()) + " Folds cross validation and " + std::to_string(data["seeds"].size())
|
||||
+ " random seeds. " + data["date"].get<std::string>() + " " + data["time"].get<std::string>()
|
||||
);
|
||||
std::cout << headerLine(data["title"].get<std::string>());
|
||||
std::cout << headerLine("Random seeds: " + fromVector("seeds") + " Stratified: " + (data["stratified"].get<bool>() ? "True" : "False"));
|
||||
oss << "Execution took " << std::setprecision(2) << std::fixed << data["duration"].get<float>()
|
||||
<< " seconds, " << data["duration"].get<float>() / 3600 << " hours, on " << data["platform"].get<std::string>();
|
||||
std::cout << headerLine(oss.str());
|
||||
std::cout << headerLine("Score is " + data["score_name"].get<std::string>());
|
||||
std::cout << std::string(MAXL, '*') << std::endl;
|
||||
std::cout << std::endl;
|
||||
}
|
||||
void ReportConsole::body()
|
||||
{
|
||||
@@ -32,12 +37,12 @@ namespace platform {
|
||||
int maxHyper = 15;
|
||||
int maxDataset = 7;
|
||||
for (const auto& r : data["results"]) {
|
||||
maxHyper = max(maxHyper, (int)r["hyperparameters"].dump().size());
|
||||
maxDataset = max(maxDataset, (int)r["dataset"].get<string>().size());
|
||||
maxHyper = std::max(maxHyper, (int)r["hyperparameters"].dump().size());
|
||||
maxDataset = std::max(maxDataset, (int)r["dataset"].get<std::string>().size());
|
||||
|
||||
}
|
||||
cout << Colors::GREEN() << " # " << setw(maxDataset) << left << "Dataset" << " Sampl. Feat. Cls Nodes Edges States Score Time Hyperparameters" << endl;
|
||||
cout << "=== " << string(maxDataset, '=') << " ====== ===== === ========= ========= ========= =============== =================== " << string(maxHyper, '=') << endl;
|
||||
std::cout << Colors::GREEN() << " # " << std::setw(maxDataset) << std::left << "Dataset" << " Sampl. Feat. Cls Nodes Edges States Score Time Hyperparameters" << std::endl;
|
||||
std::cout << "=== " << std::string(maxDataset, '=') << " ====== ===== === ========= ========= ========= =============== =================== " << std::string(maxHyper, '=') << std::endl;
|
||||
json lastResult;
|
||||
double totalScore = 0.0;
|
||||
bool odd = true;
|
||||
@@ -48,33 +53,33 @@ namespace platform {
|
||||
continue;
|
||||
}
|
||||
auto color = odd ? Colors::CYAN() : Colors::BLUE();
|
||||
cout << color;
|
||||
cout << setw(3) << right << index++ << " ";
|
||||
cout << setw(maxDataset) << left << r["dataset"].get<string>() << " ";
|
||||
cout << setw(6) << right << r["samples"].get<int>() << " ";
|
||||
cout << setw(5) << right << r["features"].get<int>() << " ";
|
||||
cout << setw(3) << right << r["classes"].get<int>() << " ";
|
||||
cout << setw(9) << setprecision(2) << fixed << r["nodes"].get<float>() << " ";
|
||||
cout << setw(9) << setprecision(2) << fixed << r["leaves"].get<float>() << " ";
|
||||
cout << setw(9) << setprecision(2) << fixed << r["depth"].get<float>() << " ";
|
||||
cout << setw(8) << right << setprecision(6) << fixed << r["score"].get<double>() << "±" << setw(6) << setprecision(4) << fixed << r["score_std"].get<double>();
|
||||
const string status = compareResult(r["dataset"].get<string>(), r["score"].get<double>());
|
||||
cout << status;
|
||||
cout << setw(12) << right << setprecision(6) << fixed << r["time"].get<double>() << "±" << setw(6) << setprecision(4) << fixed << r["time_std"].get<double>() << " ";
|
||||
cout << r["hyperparameters"].dump();
|
||||
cout << endl;
|
||||
cout << flush;
|
||||
std::cout << color;
|
||||
std::cout << std::setw(3) << std::right << index++ << " ";
|
||||
std::cout << std::setw(maxDataset) << std::left << r["dataset"].get<std::string>() << " ";
|
||||
std::cout << std::setw(6) << std::right << r["samples"].get<int>() << " ";
|
||||
std::cout << std::setw(5) << std::right << r["features"].get<int>() << " ";
|
||||
std::cout << std::setw(3) << std::right << r["classes"].get<int>() << " ";
|
||||
std::cout << std::setw(9) << std::setprecision(2) << std::fixed << r["nodes"].get<float>() << " ";
|
||||
std::cout << std::setw(9) << std::setprecision(2) << std::fixed << r["leaves"].get<float>() << " ";
|
||||
std::cout << std::setw(9) << std::setprecision(2) << std::fixed << r["depth"].get<float>() << " ";
|
||||
std::cout << std::setw(8) << std::right << std::setprecision(6) << std::fixed << r["score"].get<double>() << "±" << std::setw(6) << std::setprecision(4) << std::fixed << r["score_std"].get<double>();
|
||||
const std::string status = compareResult(r["dataset"].get<std::string>(), r["score"].get<double>());
|
||||
std::cout << status;
|
||||
std::cout << std::setw(12) << std::right << std::setprecision(6) << std::fixed << r["time"].get<double>() << "±" << std::setw(6) << std::setprecision(4) << std::fixed << r["time_std"].get<double>() << " ";
|
||||
std::cout << r["hyperparameters"].dump();
|
||||
std::cout << std::endl;
|
||||
std::cout << std::flush;
|
||||
lastResult = r;
|
||||
totalScore += r["score"].get<double>();
|
||||
odd = !odd;
|
||||
}
|
||||
if (data["results"].size() == 1 || selectedIndex != -1) {
|
||||
cout << string(MAXL, '*') << endl;
|
||||
cout << headerLine(fVector("Train scores: ", lastResult["scores_train"], 14, 12));
|
||||
cout << headerLine(fVector("Test scores: ", lastResult["scores_test"], 14, 12));
|
||||
cout << headerLine(fVector("Train times: ", lastResult["times_train"], 10, 3));
|
||||
cout << headerLine(fVector("Test times: ", lastResult["times_test"], 10, 3));
|
||||
cout << string(MAXL, '*') << endl;
|
||||
std::cout << std::string(MAXL, '*') << std::endl;
|
||||
std::cout << headerLine(fVector("Train scores: ", lastResult["scores_train"], 14, 12));
|
||||
std::cout << headerLine(fVector("Test scores: ", lastResult["scores_test"], 14, 12));
|
||||
std::cout << headerLine(fVector("Train times: ", lastResult["times_train"], 10, 3));
|
||||
std::cout << headerLine(fVector("Test times: ", lastResult["times_test"], 10, 3));
|
||||
std::cout << std::string(MAXL, '*') << std::endl;
|
||||
} else {
|
||||
footer(totalScore);
|
||||
}
|
||||
@@ -82,28 +87,28 @@ namespace platform {
|
||||
void ReportConsole::showSummary()
|
||||
{
|
||||
for (const auto& item : summary) {
|
||||
stringstream oss;
|
||||
oss << setw(3) << left << item.first;
|
||||
oss << setw(3) << right << item.second << " ";
|
||||
oss << left << meaning.at(item.first);
|
||||
cout << headerLine(oss.str(), 2);
|
||||
std::stringstream oss;
|
||||
oss << std::setw(3) << std::left << item.first;
|
||||
oss << std::setw(3) << std::right << item.second << " ";
|
||||
oss << std::left << meaning.at(item.first);
|
||||
std::cout << headerLine(oss.str(), 2);
|
||||
}
|
||||
}
|
||||
|
||||
void ReportConsole::footer(double totalScore)
|
||||
{
|
||||
cout << Colors::MAGENTA() << string(MAXL, '*') << endl;
|
||||
std::cout << Colors::MAGENTA() << std::string(MAXL, '*') << std::endl;
|
||||
showSummary();
|
||||
auto score = data["score_name"].get<string>();
|
||||
auto score = data["score_name"].get<std::string>();
|
||||
auto best = BestScore::getScore(score);
|
||||
if (best.first != "") {
|
||||
stringstream oss;
|
||||
std::stringstream oss;
|
||||
oss << score << " compared to " << best.first << " .: " << totalScore / best.second;
|
||||
cout << headerLine(oss.str());
|
||||
std::cout << headerLine(oss.str());
|
||||
}
|
||||
if (!getExistBestFile() && compare) {
|
||||
cout << headerLine("*** Best Results File not found. Couldn't compare any result!");
|
||||
std::cout << headerLine("*** Best Results File not found. Couldn't compare any result!");
|
||||
}
|
||||
cout << string(MAXL, '*') << endl << Colors::RESET();
|
||||
std::cout << std::string(MAXL, '*') << std::endl << Colors::RESET();
|
||||
}
|
||||
}
|
@@ -5,7 +5,6 @@
|
||||
#include "Colors.h"
|
||||
|
||||
namespace platform {
|
||||
using namespace std;
|
||||
const int MAXL = 133;
|
||||
class ReportConsole : public ReportBase {
|
||||
public:
|
||||
@@ -13,7 +12,7 @@ namespace platform {
|
||||
virtual ~ReportConsole() = default;
|
||||
private:
|
||||
int selectedIndex;
|
||||
string headerLine(const string& text, int utf);
|
||||
std::string headerLine(const std::string& text, int utf);
|
||||
void header() override;
|
||||
void body() override;
|
||||
void footer(double totalScore);
|
||||
|
@@ -14,28 +14,28 @@ namespace platform {
|
||||
void ReportExcel::formatColumns()
|
||||
{
|
||||
worksheet_freeze_panes(worksheet, 6, 1);
|
||||
vector<int> columns_sizes = { 22, 10, 9, 7, 12, 12, 12, 12, 12, 3, 15, 12, 23 };
|
||||
std::vector<int> columns_sizes = { 22, 10, 9, 7, 12, 12, 12, 12, 12, 3, 15, 12, 23 };
|
||||
for (int i = 0; i < columns_sizes.size(); ++i) {
|
||||
worksheet_set_column(worksheet, i, i, columns_sizes.at(i), NULL);
|
||||
}
|
||||
}
|
||||
void ReportExcel::createWorksheet()
|
||||
{
|
||||
const string name = data["model"].get<string>();
|
||||
string suffix = "";
|
||||
string efectiveName;
|
||||
const std::string name = data["model"].get<std::string>();
|
||||
std::string suffix = "";
|
||||
std::string efectiveName;
|
||||
int num = 1;
|
||||
// Create a sheet with the name of the model
|
||||
while (true) {
|
||||
efectiveName = name + suffix;
|
||||
if (workbook_get_worksheet_by_name(workbook, efectiveName.c_str())) {
|
||||
suffix = to_string(++num);
|
||||
suffix = std::to_string(++num);
|
||||
} else {
|
||||
worksheet = workbook_add_worksheet(workbook, efectiveName.c_str());
|
||||
break;
|
||||
}
|
||||
if (num > 100) {
|
||||
throw invalid_argument("Couldn't create sheet " + efectiveName);
|
||||
throw std::invalid_argument("Couldn't create sheet " + efectiveName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -48,7 +48,7 @@ namespace platform {
|
||||
if (worksheet == NULL) {
|
||||
createWorksheet();
|
||||
}
|
||||
setProperties(data["title"].get<string>());
|
||||
setProperties(data["title"].get<std::string>());
|
||||
createFormats();
|
||||
formatColumns();
|
||||
}
|
||||
@@ -60,26 +60,26 @@ namespace platform {
|
||||
|
||||
void ReportExcel::header()
|
||||
{
|
||||
locale mylocale(cout.getloc(), new separated);
|
||||
locale::global(mylocale);
|
||||
cout.imbue(mylocale);
|
||||
stringstream oss;
|
||||
string message = data["model"].get<string>() + " ver. " + data["version"].get<string>() + " " +
|
||||
data["language"].get<string>() + " ver. " + data["language_version"].get<string>() +
|
||||
" with " + to_string(data["folds"].get<int>()) + " Folds cross validation and " + to_string(data["seeds"].size()) +
|
||||
" random seeds. " + data["date"].get<string>() + " " + data["time"].get<string>();
|
||||
std::locale mylocale(std::cout.getloc(), new separated);
|
||||
std::locale::global(mylocale);
|
||||
std::cout.imbue(mylocale);
|
||||
std::stringstream oss;
|
||||
std::string message = data["model"].get<std::string>() + " ver. " + data["version"].get<std::string>() + " " +
|
||||
data["language"].get<std::string>() + " ver. " + data["language_version"].get<std::string>() +
|
||||
" with " + std::to_string(data["folds"].get<int>()) + " Folds cross validation and " + std::to_string(data["seeds"].size()) +
|
||||
" random seeds. " + data["date"].get<std::string>() + " " + data["time"].get<std::string>();
|
||||
worksheet_merge_range(worksheet, 0, 0, 0, 12, message.c_str(), styles["headerFirst"]);
|
||||
worksheet_merge_range(worksheet, 1, 0, 1, 12, data["title"].get<string>().c_str(), styles["headerRest"]);
|
||||
worksheet_merge_range(worksheet, 2, 0, 3, 0, ("Score is " + data["score_name"].get<string>()).c_str(), styles["headerRest"]);
|
||||
worksheet_merge_range(worksheet, 1, 0, 1, 12, data["title"].get<std::string>().c_str(), styles["headerRest"]);
|
||||
worksheet_merge_range(worksheet, 2, 0, 3, 0, ("Score is " + data["score_name"].get<std::string>()).c_str(), styles["headerRest"]);
|
||||
worksheet_merge_range(worksheet, 2, 1, 3, 3, "Execution time", styles["headerRest"]);
|
||||
oss << setprecision(2) << fixed << data["duration"].get<float>() << " s";
|
||||
oss << std::setprecision(2) << std::fixed << data["duration"].get<float>() << " s";
|
||||
worksheet_merge_range(worksheet, 2, 4, 2, 5, oss.str().c_str(), styles["headerRest"]);
|
||||
oss.str("");
|
||||
oss.clear();
|
||||
oss << setprecision(2) << fixed << data["duration"].get<float>() / 3600 << " h";
|
||||
oss << std::setprecision(2) << std::fixed << data["duration"].get<float>() / 3600 << " h";
|
||||
worksheet_merge_range(worksheet, 3, 4, 3, 5, oss.str().c_str(), styles["headerRest"]);
|
||||
worksheet_merge_range(worksheet, 2, 6, 3, 7, "Platform", styles["headerRest"]);
|
||||
worksheet_merge_range(worksheet, 2, 8, 3, 9, data["platform"].get<string>().c_str(), styles["headerRest"]);
|
||||
worksheet_merge_range(worksheet, 2, 8, 3, 9, data["platform"].get<std::string>().c_str(), styles["headerRest"]);
|
||||
worksheet_merge_range(worksheet, 2, 10, 2, 12, ("Random seeds: " + fromVector("seeds")).c_str(), styles["headerSmall"]);
|
||||
oss.str("");
|
||||
oss.clear();
|
||||
@@ -93,7 +93,7 @@ namespace platform {
|
||||
|
||||
void ReportExcel::body()
|
||||
{
|
||||
auto head = vector<string>(
|
||||
auto head = std::vector<std::string>(
|
||||
{ "Dataset", "Samples", "Features", "Classes", "Nodes", "Edges", "States", "Score", "Score Std.", "St.", "Time",
|
||||
"Time Std.", "Hyperparameters" });
|
||||
int col = 0;
|
||||
@@ -105,9 +105,9 @@ namespace platform {
|
||||
int hypSize = 22;
|
||||
json lastResult;
|
||||
double totalScore = 0.0;
|
||||
string hyperparameters;
|
||||
std::string hyperparameters;
|
||||
for (const auto& r : data["results"]) {
|
||||
writeString(row, col, r["dataset"].get<string>(), "text");
|
||||
writeString(row, col, r["dataset"].get<std::string>(), "text");
|
||||
writeInt(row, col + 1, r["samples"].get<int>(), "ints");
|
||||
writeInt(row, col + 2, r["features"].get<int>(), "ints");
|
||||
writeInt(row, col + 3, r["classes"].get<int>(), "ints");
|
||||
@@ -116,7 +116,7 @@ namespace platform {
|
||||
writeDouble(row, col + 6, r["depth"].get<double>(), "floats");
|
||||
writeDouble(row, col + 7, r["score"].get<double>(), "result");
|
||||
writeDouble(row, col + 8, r["score_std"].get<double>(), "result");
|
||||
const string status = compareResult(r["dataset"].get<string>(), r["score"].get<double>());
|
||||
const std::string status = compareResult(r["dataset"].get<std::string>(), r["score"].get<double>());
|
||||
writeString(row, col + 9, status, "textCentered");
|
||||
writeDouble(row, col + 10, r["time"].get<double>(), "time");
|
||||
writeDouble(row, col + 11, r["time_std"].get<double>(), "time");
|
||||
@@ -133,12 +133,12 @@ namespace platform {
|
||||
worksheet_set_column(worksheet, 12, 12, hypSize + 5, NULL);
|
||||
// Show totals if only one dataset is present in the result
|
||||
if (data["results"].size() == 1) {
|
||||
for (const string& group : { "scores_train", "scores_test", "times_train", "times_test" }) {
|
||||
for (const std::string& group : { "scores_train", "scores_test", "times_train", "times_test" }) {
|
||||
row++;
|
||||
col = 1;
|
||||
writeString(row, col, group, "text");
|
||||
for (double item : lastResult[group]) {
|
||||
string style = group.find("scores") != string::npos ? "result" : "time";
|
||||
std::string style = group.find("scores") != std::string::npos ? "result" : "time";
|
||||
writeDouble(row, ++col, item, style);
|
||||
}
|
||||
}
|
||||
@@ -167,7 +167,7 @@ namespace platform {
|
||||
{
|
||||
showSummary();
|
||||
row += 4 + summary.size();
|
||||
auto score = data["score_name"].get<string>();
|
||||
auto score = data["score_name"].get<std::string>();
|
||||
auto best = BestScore::getScore(score);
|
||||
if (best.first != "") {
|
||||
worksheet_merge_range(worksheet, row, 1, row, 5, (score + " compared to " + best.first + " .:").c_str(), efectiveStyle("text"));
|
||||
|
@@ -6,7 +6,6 @@
|
||||
#include "ExcelFile.h"
|
||||
#include "Colors.h"
|
||||
namespace platform {
|
||||
using namespace std;
|
||||
class ReportExcel : public ReportBase, public ExcelFile {
|
||||
public:
|
||||
explicit ReportExcel(json data_, bool compare, lxw_workbook* workbook, lxw_worksheet* worksheet = NULL);
|
||||
|
@@ -8,7 +8,7 @@
|
||||
#include "CLocale.h"
|
||||
|
||||
namespace platform {
|
||||
Result::Result(const string& path, const string& filename)
|
||||
Result::Result(const std::string& path, const std::string& filename)
|
||||
: path(path)
|
||||
, filename(filename)
|
||||
{
|
||||
@@ -31,28 +31,28 @@ namespace platform {
|
||||
|
||||
json Result::load() const
|
||||
{
|
||||
ifstream resultData(path + "/" + filename);
|
||||
std::ifstream resultData(path + "/" + filename);
|
||||
if (resultData.is_open()) {
|
||||
json data = json::parse(resultData);
|
||||
return data;
|
||||
}
|
||||
throw invalid_argument("Unable to open result file. [" + path + "/" + filename + "]");
|
||||
throw std::invalid_argument("Unable to open result file. [" + path + "/" + filename + "]");
|
||||
}
|
||||
|
||||
string Result::to_string(int maxModel) const
|
||||
std::string Result::to_string(int maxModel) const
|
||||
{
|
||||
auto tmp = ConfigLocale();
|
||||
stringstream oss;
|
||||
std::stringstream oss;
|
||||
double durationShow = duration > 3600 ? duration / 3600 : duration > 60 ? duration / 60 : duration;
|
||||
string durationUnit = duration > 3600 ? "h" : duration > 60 ? "m" : "s";
|
||||
std::string durationUnit = duration > 3600 ? "h" : duration > 60 ? "m" : "s";
|
||||
oss << date << " ";
|
||||
oss << setw(maxModel) << left << model << " ";
|
||||
oss << setw(11) << left << scoreName << " ";
|
||||
oss << right << setw(11) << setprecision(7) << fixed << score << " ";
|
||||
oss << std::setw(maxModel) << std::left << model << " ";
|
||||
oss << std::setw(11) << std::left << scoreName << " ";
|
||||
oss << std::right << std::setw(11) << std::setprecision(7) << std::fixed << score << " ";
|
||||
auto completeString = isComplete() ? "C" : "P";
|
||||
oss << setw(1) << " " << completeString << " ";
|
||||
oss << setw(7) << setprecision(2) << fixed << durationShow << " " << durationUnit << " ";
|
||||
oss << setw(50) << left << title << " ";
|
||||
oss << std::setw(1) << " " << completeString << " ";
|
||||
oss << std::setw(7) << std::setprecision(2) << std::fixed << durationShow << " " << durationUnit << " ";
|
||||
oss << std::setw(50) << std::left << title << " ";
|
||||
return oss.str();
|
||||
}
|
||||
}
|
@@ -5,31 +5,30 @@
|
||||
#include <string>
|
||||
#include <nlohmann/json.hpp>
|
||||
namespace platform {
|
||||
using namespace std;
|
||||
using json = nlohmann::json;
|
||||
|
||||
class Result {
|
||||
public:
|
||||
Result(const string& path, const string& filename);
|
||||
Result(const std::string& path, const std::string& filename);
|
||||
json load() const;
|
||||
string to_string(int maxModel) const;
|
||||
string getFilename() const { return filename; };
|
||||
string getDate() const { return date; };
|
||||
std::string to_string(int maxModel) const;
|
||||
std::string getFilename() const { return filename; };
|
||||
std::string getDate() const { return date; };
|
||||
double getScore() const { return score; };
|
||||
string getTitle() const { return title; };
|
||||
std::string getTitle() const { return title; };
|
||||
double getDuration() const { return duration; };
|
||||
string getModel() const { return model; };
|
||||
string getScoreName() const { return scoreName; };
|
||||
std::string getModel() const { return model; };
|
||||
std::string getScoreName() const { return scoreName; };
|
||||
bool isComplete() const { return complete; };
|
||||
private:
|
||||
string path;
|
||||
string filename;
|
||||
string date;
|
||||
std::string path;
|
||||
std::string filename;
|
||||
std::string date;
|
||||
double score;
|
||||
string title;
|
||||
std::string title;
|
||||
double duration;
|
||||
string model;
|
||||
string scoreName;
|
||||
std::string model;
|
||||
std::string scoreName;
|
||||
bool complete;
|
||||
};
|
||||
};
|
||||
|
@@ -2,7 +2,7 @@
|
||||
#include <algorithm>
|
||||
|
||||
namespace platform {
|
||||
Results::Results(const string& path, const string& model, const string& score, bool complete, bool partial) :
|
||||
Results::Results(const std::string& path, const std::string& model, const std::string& score, bool complete, bool partial) :
|
||||
path(path), model(model), scoreName(score), complete(complete), partial(partial)
|
||||
{
|
||||
load();
|
||||
@@ -17,7 +17,7 @@ namespace platform {
|
||||
using std::filesystem::directory_iterator;
|
||||
for (const auto& file : directory_iterator(path)) {
|
||||
auto filename = file.path().filename().string();
|
||||
if (filename.find(".json") != string::npos && filename.find("results_") == 0) {
|
||||
if (filename.find(".json") != std::string::npos && filename.find("results_") == 0) {
|
||||
auto result = Result(path, filename);
|
||||
bool addResult = true;
|
||||
if (model != "any" && result.getModel() != model || scoreName != "any" && scoreName != result.getScoreName() || complete && !result.isComplete() || partial && result.isComplete())
|
||||
@@ -27,7 +27,7 @@ namespace platform {
|
||||
}
|
||||
}
|
||||
}
|
||||
void Results::hideResult(int index, const string& pathHidden)
|
||||
void Results::hideResult(int index, const std::string& pathHidden)
|
||||
{
|
||||
auto filename = files.at(index).getFilename();
|
||||
rename((path + "/" + filename).c_str(), (pathHidden + "/" + filename).c_str());
|
||||
|
@@ -6,32 +6,31 @@
|
||||
#include <nlohmann/json.hpp>
|
||||
#include "Result.h"
|
||||
namespace platform {
|
||||
using namespace std;
|
||||
using json = nlohmann::json;
|
||||
|
||||
class Results {
|
||||
public:
|
||||
Results(const string& path, const string& model, const string& score, bool complete, bool partial);
|
||||
Results(const std::string& path, const std::string& model, const std::string& score, bool complete, bool partial);
|
||||
void sortDate();
|
||||
void sortScore();
|
||||
void sortModel();
|
||||
void sortDuration();
|
||||
int maxModelSize() const { return maxModel; };
|
||||
void hideResult(int index, const string& pathHidden);
|
||||
void hideResult(int index, const std::string& pathHidden);
|
||||
void deleteResult(int index);
|
||||
int size() const;
|
||||
bool empty() const;
|
||||
vector<Result>::iterator begin() { return files.begin(); };
|
||||
vector<Result>::iterator end() { return files.end(); };
|
||||
std::vector<Result>::iterator begin() { return files.begin(); };
|
||||
std::vector<Result>::iterator end() { return files.end(); };
|
||||
Result& at(int index) { return files.at(index); };
|
||||
private:
|
||||
string path;
|
||||
string model;
|
||||
string scoreName;
|
||||
std::string path;
|
||||
std::string model;
|
||||
std::string scoreName;
|
||||
bool complete;
|
||||
bool partial;
|
||||
int maxModel;
|
||||
vector<Result> files;
|
||||
std::vector<Result> files;
|
||||
void load(); // Loads the list of results
|
||||
};
|
||||
};
|
||||
|
@@ -9,7 +9,7 @@
|
||||
|
||||
namespace platform {
|
||||
|
||||
Statistics::Statistics(const vector<string>& models, const vector<string>& datasets, const json& data, double significance, bool output) :
|
||||
Statistics::Statistics(const std::vector<std::string>& models, const std::vector<std::string>& datasets, const json& data, double significance, bool output) :
|
||||
models(models), datasets(datasets), data(data), significance(significance), output(output)
|
||||
{
|
||||
nModels = models.size();
|
||||
@@ -20,27 +20,27 @@ namespace platform {
|
||||
void Statistics::fit()
|
||||
{
|
||||
if (nModels < 3 || nDatasets < 3) {
|
||||
cerr << "nModels: " << nModels << endl;
|
||||
cerr << "nDatasets: " << nDatasets << endl;
|
||||
throw runtime_error("Can't make the Friedman test with less than 3 models and/or less than 3 datasets.");
|
||||
std::cerr << "nModels: " << nModels << std::endl;
|
||||
std::cerr << "nDatasets: " << nDatasets << std::endl;
|
||||
throw std::runtime_error("Can't make the Friedman test with less than 3 models and/or less than 3 datasets.");
|
||||
}
|
||||
ranksModels.clear();
|
||||
computeRanks();
|
||||
// Set the control model as the one with the lowest average rank
|
||||
controlIdx = distance(ranks.begin(), min_element(ranks.begin(), ranks.end(), [](const auto& l, const auto& r) { return l.second < r.second; }));
|
||||
computeWTL();
|
||||
maxModelName = (*max_element(models.begin(), models.end(), [](const string& a, const string& b) { return a.size() < b.size(); })).size();
|
||||
maxDatasetName = (*max_element(datasets.begin(), datasets.end(), [](const string& a, const string& b) { return a.size() < b.size(); })).size();
|
||||
maxModelName = (*std::max_element(models.begin(), models.end(), [](const std::string& a, const std::string& b) { return a.size() < b.size(); })).size();
|
||||
maxDatasetName = (*std::max_element(datasets.begin(), datasets.end(), [](const std::string& a, const std::string& b) { return a.size() < b.size(); })).size();
|
||||
fitted = true;
|
||||
}
|
||||
map<string, float> assignRanks(vector<pair<string, double>>& ranksOrder)
|
||||
std::map<std::string, float> assignRanks(std::vector<std::pair<std::string, double>>& ranksOrder)
|
||||
{
|
||||
// sort the ranksOrder vector by value
|
||||
sort(ranksOrder.begin(), ranksOrder.end(), [](const pair<string, double>& a, const pair<string, double>& b) {
|
||||
// sort the ranksOrder std::vector by value
|
||||
std::sort(ranksOrder.begin(), ranksOrder.end(), [](const std::pair<std::string, double>& a, const std::pair<std::string, double>& b) {
|
||||
return a.second > b.second;
|
||||
});
|
||||
//Assign ranks to values and if they are the same they share the same averaged rank
|
||||
map<string, float> ranks;
|
||||
std::map<std::string, float> ranks;
|
||||
for (int i = 0; i < ranksOrder.size(); i++) {
|
||||
ranks[ranksOrder[i].first] = i + 1.0;
|
||||
}
|
||||
@@ -63,9 +63,9 @@ namespace platform {
|
||||
}
|
||||
void Statistics::computeRanks()
|
||||
{
|
||||
map<string, float> ranksLine;
|
||||
std::map<std::string, float> ranksLine;
|
||||
for (const auto& dataset : datasets) {
|
||||
vector<pair<string, double>> ranksOrder;
|
||||
std::vector<std::pair<std::string, double>> ranksOrder;
|
||||
for (const auto& model : models) {
|
||||
double value = data[model].at(dataset).at(0).get<double>();
|
||||
ranksOrder.push_back({ model, value });
|
||||
@@ -118,11 +118,11 @@ namespace platform {
|
||||
if (!fitted) {
|
||||
fit();
|
||||
}
|
||||
stringstream oss;
|
||||
std::stringstream oss;
|
||||
// Reference https://link.springer.com/article/10.1007/s44196-022-00083-8
|
||||
// Post-hoc Holm test
|
||||
// Calculate the p-value for the models paired with the control model
|
||||
map<int, double> stats; // p-value of each model paired with the control model
|
||||
std::map<int, double> stats; // p-value of each model paired with the control model
|
||||
boost::math::normal dist(0.0, 1.0);
|
||||
double diff = sqrt(nModels * (nModels + 1) / (6.0 * nDatasets));
|
||||
for (int i = 0; i < nModels; i++) {
|
||||
@@ -135,11 +135,11 @@ namespace platform {
|
||||
stats[i] = p_value;
|
||||
}
|
||||
// Sort the models by p-value
|
||||
vector<pair<int, double>> statsOrder;
|
||||
std::vector<std::pair<int, double>> statsOrder;
|
||||
for (const auto& stat : stats) {
|
||||
statsOrder.push_back({ stat.first, stat.second });
|
||||
}
|
||||
sort(statsOrder.begin(), statsOrder.end(), [](const pair<int, double>& a, const pair<int, double>& b) {
|
||||
std::sort(statsOrder.begin(), statsOrder.end(), [](const std::pair<int, double>& a, const std::pair<int, double>& b) {
|
||||
return a.second < b.second;
|
||||
});
|
||||
|
||||
@@ -147,29 +147,29 @@ namespace platform {
|
||||
for (int i = 0; i < statsOrder.size(); ++i) {
|
||||
auto item = statsOrder.at(i);
|
||||
double before = i == 0 ? 0.0 : statsOrder.at(i - 1).second;
|
||||
double p_value = min((double)1.0, item.second * (nModels - i));
|
||||
p_value = max(before, p_value);
|
||||
double p_value = std::min((double)1.0, item.second * (nModels - i));
|
||||
p_value = std::max(before, p_value);
|
||||
statsOrder[i] = { item.first, p_value };
|
||||
}
|
||||
holmResult.model = models.at(controlIdx);
|
||||
auto color = friedmanResult ? Colors::CYAN() : Colors::YELLOW();
|
||||
oss << color;
|
||||
oss << " *************************************************************************************************************" << endl;
|
||||
oss << " Post-hoc Holm test: H0: 'There is no significant differences between the control model and the other models.'" << endl;
|
||||
oss << " Control model: " << models.at(controlIdx) << endl;
|
||||
oss << " " << left << setw(maxModelName) << string("Model") << " p-value rank win tie loss Status" << endl;
|
||||
oss << " " << string(maxModelName, '=') << " ============ ========= === === ==== =============" << endl;
|
||||
oss << " *************************************************************************************************************" << std::endl;
|
||||
oss << " Post-hoc Holm test: H0: 'There is no significant differences between the control model and the other models.'" << std::endl;
|
||||
oss << " Control model: " << models.at(controlIdx) << std::endl;
|
||||
oss << " " << std::left << std::setw(maxModelName) << std::string("Model") << " p-value rank win tie loss Status" << std::endl;
|
||||
oss << " " << std::string(maxModelName, '=') << " ============ ========= === === ==== =============" << std::endl;
|
||||
// sort ranks from lowest to highest
|
||||
vector<pair<string, float>> ranksOrder;
|
||||
std::vector<std::pair<std::string, float>> ranksOrder;
|
||||
for (const auto& rank : ranks) {
|
||||
ranksOrder.push_back({ rank.first, rank.second });
|
||||
}
|
||||
sort(ranksOrder.begin(), ranksOrder.end(), [](const pair<string, float>& a, const pair<string, float>& b) {
|
||||
std::sort(ranksOrder.begin(), ranksOrder.end(), [](const std::pair<std::string, float>& a, const std::pair<std::string, float>& b) {
|
||||
return a.second < b.second;
|
||||
});
|
||||
// Show the control model info.
|
||||
oss << " " << Colors::BLUE() << left << setw(maxModelName) << ranksOrder.at(0).first << " ";
|
||||
oss << setw(12) << " " << setprecision(7) << fixed << " " << ranksOrder.at(0).second << endl;
|
||||
oss << " " << Colors::BLUE() << std::left << std::setw(maxModelName) << ranksOrder.at(0).first << " ";
|
||||
oss << std::setw(12) << " " << std::setprecision(7) << std::fixed << " " << ranksOrder.at(0).second << std::endl;
|
||||
for (const auto& item : ranksOrder) {
|
||||
auto idx = distance(models.begin(), find(models.begin(), models.end(), item.first));
|
||||
double pvalue = 0.0;
|
||||
@@ -185,15 +185,15 @@ namespace platform {
|
||||
auto colorStatus = pvalue > significance ? Colors::GREEN() : Colors::MAGENTA();
|
||||
auto status = pvalue > significance ? Symbols::check_mark : Symbols::cross;
|
||||
auto textStatus = pvalue > significance ? " accepted H0" : " rejected H0";
|
||||
oss << " " << colorStatus << left << setw(maxModelName) << item.first << " ";
|
||||
oss << setprecision(6) << scientific << pvalue << setprecision(7) << fixed << " " << item.second;
|
||||
oss << " " << right << setw(3) << wtl.at(idx).win << " " << setw(3) << wtl.at(idx).tie << " " << setw(4) << wtl.at(idx).loss;
|
||||
oss << " " << status << textStatus << endl;
|
||||
oss << " " << colorStatus << std::left << std::setw(maxModelName) << item.first << " ";
|
||||
oss << std::setprecision(6) << std::scientific << pvalue << std::setprecision(7) << std::fixed << " " << item.second;
|
||||
oss << " " << std::right << std::setw(3) << wtl.at(idx).win << " " << std::setw(3) << wtl.at(idx).tie << " " << std::setw(4) << wtl.at(idx).loss;
|
||||
oss << " " << status << textStatus << std::endl;
|
||||
}
|
||||
oss << color << " *************************************************************************************************************" << endl;
|
||||
oss << color << " *************************************************************************************************************" << std::endl;
|
||||
oss << Colors::RESET();
|
||||
if (output) {
|
||||
cout << oss.str();
|
||||
std::cout << oss.str();
|
||||
}
|
||||
}
|
||||
bool Statistics::friedmanTest()
|
||||
@@ -201,12 +201,12 @@ namespace platform {
|
||||
if (!fitted) {
|
||||
fit();
|
||||
}
|
||||
stringstream oss;
|
||||
std::stringstream oss;
|
||||
// Friedman test
|
||||
// Calculate the Friedman statistic
|
||||
oss << Colors::BLUE() << endl;
|
||||
oss << "***************************************************************************************************************" << endl;
|
||||
oss << Colors::GREEN() << "Friedman test: H0: 'There is no significant differences between all the classifiers.'" << Colors::BLUE() << endl;
|
||||
oss << Colors::BLUE() << std::endl;
|
||||
oss << "***************************************************************************************************************" << std::endl;
|
||||
oss << Colors::GREEN() << "Friedman test: H0: 'There is no significant differences between all the classifiers.'" << Colors::BLUE() << std::endl;
|
||||
double degreesOfFreedom = nModels - 1.0;
|
||||
double sumSquared = 0;
|
||||
for (const auto& rank : ranks) {
|
||||
@@ -218,21 +218,21 @@ namespace platform {
|
||||
boost::math::chi_squared chiSquared(degreesOfFreedom);
|
||||
long double p_value = (long double)1.0 - cdf(chiSquared, friedmanQ);
|
||||
double criticalValue = quantile(chiSquared, 1 - significance);
|
||||
oss << "Friedman statistic: " << friedmanQ << endl;
|
||||
oss << "Critical χ2 Value for df=" << fixed << (int)degreesOfFreedom
|
||||
<< " and alpha=" << setprecision(2) << fixed << significance << ": " << setprecision(7) << scientific << criticalValue << std::endl;
|
||||
oss << "p-value: " << scientific << p_value << " is " << (p_value < significance ? "less" : "greater") << " than " << setprecision(2) << fixed << significance << endl;
|
||||
oss << "Friedman statistic: " << friedmanQ << std::endl;
|
||||
oss << "Critical χ2 Value for df=" << std::fixed << (int)degreesOfFreedom
|
||||
<< " and alpha=" << std::setprecision(2) << std::fixed << significance << ": " << std::setprecision(7) << std::scientific << criticalValue << std::endl;
|
||||
oss << "p-value: " << std::scientific << p_value << " is " << (p_value < significance ? "less" : "greater") << " than " << std::setprecision(2) << std::fixed << significance << std::endl;
|
||||
bool result;
|
||||
if (p_value < significance) {
|
||||
oss << Colors::GREEN() << "The null hypothesis H0 is rejected." << endl;
|
||||
oss << Colors::GREEN() << "The null hypothesis H0 is rejected." << std::endl;
|
||||
result = true;
|
||||
} else {
|
||||
oss << Colors::YELLOW() << "The null hypothesis H0 is accepted. Computed p-values will not be significant." << endl;
|
||||
oss << Colors::YELLOW() << "The null hypothesis H0 is accepted. Computed p-values will not be significant." << std::endl;
|
||||
result = false;
|
||||
}
|
||||
oss << Colors::BLUE() << "***************************************************************************************************************" << Colors::RESET() << endl;
|
||||
oss << Colors::BLUE() << "***************************************************************************************************************" << Colors::RESET() << std::endl;
|
||||
if (output) {
|
||||
cout << oss.str();
|
||||
std::cout << oss.str();
|
||||
}
|
||||
friedmanResult = { friedmanQ, criticalValue, p_value, result };
|
||||
return result;
|
||||
@@ -245,7 +245,7 @@ namespace platform {
|
||||
{
|
||||
return holmResult;
|
||||
}
|
||||
map<string, map<string, float>>& Statistics::getRanks()
|
||||
std::map<std::string, std::map<std::string, float>>& Statistics::getRanks()
|
||||
{
|
||||
return ranksModels;
|
||||
}
|
||||
|
@@ -5,7 +5,6 @@
|
||||
#include <map>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using namespace std;
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace platform {
|
||||
@@ -21,30 +20,30 @@ namespace platform {
|
||||
bool reject;
|
||||
};
|
||||
struct HolmLine {
|
||||
string model;
|
||||
std::string model;
|
||||
long double pvalue;
|
||||
double rank;
|
||||
WTL wtl;
|
||||
bool reject;
|
||||
};
|
||||
struct HolmResult {
|
||||
string model;
|
||||
vector<HolmLine> holmLines;
|
||||
std::string model;
|
||||
std::vector<HolmLine> holmLines;
|
||||
};
|
||||
class Statistics {
|
||||
public:
|
||||
Statistics(const vector<string>& models, const vector<string>& datasets, const json& data, double significance = 0.05, bool output = true);
|
||||
Statistics(const std::vector<std::string>& models, const std::vector<std::string>& datasets, const json& data, double significance = 0.05, bool output = true);
|
||||
bool friedmanTest();
|
||||
void postHocHolmTest(bool friedmanResult);
|
||||
FriedmanResult& getFriedmanResult();
|
||||
HolmResult& getHolmResult();
|
||||
map<string, map<string, float>>& getRanks();
|
||||
std::map<std::string, std::map<std::string, float>>& getRanks();
|
||||
private:
|
||||
void fit();
|
||||
void computeRanks();
|
||||
void computeWTL();
|
||||
const vector<string>& models;
|
||||
const vector<string>& datasets;
|
||||
const std::vector<std::string>& models;
|
||||
const std::vector<std::string>& datasets;
|
||||
const json& data;
|
||||
double significance;
|
||||
bool output;
|
||||
@@ -52,13 +51,13 @@ namespace platform {
|
||||
int nModels = 0;
|
||||
int nDatasets = 0;
|
||||
int controlIdx = 0;
|
||||
map<int, WTL> wtl;
|
||||
map<string, float> ranks;
|
||||
std::map<int, WTL> wtl;
|
||||
std::map<std::string, float> ranks;
|
||||
int maxModelName = 0;
|
||||
int maxDatasetName = 0;
|
||||
FriedmanResult friedmanResult;
|
||||
HolmResult holmResult;
|
||||
map<string, map<string, float>> ranksModels;
|
||||
std::map<std::string, std::map<std::string, float>> ranksModels;
|
||||
};
|
||||
}
|
||||
#endif // !STATISTICS_H
|
@@ -1,18 +1,17 @@
|
||||
#ifndef SYMBOLS_H
|
||||
#define SYMBOLS_H
|
||||
#include <string>
|
||||
using namespace std;
|
||||
namespace platform {
|
||||
class Symbols {
|
||||
public:
|
||||
inline static const string check_mark{ "\u2714" };
|
||||
inline static const string exclamation{ "\u2757" };
|
||||
inline static const string black_star{ "\u2605" };
|
||||
inline static const string cross{ "\u2717" };
|
||||
inline static const string upward_arrow{ "\u27B6" };
|
||||
inline static const string down_arrow{ "\u27B4" };
|
||||
inline static const string equal_best{ check_mark };
|
||||
inline static const string better_best{ black_star };
|
||||
inline static const std::string check_mark{ "\u2714" };
|
||||
inline static const std::string exclamation{ "\u2757" };
|
||||
inline static const std::string black_star{ "\u2605" };
|
||||
inline static const std::string cross{ "\u2717" };
|
||||
inline static const std::string upward_arrow{ "\u27B6" };
|
||||
inline static const std::string down_arrow{ "\u27B4" };
|
||||
inline static const std::string equal_best{ check_mark };
|
||||
inline static const std::string better_best{ black_star };
|
||||
};
|
||||
}
|
||||
#endif // !SYMBOLS_H
|
@@ -4,7 +4,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
namespace platform {
|
||||
//static vector<string> split(const string& text, char delimiter);
|
||||
//static std::vector<std::string> split(const std::string& text, char delimiter);
|
||||
static std::vector<std::string> split(const std::string& text, char delimiter)
|
||||
{
|
||||
std::vector<std::string> result;
|
||||
|
@@ -4,7 +4,6 @@
|
||||
#include "BestResults.h"
|
||||
#include "Colors.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
argparse::ArgumentParser manageArguments(int argc, char** argv)
|
||||
{
|
||||
@@ -15,19 +14,19 @@ argparse::ArgumentParser manageArguments(int argc, char** argv)
|
||||
program.add_argument("--report").help("report of best score results file").default_value(false).implicit_value(true);
|
||||
program.add_argument("--friedman").help("Friedman test").default_value(false).implicit_value(true);
|
||||
program.add_argument("--excel").help("Output to excel").default_value(false).implicit_value(true);
|
||||
program.add_argument("--level").help("significance level").default_value(0.05).scan<'g', double>().action([](const string& value) {
|
||||
program.add_argument("--level").help("significance level").default_value(0.05).scan<'g', double>().action([](const std::string& value) {
|
||||
try {
|
||||
auto k = stod(value);
|
||||
auto k = std::stod(value);
|
||||
if (k < 0.01 || k > 0.15) {
|
||||
throw runtime_error("Significance level hast to be a number in [0.01, 0.15]");
|
||||
throw std::runtime_error("Significance level hast to be a number in [0.01, 0.15]");
|
||||
}
|
||||
return k;
|
||||
}
|
||||
catch (const runtime_error& err) {
|
||||
throw runtime_error(err.what());
|
||||
catch (const std::runtime_error& err) {
|
||||
throw std::runtime_error(err.what());
|
||||
}
|
||||
catch (...) {
|
||||
throw runtime_error("Number of folds must be an decimal number");
|
||||
throw std::runtime_error("Number of folds must be an decimal number");
|
||||
}});
|
||||
return program;
|
||||
}
|
||||
@@ -35,35 +34,35 @@ argparse::ArgumentParser manageArguments(int argc, char** argv)
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
auto program = manageArguments(argc, argv);
|
||||
string model, score;
|
||||
std::string model, score;
|
||||
bool build, report, friedman, excel;
|
||||
double level;
|
||||
try {
|
||||
program.parse_args(argc, argv);
|
||||
model = program.get<string>("model");
|
||||
score = program.get<string>("score");
|
||||
model = program.get<std::string>("model");
|
||||
score = program.get<std::string>("score");
|
||||
build = program.get<bool>("build");
|
||||
report = program.get<bool>("report");
|
||||
friedman = program.get<bool>("friedman");
|
||||
excel = program.get<bool>("excel");
|
||||
level = program.get<double>("level");
|
||||
if (model == "" || score == "") {
|
||||
throw runtime_error("Model and score name must be supplied");
|
||||
throw std::runtime_error("Model and score name must be supplied");
|
||||
}
|
||||
if (friedman && model != "any") {
|
||||
cerr << "Friedman test can only be used with all models" << endl;
|
||||
cerr << program;
|
||||
std::cerr << "Friedman test can only be used with all models" << std::endl;
|
||||
std::cerr << program;
|
||||
exit(1);
|
||||
}
|
||||
if (!report && !build) {
|
||||
cerr << "Either build, report or both, have to be selected to do anything!" << endl;
|
||||
cerr << program;
|
||||
std::cerr << "Either build, report or both, have to be selected to do anything!" << std::endl;
|
||||
std::cerr << program;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
catch (const exception& err) {
|
||||
cerr << err.what() << endl;
|
||||
cerr << program;
|
||||
catch (const std::exception& err) {
|
||||
std::cerr << err.what() << std::endl;
|
||||
std::cerr << program;
|
||||
exit(1);
|
||||
}
|
||||
// Generate report
|
||||
@@ -72,8 +71,8 @@ int main(int argc, char** argv)
|
||||
if (model == "any") {
|
||||
results.buildAll();
|
||||
} else {
|
||||
string fileName = results.build();
|
||||
cout << Colors::GREEN() << fileName << " created!" << Colors::RESET() << endl;
|
||||
std::string fileName = results.build();
|
||||
std::cout << Colors::GREEN() << fileName << " created!" << Colors::RESET() << std::endl;
|
||||
}
|
||||
}
|
||||
if (report) {
|
||||
|
@@ -4,54 +4,53 @@
|
||||
#include "Colors.h"
|
||||
#include "Datasets.h"
|
||||
|
||||
using namespace std;
|
||||
const int BALANCE_LENGTH = 75;
|
||||
|
||||
struct separated : numpunct<char> {
|
||||
char do_decimal_point() const { return ','; }
|
||||
char do_thousands_sep() const { return '.'; }
|
||||
string do_grouping() const { return "\03"; }
|
||||
std::string do_grouping() const { return "\03"; }
|
||||
};
|
||||
|
||||
void outputBalance(const string& balance)
|
||||
void outputBalance(const std::string& balance)
|
||||
{
|
||||
auto temp = string(balance);
|
||||
auto temp = std::string(balance);
|
||||
while (temp.size() > BALANCE_LENGTH - 1) {
|
||||
auto part = temp.substr(0, BALANCE_LENGTH);
|
||||
cout << part << endl;
|
||||
cout << setw(48) << " ";
|
||||
std::cout << part << std::endl;
|
||||
std::cout << setw(48) << " ";
|
||||
temp = temp.substr(BALANCE_LENGTH);
|
||||
}
|
||||
cout << temp << endl;
|
||||
std::cout << temp << std::endl;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
auto data = platform::Datasets(false, platform::Paths::datasets());
|
||||
locale mylocale(cout.getloc(), new separated);
|
||||
locale mylocale(std::cout.getloc(), new separated);
|
||||
locale::global(mylocale);
|
||||
cout.imbue(mylocale);
|
||||
cout << Colors::GREEN() << "Dataset Sampl. Feat. Cls. Balance" << endl;
|
||||
string balanceBars = string(BALANCE_LENGTH, '=');
|
||||
cout << "============================== ====== ===== === " << balanceBars << endl;
|
||||
std::cout.imbue(mylocale);
|
||||
std::cout << Colors::GREEN() << "Dataset Sampl. Feat. Cls. Balance" << std::endl;
|
||||
std::string balanceBars = std::string(BALANCE_LENGTH, '=');
|
||||
std::cout << "============================== ====== ===== === " << balanceBars << std::endl;
|
||||
bool odd = true;
|
||||
for (const auto& dataset : data.getNames()) {
|
||||
auto color = odd ? Colors::CYAN() : Colors::BLUE();
|
||||
cout << color << setw(30) << left << dataset << " ";
|
||||
std::cout << color << setw(30) << left << dataset << " ";
|
||||
data.loadDataset(dataset);
|
||||
auto nSamples = data.getNSamples(dataset);
|
||||
cout << setw(6) << right << nSamples << " ";
|
||||
cout << setw(5) << right << data.getFeatures(dataset).size() << " ";
|
||||
cout << setw(3) << right << data.getNClasses(dataset) << " ";
|
||||
stringstream oss;
|
||||
string sep = "";
|
||||
std::cout << setw(6) << right << nSamples << " ";
|
||||
std::cout << setw(5) << right << data.getFeatures(dataset).size() << " ";
|
||||
std::cout << setw(3) << right << data.getNClasses(dataset) << " ";
|
||||
std::stringstream oss;
|
||||
std::string sep = "";
|
||||
for (auto number : data.getClassesCounts(dataset)) {
|
||||
oss << sep << setprecision(2) << fixed << (float)number / nSamples * 100.0 << "% (" << number << ")";
|
||||
oss << sep << std::setprecision(2) << fixed << (float)number / nSamples * 100.0 << "% (" << number << ")";
|
||||
sep = " / ";
|
||||
}
|
||||
outputBalance(oss.str());
|
||||
odd = !odd;
|
||||
}
|
||||
cout << Colors::RESET() << endl;
|
||||
std::cout << Colors::RESET() << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
@@ -9,7 +9,6 @@
|
||||
#include "Paths.h"
|
||||
|
||||
|
||||
using namespace std;
|
||||
using json = nlohmann::json;
|
||||
|
||||
argparse::ArgumentParser manageArguments()
|
||||
@@ -19,13 +18,13 @@ argparse::ArgumentParser manageArguments()
|
||||
program.add_argument("-d", "--dataset").default_value("").help("Dataset file name");
|
||||
program.add_argument("--hyperparameters").default_value("{}").help("Hyperparamters passed to the model in Experiment");
|
||||
program.add_argument("-m", "--model")
|
||||
.help("Model to use " + platform::Models::instance()->toString())
|
||||
.help("Model to use " + platform::Models::instance()->tostring())
|
||||
.action([](const std::string& value) {
|
||||
static const vector<string> choices = platform::Models::instance()->getNames();
|
||||
static const std::vector<std::string> choices = platform::Models::instance()->getNames();
|
||||
if (find(choices.begin(), choices.end(), value) != choices.end()) {
|
||||
return value;
|
||||
}
|
||||
throw runtime_error("Model must be one of " + platform::Models::instance()->toString());
|
||||
throw std::runtime_error("Model must be one of " + platform::Models::instance()->tostring());
|
||||
}
|
||||
);
|
||||
program.add_argument("--title").default_value("").help("Experiment title");
|
||||
@@ -33,19 +32,19 @@ argparse::ArgumentParser manageArguments()
|
||||
program.add_argument("--quiet").help("Don't display detailed progress").default_value(false).implicit_value(true);
|
||||
program.add_argument("--save").help("Save result (always save if no dataset is supplied)").default_value(false).implicit_value(true);
|
||||
program.add_argument("--stratified").help("If Stratified KFold is to be done").default_value((bool)stoi(env.get("stratified"))).implicit_value(true);
|
||||
program.add_argument("-f", "--folds").help("Number of folds").default_value(stoi(env.get("n_folds"))).scan<'i', int>().action([](const string& value) {
|
||||
program.add_argument("-f", "--folds").help("Number of folds").default_value(stoi(env.get("n_folds"))).scan<'i', int>().action([](const std::string& value) {
|
||||
try {
|
||||
auto k = stoi(value);
|
||||
if (k < 2) {
|
||||
throw runtime_error("Number of folds must be greater than 1");
|
||||
throw std::runtime_error("Number of folds must be greater than 1");
|
||||
}
|
||||
return k;
|
||||
}
|
||||
catch (const runtime_error& err) {
|
||||
throw runtime_error(err.what());
|
||||
throw std::runtime_error(err.what());
|
||||
}
|
||||
catch (...) {
|
||||
throw runtime_error("Number of folds must be an integer");
|
||||
throw std::runtime_error("Number of folds must be an integer");
|
||||
}});
|
||||
auto seed_values = env.getSeeds();
|
||||
program.add_argument("-s", "--seeds").nargs(1, 10).help("Random seeds. Set to -1 to have pseudo random").scan<'i', int>().default_value(seed_values);
|
||||
@@ -54,39 +53,39 @@ argparse::ArgumentParser manageArguments()
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
string file_name, model_name, title;
|
||||
std::string file_name, model_name, title;
|
||||
json hyperparameters_json;
|
||||
bool discretize_dataset, stratified, saveResults, quiet;
|
||||
vector<int> seeds;
|
||||
vector<string> filesToTest;
|
||||
std::vector<int> seeds;
|
||||
std::vector<std::string> filesToTest;
|
||||
int n_folds;
|
||||
auto program = manageArguments();
|
||||
try {
|
||||
program.parse_args(argc, argv);
|
||||
file_name = program.get<string>("dataset");
|
||||
model_name = program.get<string>("model");
|
||||
file_name = program.get<std::string>("dataset");
|
||||
model_name = program.get<std::string>("model");
|
||||
discretize_dataset = program.get<bool>("discretize");
|
||||
stratified = program.get<bool>("stratified");
|
||||
quiet = program.get<bool>("quiet");
|
||||
n_folds = program.get<int>("folds");
|
||||
seeds = program.get<vector<int>>("seeds");
|
||||
auto hyperparameters = program.get<string>("hyperparameters");
|
||||
seeds = program.get<std::vector<int>>("seeds");
|
||||
auto hyperparameters = program.get<std::string>("hyperparameters");
|
||||
hyperparameters_json = json::parse(hyperparameters);
|
||||
title = program.get<string>("title");
|
||||
title = program.get<std::string>("title");
|
||||
if (title == "" && file_name == "") {
|
||||
throw runtime_error("title is mandatory if dataset is not provided");
|
||||
}
|
||||
saveResults = program.get<bool>("save");
|
||||
}
|
||||
catch (const exception& err) {
|
||||
cerr << err.what() << endl;
|
||||
cerr << err.what() << std::endl;
|
||||
cerr << program;
|
||||
exit(1);
|
||||
}
|
||||
auto datasets = platform::Datasets(discretize_dataset, platform::Paths::datasets());
|
||||
if (file_name != "") {
|
||||
if (!datasets.isDataset(file_name)) {
|
||||
cerr << "Dataset " << file_name << " not found" << endl;
|
||||
cerr << "Dataset " << file_name << " not found" << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
if (title == "") {
|
||||
@@ -118,6 +117,6 @@ int main(int argc, char** argv)
|
||||
}
|
||||
if (!quiet)
|
||||
experiment.report();
|
||||
cout << "Done!" << endl;
|
||||
std::cout << "Done!" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
@@ -2,7 +2,6 @@
|
||||
#include <argparse/argparse.hpp>
|
||||
#include "ManageResults.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
argparse::ArgumentParser manageArguments(int argc, char** argv)
|
||||
{
|
||||
@@ -17,17 +16,17 @@ argparse::ArgumentParser manageArguments(int argc, char** argv)
|
||||
program.parse_args(argc, argv);
|
||||
auto number = program.get<int>("number");
|
||||
if (number < 0) {
|
||||
throw runtime_error("Number of results must be greater than or equal to 0");
|
||||
throw std::runtime_error("Number of results must be greater than or equal to 0");
|
||||
}
|
||||
auto model = program.get<string>("model");
|
||||
auto score = program.get<string>("score");
|
||||
auto model = program.get<std::string>("model");
|
||||
auto score = program.get<std::string>("score");
|
||||
auto complete = program.get<bool>("complete");
|
||||
auto partial = program.get<bool>("partial");
|
||||
auto compare = program.get<bool>("compare");
|
||||
}
|
||||
catch (const exception& err) {
|
||||
cerr << err.what() << endl;
|
||||
cerr << program;
|
||||
catch (const std::exception& err) {
|
||||
std::cerr << err.what() << std::endl;
|
||||
std::cerr << program;
|
||||
exit(1);
|
||||
}
|
||||
return program;
|
||||
@@ -37,8 +36,8 @@ int main(int argc, char** argv)
|
||||
{
|
||||
auto program = manageArguments(argc, argv);
|
||||
int number = program.get<int>("number");
|
||||
string model = program.get<string>("model");
|
||||
string score = program.get<string>("score");
|
||||
std::string model = program.get<std::string>("model");
|
||||
std::string score = program.get<std::string>("score");
|
||||
auto complete = program.get<bool>("complete");
|
||||
auto partial = program.get<bool>("partial");
|
||||
auto compare = program.get<bool>("compare");
|
||||
|
Reference in New Issue
Block a user