diff --git a/src/Platform/BestResults.cc b/src/Platform/BestResults.cc index 5dd34f4..2a94182 100644 --- a/src/Platform/BestResults.cc +++ b/src/Platform/BestResults.cc @@ -290,8 +290,7 @@ namespace platform { ranksModels = stats.getRanks(); } if (excel) { - // BestResultsExcel excel(score, models, datasets, ranksModels, table, friedman, significance); - BestResultsExcel excel(score, models, datasets, table, friedman, significance); + BestResultsExcel excel(score, models, datasets, table, ranksModels, friedman, significance); excel.build(); cout << Colors::YELLOW() << "** Excel file generated: " << excel.getFileName() << Colors::RESET() << endl; } diff --git a/src/Platform/BestResultsExcel.cc b/src/Platform/BestResultsExcel.cc index 937d0e7..39675d9 100644 --- a/src/Platform/BestResultsExcel.cc +++ b/src/Platform/BestResultsExcel.cc @@ -4,8 +4,8 @@ #include "Statistics.h" namespace platform { - BestResultsExcel::BestResultsExcel(const string& score, const vector& models, const vector& datasets, const json& table, bool friedman, double significance) : - score(score), models(models), datasets(datasets), table(table), friedman(friedman), significance(significance) + BestResultsExcel::BestResultsExcel(const string& score, const vector& models, const vector& datasets, const json& table, const map>& ranksModels, bool friedman, double significance) : + score(score), models(models), datasets(datasets), table(table), ranksModels(ranksModels), friedman(friedman), significance(significance) { workbook = workbook_new((Paths::excel() + fileName).c_str()); worksheet = workbook_add_worksheet(workbook, "Best Results"); @@ -34,20 +34,30 @@ namespace platform { } void BestResultsExcel::build() { - header(); - body(); - footer(); + // Create Sheet with scores + header(false); + body(false); + footer(false); + if (friedman) { + // Create Sheet with ranks + worksheet = workbook_add_worksheet(workbook, "Ranks"); + formatColumns(); + header(true); + body(true); + footer(true); + // Create Sheet with Friedman Test + doFriedman(); + } } string BestResultsExcel::getFileName() { return Paths::excel() + fileName; } - void BestResultsExcel::header() + void BestResultsExcel::header(bool ranks) { row = 0; - string message = "Best results for " + score; + 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; int col = 1; @@ -57,7 +67,7 @@ namespace platform { writeString(row, ++col, model.c_str(), "bodyHeader"); } } - void BestResultsExcel::body() + void BestResultsExcel::body(bool ranks) { row = 4; int i = 0; @@ -67,11 +77,14 @@ namespace platform { writeString(row, 1, item.key().c_str(), "text"); int col = 1; for (const auto& model : models) { - double value = table[model].at(item.key()).at(0).get(); + double value = ranks ? ranksModels[item.key()][model] : table[model].at(item.key()).at(0).get(); writeDouble(row, ++col, value, "result"); } ++row; } + } + void BestResultsExcel::footer(bool ranks) + { // Set Totals writeString(row, 1, "Total", "bodyHeader"); int col = 1; @@ -80,77 +93,85 @@ namespace platform { oss << "=sum(indirect(address(" << 5 << "," << col + 2 << ")):indirect(address(" << row << "," << col + 2 << ")))"; worksheet_write_formula(worksheet, row, ++col, oss.str().c_str(), styles["bodyHeader_odd"]); } - } - void BestResultsExcel::footer() - { - if (friedman) { - worksheet = workbook_add_worksheet(workbook, "Friedman"); - vector columns_sizes = { 5, datasetNameSize }; - for (int i = 0; i < models.size(); ++i) { - columns_sizes.push_back(modelNameSize); - } - for (int i = 0; i < columns_sizes.size(); ++i) { - worksheet_set_column(worksheet, i, i, columns_sizes.at(i), NULL); - } - worksheet_merge_range(worksheet, 0, 0, 0, 1 + models.size(), "Friedman Test", styles["headerFirst"]); - row = 2; - Statistics stats(models, datasets, table, significance, false); - auto result = stats.friedmanTest(); - stats.postHocHolmTest(result); - auto friedmanResult = stats.getFriedmanResult(); - auto holmResult = stats.getHolmResult(); - worksheet_merge_range(worksheet, row, 0, row, 1 + models.size(), "Null hypothesis: H0 'There is no significant differences between all the classifiers.'", styles["headerSmall"]); - row += 2; - writeString(row, 1, "Friedman Q", "bodyHeader"); - writeDouble(row, 2, friedmanResult.statistic, "bodyHeader"); + if (ranks) { row++; - writeString(row, 1, "Critical χ2 value", "bodyHeader"); - writeDouble(row, 2, friedmanResult.criticalValue, "bodyHeader"); - row++; - writeString(row, 1, "p-value", "bodyHeader"); - writeDouble(row, 2, friedmanResult.pvalue, "bodyHeader"); - writeString(row, 3, friedmanResult.reject ? "<" : ">", "bodyHeader"); - writeDouble(row, 4, significance, "bodyHeader"); - writeString(row, 5, friedmanResult.reject ? "Reject H0" : "Accept H0", "bodyHeader"); - row += 3; - worksheet_merge_range(worksheet, row, 0, row, 1 + models.size(), "Holm Test", styles["headerFirst"]); - 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; - worksheet_merge_range(worksheet, row, 1, row, 7, controlModel.c_str(), styles["bodyHeader_odd"]); - row++; - writeString(row, 1, "Model", "bodyHeader"); - writeString(row, 2, "p-value", "bodyHeader"); - writeString(row, 3, "Rank", "bodyHeader"); - writeString(row, 4, "Win", "bodyHeader"); - writeString(row, 5, "Tie", "bodyHeader"); - writeString(row, 6, "Loss", "bodyHeader"); - writeString(row, 7, "Reject H0", "bodyHeader"); - row++; - bool first = true; - for (const auto& item : holmResult.holmLines) { - writeString(row, 1, item.model, "text"); - if (first) { - // Control model info - first = false; - writeString(row, 2, "", "text"); - writeDouble(row, 3, item.rank, "result"); - writeString(row, 4, "", "text"); - writeString(row, 5, "", "text"); - writeString(row, 6, "", "text"); - writeString(row, 7, "", "textCentered"); - } else { - // Rest of the models info - writeDouble(row, 2, item.pvalue, "result"); - writeDouble(row, 3, item.rank, "result"); - writeInt(row, 4, item.wtl.win, "ints"); - writeInt(row, 5, item.wtl.tie, "ints"); - writeInt(row, 6, item.wtl.loss, "ints"); - writeString(row, 7, item.reject ? "Yes" : "No", "textCentered"); - } - row++; + writeString(row, 1, "Average ranks", "bodyHeader"); + int col = 1; + for (const auto& model : models) { + stringstream oss; + oss << "=sum(indirect(address(" << 5 << "," << col + 2 << ")):indirect(address(" << row - 1 << "," << col + 2 << ")))/" << datasets.size(); + worksheet_write_formula(worksheet, row, ++col, oss.str().c_str(), styles["bodyHeader_odd"]); } } } + void BestResultsExcel::doFriedman() + { + worksheet = workbook_add_worksheet(workbook, "Friedman"); + vector columns_sizes = { 5, datasetNameSize }; + for (int i = 0; i < models.size(); ++i) { + columns_sizes.push_back(modelNameSize); + } + for (int i = 0; i < columns_sizes.size(); ++i) { + worksheet_set_column(worksheet, i, i, columns_sizes.at(i), NULL); + } + worksheet_merge_range(worksheet, 0, 0, 0, 1 + models.size(), "Friedman Test", styles["headerFirst"]); + row = 2; + Statistics stats(models, datasets, table, significance, false); + auto result = stats.friedmanTest(); + stats.postHocHolmTest(result); + auto friedmanResult = stats.getFriedmanResult(); + auto holmResult = stats.getHolmResult(); + worksheet_merge_range(worksheet, row, 0, row, 1 + models.size(), "Null hypothesis: H0 'There is no significant differences between all the classifiers.'", styles["headerSmall"]); + row += 2; + writeString(row, 1, "Friedman Q", "bodyHeader"); + writeDouble(row, 2, friedmanResult.statistic, "bodyHeader"); + row++; + writeString(row, 1, "Critical χ2 value", "bodyHeader"); + writeDouble(row, 2, friedmanResult.criticalValue, "bodyHeader"); + row++; + writeString(row, 1, "p-value", "bodyHeader"); + writeDouble(row, 2, friedmanResult.pvalue, "bodyHeader"); + writeString(row, 3, friedmanResult.reject ? "<" : ">", "bodyHeader"); + writeDouble(row, 4, significance, "bodyHeader"); + writeString(row, 5, friedmanResult.reject ? "Reject H0" : "Accept H0", "bodyHeader"); + row += 3; + worksheet_merge_range(worksheet, row, 0, row, 1 + models.size(), "Holm Test", styles["headerFirst"]); + 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; + worksheet_merge_range(worksheet, row, 1, row, 7, controlModel.c_str(), styles["bodyHeader_odd"]); + row++; + writeString(row, 1, "Model", "bodyHeader"); + writeString(row, 2, "p-value", "bodyHeader"); + writeString(row, 3, "Rank", "bodyHeader"); + writeString(row, 4, "Win", "bodyHeader"); + writeString(row, 5, "Tie", "bodyHeader"); + writeString(row, 6, "Loss", "bodyHeader"); + writeString(row, 7, "Reject H0", "bodyHeader"); + row++; + bool first = true; + for (const auto& item : holmResult.holmLines) { + writeString(row, 1, item.model, "text"); + if (first) { + // Control model info + first = false; + writeString(row, 2, "", "text"); + writeDouble(row, 3, item.rank, "result"); + writeString(row, 4, "", "text"); + writeString(row, 5, "", "text"); + writeString(row, 6, "", "text"); + writeString(row, 7, "", "textCentered"); + } else { + // Rest of the models info + writeDouble(row, 2, item.pvalue, "result"); + writeDouble(row, 3, item.rank, "result"); + writeInt(row, 4, item.wtl.win, "ints"); + writeInt(row, 5, item.wtl.tie, "ints"); + writeInt(row, 6, item.wtl.loss, "ints"); + writeString(row, 7, item.reject ? "Yes" : "No", "textCentered"); + } + row++; + } + } } \ No newline at end of file diff --git a/src/Platform/BestResultsExcel.h b/src/Platform/BestResultsExcel.h index fef9add..c31c61f 100644 --- a/src/Platform/BestResultsExcel.h +++ b/src/Platform/BestResultsExcel.h @@ -12,25 +12,26 @@ namespace platform { class BestResultsExcel : ExcelFile { public: - BestResultsExcel(const string& score, const vector& models, const vector& datasets, const json& table, bool friedman, double significance); + BestResultsExcel(const string& score, const vector& models, const vector& datasets, const json& table, const map>& ranks, bool friedman, double significance); ~BestResultsExcel(); void build(); string getFileName(); private: - void header(); - void body(); - void footer(); + void header(bool ranks); + void body(bool ranks); + void footer(bool ranks); void formatColumns(); + void doFriedman(); const string fileName = "BestResults.xlsx"; - const string& score; - const vector& models; - const vector& datasets; - const json& table; + string score; + vector models; + vector datasets; + json table; + map> ranksModels; bool friedman; double significance; int modelNameSize = 12; // Min size of the column int datasetNameSize = 25; // Min size of the column - // map>& ranksModels; }; } #endif //BESTRESULTS_EXCEL_H \ No newline at end of file