Refactor postHoc
This commit is contained in:
@@ -7,8 +7,6 @@ project(Platform
|
|||||||
LANGUAGES CXX
|
LANGUAGES CXX
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Global CMake variables
|
# Global CMake variables
|
||||||
# ----------------------
|
# ----------------------
|
||||||
set(CMAKE_CXX_STANDARD 20)
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
|
@@ -13,7 +13,7 @@ include_directories(
|
|||||||
# b_best
|
# b_best
|
||||||
add_executable(
|
add_executable(
|
||||||
b_best commands/b_best.cpp best/Statistics.cpp
|
b_best commands/b_best.cpp best/Statistics.cpp
|
||||||
best/BestResultsExcel.cpp best/BestResultsTex.cpp best/BestResultsMd.cpp best/BestResults.cpp
|
best/BestResultsExcel.cpp best/BestResultsTex.cpp best/BestResultsMd.cpp best/BestResults.cpp best/DeLong.cpp
|
||||||
common/Datasets.cpp common/Dataset.cpp common/Discretization.cpp
|
common/Datasets.cpp common/Dataset.cpp common/Discretization.cpp
|
||||||
main/Models.cpp main/Scores.cpp
|
main/Models.cpp main/Scores.cpp
|
||||||
reports/ReportExcel.cpp reports/ReportBase.cpp reports/ExcelFile.cpp
|
reports/ReportExcel.cpp reports/ReportBase.cpp reports/ExcelFile.cpp
|
||||||
|
@@ -222,7 +222,7 @@ namespace platform {
|
|||||||
std::cout << oss.str();
|
std::cout << oss.str();
|
||||||
std::cout << std::string(oss.str().size() - 8, '-') << std::endl;
|
std::cout << std::string(oss.str().size() - 8, '-') << std::endl;
|
||||||
std::cout << Colors::GREEN() << " # " << std::setw(maxDatasetName + 1) << std::left << std::string("Dataset");
|
std::cout << Colors::GREEN() << " # " << std::setw(maxDatasetName + 1) << std::left << std::string("Dataset");
|
||||||
auto bestResultsTex = BestResultsTex();
|
auto bestResultsTex = BestResultsTex(score);
|
||||||
auto bestResultsMd = BestResultsMd();
|
auto bestResultsMd = BestResultsMd();
|
||||||
if (tex) {
|
if (tex) {
|
||||||
bestResultsTex.results_header(models, table.at("dateTable").get<std::string>(), index);
|
bestResultsTex.results_header(models, table.at("dateTable").get<std::string>(), index);
|
||||||
@@ -339,7 +339,8 @@ namespace platform {
|
|||||||
if (friedman) {
|
if (friedman) {
|
||||||
Statistics stats(models, datasets, table, significance);
|
Statistics stats(models, datasets, table, significance);
|
||||||
auto result = stats.friedmanTest();
|
auto result = stats.friedmanTest();
|
||||||
stats.postHocHolmTest(result, tex);
|
stats.postHocHolmTest();
|
||||||
|
stats.postHocTestReport("Holm", score, result, tex);
|
||||||
ranksModels = stats.getRanks();
|
ranksModels = stats.getRanks();
|
||||||
}
|
}
|
||||||
if (tex) {
|
if (tex) {
|
||||||
|
@@ -243,9 +243,10 @@ namespace platform {
|
|||||||
row = 2;
|
row = 2;
|
||||||
Statistics stats(models, datasets, table, significance, false);
|
Statistics stats(models, datasets, table, significance, false);
|
||||||
auto result = stats.friedmanTest();
|
auto result = stats.friedmanTest();
|
||||||
stats.postHocHolmTest(result);
|
stats.postHocHolmTest();
|
||||||
|
// stats.postHocTestReport("Holm", result, false);
|
||||||
auto friedmanResult = stats.getFriedmanResult();
|
auto friedmanResult = stats.getFriedmanResult();
|
||||||
auto holmResult = stats.getHolmResult();
|
auto postHocResult = stats.getPostHocResult();
|
||||||
worksheet_merge_range(worksheet, row, 0, row, 7, "Null hypothesis: H0 'There is no significant differences between all the classifiers.'", styles["headerSmall"]);
|
worksheet_merge_range(worksheet, row, 0, row, 7, "Null hypothesis: H0 'There is no significant differences between all the classifiers.'", styles["headerSmall"]);
|
||||||
row += 2;
|
row += 2;
|
||||||
writeString(row, 1, "Friedman Q", "bodyHeader");
|
writeString(row, 1, "Friedman Q", "bodyHeader");
|
||||||
@@ -264,7 +265,7 @@ namespace platform {
|
|||||||
row += 2;
|
row += 2;
|
||||||
worksheet_merge_range(worksheet, row, 0, row, 7, "Null hypothesis: H0 'There is no significant differences between the control model and the other models.'", styles["headerSmall"]);
|
worksheet_merge_range(worksheet, row, 0, row, 7, "Null hypothesis: H0 'There is no significant differences between the control model and the other models.'", styles["headerSmall"]);
|
||||||
row += 2;
|
row += 2;
|
||||||
std::string controlModel = "Control Model: " + holmResult.model;
|
std::string controlModel = "Control Model: " + postHocResult.model;
|
||||||
worksheet_merge_range(worksheet, row, 1, row, 7, controlModel.c_str(), styles["bodyHeader_odd"]);
|
worksheet_merge_range(worksheet, row, 1, row, 7, controlModel.c_str(), styles["bodyHeader_odd"]);
|
||||||
row++;
|
row++;
|
||||||
writeString(row, 1, "Model", "bodyHeader");
|
writeString(row, 1, "Model", "bodyHeader");
|
||||||
@@ -276,7 +277,7 @@ namespace platform {
|
|||||||
writeString(row, 7, "Reject H0", "bodyHeader");
|
writeString(row, 7, "Reject H0", "bodyHeader");
|
||||||
row++;
|
row++;
|
||||||
bool first = true;
|
bool first = true;
|
||||||
for (const auto& item : holmResult.holmLines) {
|
for (const auto& item : postHocResult.postHocLines) {
|
||||||
writeString(row, 1, item.model, "text");
|
writeString(row, 1, item.model, "text");
|
||||||
if (first) {
|
if (first) {
|
||||||
// Control model info
|
// Control model info
|
||||||
|
@@ -75,7 +75,7 @@ namespace platform {
|
|||||||
|
|
||||||
handler.close();
|
handler.close();
|
||||||
}
|
}
|
||||||
void BestResultsMd::holm_test(struct HolmResult& holmResult, const std::string& date)
|
void BestResultsMd::postHoc_test(struct PostHocResult& postHocResult, const std::string& kind, const std::string& date)
|
||||||
{
|
{
|
||||||
auto file_name = Paths::tex() + Paths::md_post_hoc();
|
auto file_name = Paths::tex() + Paths::md_post_hoc();
|
||||||
openMdFile(file_name);
|
openMdFile(file_name);
|
||||||
@@ -84,12 +84,12 @@ namespace platform {
|
|||||||
handler << std::endl;
|
handler << std::endl;
|
||||||
handler << " Post-hoc handler test" << std::endl;
|
handler << " Post-hoc handler test" << std::endl;
|
||||||
handler << "-->" << std::endl;
|
handler << "-->" << std::endl;
|
||||||
handler << "Post-hoc Holm test: H<sub>0</sub>: There is no significant differences between the control model and the other models." << std::endl << std::endl;
|
handler << "Post-hoc " << kind << " test: H<sub>0</sub>: There is no significant differences between the control model and the other models." << std::endl << std::endl;
|
||||||
handler << "| classifier | pvalue | rank | win | tie | loss | H<sub>0</sub> |" << std::endl;
|
handler << "| classifier | pvalue | rank | win | tie | loss | H<sub>0</sub> |" << std::endl;
|
||||||
handler << "| :-- | --: | --: | --:| --: | --: | :--: |" << std::endl;
|
handler << "| :-- | --: | --: | --:| --: | --: | :--: |" << std::endl;
|
||||||
for (auto const& line : holmResult.holmLines) {
|
for (auto const& line : postHocResult.postHocLines) {
|
||||||
auto textStatus = !line.reject ? "**" : " ";
|
auto textStatus = !line.reject ? "**" : " ";
|
||||||
if (line.model == holmResult.model) {
|
if (line.model == postHocResult.model) {
|
||||||
handler << "| " << line.model << " | - | " << std::fixed << std::setprecision(2) << line.rank << " | - | - | - |" << std::endl;
|
handler << "| " << line.model << " | - | " << std::fixed << std::setprecision(2) << line.rank << " | - | - | - |" << std::endl;
|
||||||
} else {
|
} else {
|
||||||
handler << "| " << line.model << " | " << textStatus << std::scientific << std::setprecision(4) << line.pvalue << textStatus << " |";
|
handler << "| " << line.model << " | " << textStatus << std::scientific << std::setprecision(4) << line.pvalue << textStatus << " |";
|
||||||
|
@@ -14,7 +14,7 @@ namespace platform {
|
|||||||
void results_header(const std::vector<std::string>& models, const std::string& date);
|
void results_header(const std::vector<std::string>& models, const std::string& date);
|
||||||
void results_body(const std::vector<std::string>& datasets, json& table);
|
void results_body(const std::vector<std::string>& datasets, json& table);
|
||||||
void results_footer(const std::map<std::string, std::vector<double>>& totals, const std::string& best_model);
|
void results_footer(const std::map<std::string, std::vector<double>>& totals, const std::string& best_model);
|
||||||
void holm_test(struct HolmResult& holmResult, const std::string& date);
|
void postHoc_test(struct PostHocResult& postHocResult, const std::string& kind, const std::string& date);
|
||||||
private:
|
private:
|
||||||
void openMdFile(const std::string& name);
|
void openMdFile(const std::string& name);
|
||||||
std::ofstream handler;
|
std::ofstream handler;
|
||||||
|
@@ -27,8 +27,10 @@ namespace platform {
|
|||||||
handler << "\\tiny " << std::endl;
|
handler << "\\tiny " << std::endl;
|
||||||
handler << "\\renewcommand{\\arraystretch }{1.2} " << std::endl;
|
handler << "\\renewcommand{\\arraystretch }{1.2} " << std::endl;
|
||||||
handler << "\\renewcommand{\\tabcolsep }{0.07cm} " << std::endl;
|
handler << "\\renewcommand{\\tabcolsep }{0.07cm} " << std::endl;
|
||||||
handler << "\\caption{Accuracy results(mean $\\pm$ std) for all the algorithms and datasets} " << std::endl;
|
auto umetric = metric;
|
||||||
handler << "\\label{tab:results_accuracy}" << std::endl;
|
umetric[0] = toupper(umetric[0]);
|
||||||
|
handler << "\\caption{" << umetric << " results(mean $\\pm$ std) for all the algorithms and datasets} " << std::endl;
|
||||||
|
handler << "\\label{tab:results_" << metric << "}" << std::endl;
|
||||||
std::string header_dataset_name = index ? "r" : "l";
|
std::string header_dataset_name = index ? "r" : "l";
|
||||||
handler << "\\begin{tabular} {{" << header_dataset_name << std::string(models.size(), 'c').c_str() << "}}" << std::endl;
|
handler << "\\begin{tabular} {{" << header_dataset_name << std::string(models.size(), 'c').c_str() << "}}" << std::endl;
|
||||||
handler << "\\hline " << std::endl;
|
handler << "\\hline " << std::endl;
|
||||||
@@ -87,25 +89,25 @@ namespace platform {
|
|||||||
handler << "\\end{table}" << std::endl;
|
handler << "\\end{table}" << std::endl;
|
||||||
handler.close();
|
handler.close();
|
||||||
}
|
}
|
||||||
void BestResultsTex::holm_test(struct HolmResult& holmResult, const std::string& date)
|
void BestResultsTex::postHoc_test(struct PostHocResult& postHocResult, const std::string& kind, const std::string& date)
|
||||||
{
|
{
|
||||||
auto file_name = Paths::tex() + Paths::tex_post_hoc();
|
auto file_name = Paths::tex() + Paths::tex_post_hoc();
|
||||||
openTexFile(file_name);
|
openTexFile(file_name);
|
||||||
handler << "%% This file has been generated by the platform program" << std::endl;
|
handler << "%% This file has been generated by the platform program" << std::endl;
|
||||||
handler << "%% Date: " << date.c_str() << std::endl;
|
handler << "%% Date: " << date.c_str() << std::endl;
|
||||||
handler << "%%" << std::endl;
|
handler << "%%" << std::endl;
|
||||||
handler << "%% Post-hoc handler test" << std::endl;
|
handler << "%% Post-hoc " << kind << " test" << std::endl;
|
||||||
handler << "%%" << std::endl;
|
handler << "%%" << std::endl;
|
||||||
handler << "\\begin{table}[htbp]" << std::endl;
|
handler << "\\begin{table}[htbp]" << std::endl;
|
||||||
handler << "\\centering" << std::endl;
|
handler << "\\centering" << std::endl;
|
||||||
handler << "\\caption{Results of the post-hoc test for the mean accuracy of the algorithms.}\\label{tab:tests}" << std::endl;
|
handler << "\\caption{Results of the post-hoc " << kind << " test for the mean " << metric << " of the algorithms.}\\label{ tab:tests }" << std::endl;
|
||||||
handler << "\\begin{tabular}{lrrrrr}" << std::endl;
|
handler << "\\begin{tabular}{lrrrrr}" << std::endl;
|
||||||
handler << "\\hline" << std::endl;
|
handler << "\\hline" << std::endl;
|
||||||
handler << "classifier & pvalue & rank & win & tie & loss\\\\" << std::endl;
|
handler << "classifier & pvalue & rank & win & tie & loss\\\\" << std::endl;
|
||||||
handler << "\\hline" << std::endl;
|
handler << "\\hline" << std::endl;
|
||||||
for (auto const& line : holmResult.holmLines) {
|
for (auto const& line : postHocResult.postHocLines) {
|
||||||
auto textStatus = !line.reject ? "\\bf " : " ";
|
auto textStatus = !line.reject ? "\\bf " : " ";
|
||||||
if (line.model == holmResult.model) {
|
if (line.model == postHocResult.model) {
|
||||||
handler << line.model << " & - & " << std::fixed << std::setprecision(2) << line.rank << " & - & - & - \\\\" << std::endl;
|
handler << line.model << " & - & " << std::fixed << std::setprecision(2) << line.rank << " & - & - & - \\\\" << std::endl;
|
||||||
} else {
|
} else {
|
||||||
handler << line.model << " & " << textStatus << std::scientific << std::setprecision(4) << line.pvalue << " & ";
|
handler << line.model << " & " << textStatus << std::scientific << std::setprecision(4) << line.pvalue << " & ";
|
||||||
|
@@ -9,13 +9,14 @@ namespace platform {
|
|||||||
using json = nlohmann::ordered_json;
|
using json = nlohmann::ordered_json;
|
||||||
class BestResultsTex {
|
class BestResultsTex {
|
||||||
public:
|
public:
|
||||||
BestResultsTex(bool dataset_name = true) : dataset_name(dataset_name) {};
|
BestResultsTex(const std::string metric_, bool dataset_name = true) : metric{ metric_ }, dataset_name{ dataset_name } {};
|
||||||
~BestResultsTex() = default;
|
~BestResultsTex() = default;
|
||||||
void results_header(const std::vector<std::string>& models, const std::string& date, bool index);
|
void results_header(const std::vector<std::string>& models, const std::string& date, bool index);
|
||||||
void results_body(const std::vector<std::string>& datasets, json& table, bool index);
|
void results_body(const std::vector<std::string>& datasets, json& table, bool index);
|
||||||
void results_footer(const std::map<std::string, std::vector<double>>& totals, const std::string& best_model);
|
void results_footer(const std::map<std::string, std::vector<double>>& totals, const std::string& best_model);
|
||||||
void holm_test(struct HolmResult& holmResult, const std::string& date);
|
void postHoc_test(struct PostHocResult& postHocResult, const std::string& kind, const std::string& date);
|
||||||
private:
|
private:
|
||||||
|
std::string metric;
|
||||||
bool dataset_name;
|
bool dataset_name;
|
||||||
void openTexFile(const std::string& name);
|
void openTexFile(const std::string& name);
|
||||||
std::ofstream handler;
|
std::ofstream handler;
|
||||||
|
45
src/best/DeLong.cpp
Normal file
45
src/best/DeLong.cpp
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
// DeLong.cpp
|
||||||
|
// Integración del test de DeLong con la clase RocAuc y Statistics
|
||||||
|
// Basado en: X. Sun and W. Xu, "Fast Implementation of DeLong’s Algorithm for Comparing the Areas Under Correlated Receiver Operating Characteristic Curves," (2014), y algoritmos inspirados en sklearn/pROC
|
||||||
|
|
||||||
|
#include "DeLong.h"
|
||||||
|
#include <vector>
|
||||||
|
#include <cmath>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <numeric>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
namespace platform {
|
||||||
|
|
||||||
|
DeLong::DeLongResult DeLong::compare(const std::vector<double>& aucs_model1,
|
||||||
|
const std::vector<double>& aucs_model2)
|
||||||
|
{
|
||||||
|
if (aucs_model1.size() != aucs_model2.size()) {
|
||||||
|
throw std::invalid_argument("AUC lists must have the same size");
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t N = aucs_model1.size();
|
||||||
|
if (N < 2) {
|
||||||
|
throw std::invalid_argument("At least two AUC values are required");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<double> diffs(N);
|
||||||
|
for (size_t i = 0; i < N; ++i) {
|
||||||
|
diffs[i] = aucs_model1[i] - aucs_model2[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
double mean_diff = std::accumulate(diffs.begin(), diffs.end(), 0.0) / N;
|
||||||
|
double var = 0.0;
|
||||||
|
for (size_t i = 0; i < N; ++i) {
|
||||||
|
var += (diffs[i] - mean_diff) * (diffs[i] - mean_diff);
|
||||||
|
}
|
||||||
|
var /= (N * (N - 1));
|
||||||
|
if (var <= 0.0) var = 1e-10;
|
||||||
|
|
||||||
|
double z = mean_diff / std::sqrt(var);
|
||||||
|
double p = 2.0 * (1.0 - std::erfc(std::abs(z) / std::sqrt(2.0)) / 2.0);
|
||||||
|
return { mean_diff, z, p };
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
24
src/best/DeLong.h
Normal file
24
src/best/DeLong.h
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
#ifndef DELONG_H
|
||||||
|
#define DELONG_H
|
||||||
|
/* ********************************************************************************************************************
|
||||||
|
/* Integración del test de DeLong con la clase RocAuc y Statistics
|
||||||
|
/* Basado en: X. Sun and W. Xu, "Fast Implementation of DeLong’s Algorithm for Comparing the Areas Under Correlated
|
||||||
|
/* Receiver Operating Characteristic Curves," (2014), y algoritmos inspirados en sklearn/pROC
|
||||||
|
/* ********************************************************************************************************************/
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace platform {
|
||||||
|
class DeLong {
|
||||||
|
public:
|
||||||
|
struct DeLongResult {
|
||||||
|
double auc_diff;
|
||||||
|
double z_stat;
|
||||||
|
double p_value;
|
||||||
|
};
|
||||||
|
// Compara dos vectores de AUCs por dataset y devuelve diferencia media,
|
||||||
|
// estadístico z y p-valor usando un test de rangos (DeLong simplificado)
|
||||||
|
static DeLongResult compare(const std::vector<double>& aucs_model1,
|
||||||
|
const std::vector<double>& aucs_model2);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif // DELONG_H
|
@@ -7,6 +7,7 @@
|
|||||||
#include "BestResultsTex.h"
|
#include "BestResultsTex.h"
|
||||||
#include "BestResultsMd.h"
|
#include "BestResultsMd.h"
|
||||||
#include "Statistics.h"
|
#include "Statistics.h"
|
||||||
|
#include "DeLong.h"
|
||||||
|
|
||||||
|
|
||||||
namespace platform {
|
namespace platform {
|
||||||
@@ -114,8 +115,7 @@ namespace platform {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
void Statistics::postHocHolmTest()
|
||||||
void Statistics::postHocHolmTest(bool friedmanResult, bool tex)
|
|
||||||
{
|
{
|
||||||
if (!fitted) {
|
if (!fitted) {
|
||||||
fit();
|
fit();
|
||||||
@@ -137,27 +137,33 @@ namespace platform {
|
|||||||
stats[i] = p_value;
|
stats[i] = p_value;
|
||||||
}
|
}
|
||||||
// Sort the models by p-value
|
// Sort the models by p-value
|
||||||
std::vector<std::pair<int, double>> statsOrder;
|
|
||||||
for (const auto& stat : stats) {
|
for (const auto& stat : stats) {
|
||||||
statsOrder.push_back({ stat.first, stat.second });
|
postHocData.push_back({ stat.first, stat.second });
|
||||||
}
|
}
|
||||||
std::sort(statsOrder.begin(), statsOrder.end(), [](const std::pair<int, double>& a, const std::pair<int, double>& b) {
|
std::sort(postHocData.begin(), postHocData.end(), [](const std::pair<int, double>& a, const std::pair<int, double>& b) {
|
||||||
return a.second < b.second;
|
return a.second < b.second;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Holm adjustment
|
// Holm adjustment
|
||||||
for (int i = 0; i < statsOrder.size(); ++i) {
|
for (int i = 0; i < postHocData.size(); ++i) {
|
||||||
auto item = statsOrder.at(i);
|
auto item = postHocData.at(i);
|
||||||
double before = i == 0 ? 0.0 : statsOrder.at(i - 1).second;
|
double before = i == 0 ? 0.0 : postHocData.at(i - 1).second;
|
||||||
double p_value = std::min((double)1.0, item.second * (nModels - i));
|
double p_value = std::min((double)1.0, item.second * (nModels - i));
|
||||||
p_value = std::max(before, p_value);
|
p_value = std::max(before, p_value);
|
||||||
statsOrder[i] = { item.first, p_value };
|
postHocData[i] = { item.first, p_value };
|
||||||
}
|
}
|
||||||
holmResult.model = models.at(controlIdx);
|
postHocResult.model = models.at(controlIdx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Statistics::postHocTestReport(const std::string& kind, const std::string& metric, bool friedmanResult, bool tex)
|
||||||
|
{
|
||||||
|
|
||||||
|
std::stringstream oss;
|
||||||
|
postHocResult.model = models.at(controlIdx);
|
||||||
auto color = friedmanResult ? Colors::CYAN() : Colors::YELLOW();
|
auto color = friedmanResult ? Colors::CYAN() : Colors::YELLOW();
|
||||||
oss << color;
|
oss << color;
|
||||||
oss << " *************************************************************************************************************" << std::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 << " Post-hoc " << kind << " 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 << " 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::left << std::setw(maxModelName) << std::string("Model") << " p-value rank win tie loss Status" << std::endl;
|
||||||
oss << " " << std::string(maxModelName, '=') << " ============ ========= === === ==== =============" << std::endl;
|
oss << " " << std::string(maxModelName, '=') << " ============ ========= === === ==== =============" << std::endl;
|
||||||
@@ -175,12 +181,12 @@ namespace platform {
|
|||||||
for (const auto& item : ranksOrder) {
|
for (const auto& item : ranksOrder) {
|
||||||
auto idx = distance(models.begin(), find(models.begin(), models.end(), item.first));
|
auto idx = distance(models.begin(), find(models.begin(), models.end(), item.first));
|
||||||
double pvalue = 0.0;
|
double pvalue = 0.0;
|
||||||
for (const auto& stat : statsOrder) {
|
for (const auto& stat : postHocData) {
|
||||||
if (stat.first == idx) {
|
if (stat.first == idx) {
|
||||||
pvalue = stat.second;
|
pvalue = stat.second;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
holmResult.holmLines.push_back({ item.first, pvalue, item.second, wtl.at(idx), pvalue < significance });
|
postHocResult.postHocLines.push_back({ item.first, pvalue, item.second, wtl.at(idx), pvalue < significance });
|
||||||
if (item.first == models.at(controlIdx)) {
|
if (item.first == models.at(controlIdx)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -198,12 +204,77 @@ namespace platform {
|
|||||||
std::cout << oss.str();
|
std::cout << oss.str();
|
||||||
}
|
}
|
||||||
if (tex) {
|
if (tex) {
|
||||||
BestResultsTex bestResultsTex;
|
BestResultsTex bestResultsTex(metric);
|
||||||
BestResultsMd bestResultsMd;
|
BestResultsMd bestResultsMd;
|
||||||
bestResultsTex.holm_test(holmResult, get_date() + " " + get_time());
|
bestResultsTex.postHoc_test(postHocResult, kind, get_date() + " " + get_time());
|
||||||
bestResultsMd.holm_test(holmResult, get_date() + " " + get_time());
|
bestResultsMd.postHoc_test(postHocResult, kind, get_date() + " " + get_time());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// void Statistics::postHocDeLongTest(const std::vector<std::vector<int>>& y_trues,
|
||||||
|
// const std::vector<std::vector<std::vector<double>>>& y_probas,
|
||||||
|
// bool tex)
|
||||||
|
// {
|
||||||
|
// std::map<int, double> pvalues;
|
||||||
|
// postHocResult.model = models.at(controlIdx);
|
||||||
|
// postHocResult.postHocLines.clear();
|
||||||
|
|
||||||
|
// for (size_t i = 0; i < models.size(); ++i) {
|
||||||
|
// if ((int)i == controlIdx) continue;
|
||||||
|
// double acc_p = 0.0;
|
||||||
|
// int valid = 0;
|
||||||
|
// for (size_t d = 0; d < y_trues.size(); ++d) {
|
||||||
|
// try {
|
||||||
|
// auto result = compareModelsWithDeLong(y_probas[controlIdx][d], y_probas[i][d], y_trues[d]);
|
||||||
|
// acc_p += result.p_value;
|
||||||
|
// ++valid;
|
||||||
|
// }
|
||||||
|
// catch (...) {}
|
||||||
|
// }
|
||||||
|
// if (valid > 0) {
|
||||||
|
// pvalues[i] = acc_p / valid;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// std::vector<std::pair<int, double>> sorted_pvalues(pvalues.begin(), pvalues.end());
|
||||||
|
// std::sort(sorted_pvalues.begin(), sorted_pvalues.end(), [](const auto& a, const auto& b) {
|
||||||
|
// return a.second < b.second;
|
||||||
|
// });
|
||||||
|
|
||||||
|
// std::stringstream oss;
|
||||||
|
// oss << "\n*************************************************************************************************************\n";
|
||||||
|
// oss << " Post-hoc DeLong-Holm test: H0: 'No significant differences in AUC with control model.'\n";
|
||||||
|
// oss << " Control model: " << models[controlIdx] << "\n";
|
||||||
|
// oss << " " << std::left << std::setw(maxModelName) << std::string("Model") << " p-value Adjusted Result\n";
|
||||||
|
// oss << " " << std::string(maxModelName, '=') << " ============ ========== =============\n";
|
||||||
|
|
||||||
|
// double prev = 0.0;
|
||||||
|
// for (size_t i = 0; i < sorted_pvalues.size(); ++i) {
|
||||||
|
// int idx = sorted_pvalues[i].first;
|
||||||
|
// double raw = sorted_pvalues[i].second;
|
||||||
|
// double adj = std::min(1.0, raw * (models.size() - i - 1));
|
||||||
|
// adj = std::max(prev, adj);
|
||||||
|
// prev = adj;
|
||||||
|
// bool reject = adj < significance;
|
||||||
|
|
||||||
|
// postHocResult.postHocLines.push_back({ models[idx], adj, 0.0f, {}, reject });
|
||||||
|
|
||||||
|
// auto color = reject ? Colors::MAGENTA() : Colors::GREEN();
|
||||||
|
// auto status = reject ? Symbols::cross : Symbols::check_mark;
|
||||||
|
// auto textStatus = reject ? " rejected H0" : " accepted H0";
|
||||||
|
// oss << " " << color << std::left << std::setw(maxModelName) << models[idx] << " ";
|
||||||
|
// oss << std::setprecision(6) << std::scientific << raw << " ";
|
||||||
|
// oss << std::setprecision(6) << std::scientific << adj << " " << status << textStatus << "\n";
|
||||||
|
// }
|
||||||
|
// oss << Colors::CYAN() << " *************************************************************************************************************\n";
|
||||||
|
// oss << Colors::RESET();
|
||||||
|
// if (output) std::cout << oss.str();
|
||||||
|
// if (tex) {
|
||||||
|
// BestResultsTex bestResultsTex;
|
||||||
|
// BestResultsMd bestResultsMd;
|
||||||
|
// bestResultsTex.holm_test(postHocResult, get_date() + " " + get_time());
|
||||||
|
// bestResultsMd.holm_test(postHocResult, get_date() + " " + get_time());
|
||||||
|
// }
|
||||||
|
// }
|
||||||
bool Statistics::friedmanTest()
|
bool Statistics::friedmanTest()
|
||||||
{
|
{
|
||||||
if (!fitted) {
|
if (!fitted) {
|
||||||
@@ -249,9 +320,9 @@ namespace platform {
|
|||||||
{
|
{
|
||||||
return friedmanResult;
|
return friedmanResult;
|
||||||
}
|
}
|
||||||
HolmResult& Statistics::getHolmResult()
|
PostHocResult& Statistics::getPostHocResult()
|
||||||
{
|
{
|
||||||
return holmResult;
|
return postHocResult;
|
||||||
}
|
}
|
||||||
std::map<std::string, std::map<std::string, float>>& Statistics::getRanks()
|
std::map<std::string, std::map<std::string, float>>& Statistics::getRanks()
|
||||||
{
|
{
|
||||||
|
@@ -19,24 +19,25 @@ namespace platform {
|
|||||||
long double pvalue;
|
long double pvalue;
|
||||||
bool reject;
|
bool reject;
|
||||||
};
|
};
|
||||||
struct HolmLine {
|
struct PostHocLine {
|
||||||
std::string model;
|
std::string model;
|
||||||
long double pvalue;
|
long double pvalue;
|
||||||
double rank;
|
double rank;
|
||||||
WTL wtl;
|
WTL wtl;
|
||||||
bool reject;
|
bool reject;
|
||||||
};
|
};
|
||||||
struct HolmResult {
|
struct PostHocResult {
|
||||||
std::string model;
|
std::string model;
|
||||||
std::vector<HolmLine> holmLines;
|
std::vector<PostHocLine> postHocLines;
|
||||||
};
|
};
|
||||||
class Statistics {
|
class Statistics {
|
||||||
public:
|
public:
|
||||||
Statistics(const std::vector<std::string>& models, const std::vector<std::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();
|
bool friedmanTest();
|
||||||
void postHocHolmTest(bool friedmanResult, bool tex=false);
|
void postHocHolmTest();
|
||||||
|
void postHocTestReport(const std::string& kind, const std::string& metric, bool friedmanResult, bool tex);
|
||||||
FriedmanResult& getFriedmanResult();
|
FriedmanResult& getFriedmanResult();
|
||||||
HolmResult& getHolmResult();
|
PostHocResult& getPostHocResult();
|
||||||
std::map<std::string, std::map<std::string, float>>& getRanks();
|
std::map<std::string, std::map<std::string, float>>& getRanks();
|
||||||
private:
|
private:
|
||||||
void fit();
|
void fit();
|
||||||
@@ -53,10 +54,11 @@ namespace platform {
|
|||||||
int controlIdx = 0;
|
int controlIdx = 0;
|
||||||
std::map<int, WTL> wtl;
|
std::map<int, WTL> wtl;
|
||||||
std::map<std::string, float> ranks;
|
std::map<std::string, float> ranks;
|
||||||
|
std::vector<std::pair<int, double>> postHocData;
|
||||||
int maxModelName = 0;
|
int maxModelName = 0;
|
||||||
int maxDatasetName = 0;
|
int maxDatasetName = 0;
|
||||||
FriedmanResult friedmanResult;
|
FriedmanResult friedmanResult;
|
||||||
HolmResult holmResult;
|
PostHocResult postHocResult;
|
||||||
std::map<std::string, std::map<std::string, float>> ranksModels;
|
std::map<std::string, std::map<std::string, float>> ranksModels;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user