//------------------------------------------------------------------- // Author........: Aleksander Øhrn // Date..........: 9903/9904 // Description...: Simple utility that enables hypothesis testing to // to be done from the DOS command line. // Revisions.....: //=================================================================== #include #include #include #include //------------------------------------------------------------------- // Method........: PrintUsageAndExit // Author........: Aleksander Øhrn // Date..........: 9904 // Description...: // Comments......: // Revisions.....: //=================================================================== void PrintUsageAndExit(int argc, char *argv[]) { cout << "Usage: " << argv[0] << " [ ]" << endl; cout << " HanleyMcNeil parameters: " << endl; cout << " McNemar parameters: " << endl; exit(0); } //------------------------------------------------------------------- // Method........: PrintMcNemar // Author........: Aleksander Øhrn // Date..........: 9904 // Description...: // Comments......: // Revisions.....: //=================================================================== void PrintMcNemar(const McNemarComparator &comparator) { String n_a_string = (comparator.GetNa() != Undefined::Integer()) ? String::Format(comparator.GetNa()) : Undefined::String(); String n_b_string = (comparator.GetNb() != Undefined::Integer()) ? String::Format(comparator.GetNb()) : Undefined::String(); String n_c_string = (comparator.GetNc() != Undefined::Integer()) ? String::Format(comparator.GetNc()) : Undefined::String(); String n_d_string = (comparator.GetNd() != Undefined::Integer()) ? String::Format(comparator.GetNd()) : Undefined::String(); String z_string = (comparator.GetZ() != Undefined::Float()) ? String::Format(comparator.GetZ()) : Undefined::String(); String p2s_string = (z_string != Undefined::String() && comparator.GetP() != Undefined::Float()) ? String::Format(comparator.GetP()) : Undefined::String(); cout << "N(a) = " << n_a_string << endl; cout << "N(b) = " << n_b_string << endl; cout << "N(c) = " << n_c_string << endl; cout << "N(d) = " << n_d_string << endl; cout << "Z = " << z_string << endl; cout << "p < " << p2s_string << " (2-sided)" << endl; } //------------------------------------------------------------------- // Method........: PrintHanleyMcNeil // Author........: Aleksander Øhrn // Date..........: 9903 // Description...: // Comments......: // Revisions.....: //=================================================================== void PrintHanleyMcNeil(const HanleyMcNeilComparator &comparator) { String auc1_string = (comparator.GetAUC1() != Undefined::Float()) ? String::Format(comparator.GetAUC1()) : Undefined::String(); String auc2_string = (comparator.GetAUC2() != Undefined::Float()) ? String::Format(comparator.GetAUC2()) : Undefined::String(); String se1_string = (comparator.GetSE1() != Undefined::Float()) ? String::Format(comparator.GetSE1()) : Undefined::String(); String se2_string = (comparator.GetSE2() != Undefined::Float()) ? String::Format(comparator.GetSE2()) : Undefined::String(); String corr0s_string = (comparator.GetCorrelation0s() != Undefined::Float()) ? String::Format(comparator.GetCorrelation0s()) : Undefined::String(); String corr1s_string = (comparator.GetCorrelation1s() != Undefined::Float()) ? String::Format(comparator.GetCorrelation1s()) : Undefined::String(); String r_string = (comparator.GetR() != Undefined::Float()) ? String::Format(comparator.GetR()) : Undefined::String(); String z_string = (comparator.GetZ() != Undefined::Float()) ? String::Format(comparator.GetZ()) : Undefined::String(); String p2s_string = (z_string != Undefined::String() && comparator.GetP() != Undefined::Float()) ? String::Format(comparator.GetP()) : Undefined::String(); cout << "Classifier 1, AUC = " << auc1_string << endl; cout << "Classifier 2, AUC = " << auc2_string << endl; cout << "Classifier 1, SE = " << se1_string << endl; cout << "Classifier 2, SE = " << se2_string << endl; cout << "Correlation between 0s = " << corr0s_string << endl; cout << "Correlation between 1s = " << corr1s_string << endl; cout << "r = " << r_string << endl; cout << "Z = " << z_string << endl; cout << "p < " << p2s_string << " (2-sided)" << endl; } //------------------------------------------------------------------- // Method........: DoHanleyMcNeil // Author........: Aleksander Øhrn // Date..........: 9903 // Description...: // Comments......: // Revisions.....: //=================================================================== void DoHanleyMcNeil(const String &correlation, const String &cindex, const String &filename1, const String &filename2, bool swapped1, bool swapped2) { Vector(String) filenames; filenames.reserve(2); Vector(bool) swapped; swapped.reserve(2); filenames.push_back(filename1); filenames.push_back(filename2); swapped.push_back(swapped1); swapped.push_back(swapped2); HanleyMcNeilComparator hmc; if (correlation == "PEARSON") { HanleyMcNeilComparator hmc1(filenames, swapped, HanleyMcNeilComparator::CORRELATION_PEARSON, cindex == "CINDEX"); PrintHanleyMcNeil(hmc1); } else { HanleyMcNeilComparator hmc2(filenames, swapped, HanleyMcNeilComparator::CORRELATION_KENDALL, cindex == "CINDEX"); PrintHanleyMcNeil(hmc2); } } //------------------------------------------------------------------- // Method........: DoMcNemar // Author........: Aleksander Øhrn // Date..........: 9904 // Description...: // Comments......: // Revisions.....: //=================================================================== void DoMcNemar(float threshold1, float threshold2, const String &filename1, const String &filename2, bool swapped1, bool swapped2) { Vector(String) filenames; filenames.reserve(2); Vector(bool) swapped; swapped.reserve(2); filenames.push_back(filename1); filenames.push_back(filename2); swapped.push_back(swapped1); swapped.push_back(swapped2); McNemarComparator mnc(filenames, swapped, threshold1, threshold2); PrintMcNemar(mnc); } //------------------------------------------------------------------- // Method........: main // Author........: Aleksander Øhrn // Date..........: 9903 // Description...: // Comments......: The current handling of command-line options is // very ugly and ad hoc. Use getopt instead. // Revisions.....: //=================================================================== int main(int argc, char *argv[]) { int i; // Write some yada yada. cout << "This is command-line HYPOCLASS." << endl; cout << "Compiled " << __DATE__ << " " << __TIME__ << "." << endl; // Expected number of arguments? if (argc < 2) PrintUsageAndExit(argc, argv); String test(argv[1]); test.ToUppercase(); Vector(String) parameters; // Parse test and acquire parameters. if (test == "HANLEYMCNEIL") { if (argc != 6 && argc != 8) { Message::Error("Invalid number of arguments."); PrintUsageAndExit(argc, argv); } parameters.push_back(argv[2]); parameters.push_back(argv[3]); } else if (test == "MCNEMAR") { if (argc != 6 && argc != 8) { Message::Error("Invalid number of arguments."); PrintUsageAndExit(argc, argv); } parameters.push_back(argv[2]); parameters.push_back(argv[3]); } else { PrintUsageAndExit(argc, argv); } String concatenated; // Allow case-insensitivity. for (i = 0; i < parameters.size(); i++) { parameters[i].ToUppercase(); concatenated += parameters[i]; if (i < parameters.size() - 1) concatenated += ' '; } // Parse parameters. if (test == "HANLEYMCNEIL") { if (parameters[0] != "PEARSON" && parameters[0] != "KENDALL") { Message::Error("Invalid parameter: " + parameters[0]); PrintUsageAndExit(argc, argv); } if (parameters[1] != "CINDEX" && parameters[1] != "TRAPEZOIDAL") { Message::Error("Invalid parameter: " + parameters[1]); PrintUsageAndExit(argc, argv); } } else if (test == "MCNEMAR") { if (!parameters[0].IsFloat()) { Message::Error("Invalid parameter: " + parameters[0]); PrintUsageAndExit(argc, argv); } if (!parameters[1].IsFloat()) { Message::Error("Invalid parameter: " + parameters[1]); PrintUsageAndExit(argc, argv); } } else { } String filename1(argv[2 + parameters.size()]); String filename2(argv[3 + parameters.size()]); String swapped1("F"); String swapped2("F"); // Parse reverse flags, if given. if (argc == 6 + parameters.size()) { swapped1 = argv[argc - 2]; swapped2 = argv[argc - 1]; if (!swapped1.IsBoolean() || !swapped2.IsBoolean()) { Message::Error("Invalid swap flags."); PrintUsageAndExit(argc, argv); } } // Write some yada yada. cout << "Test = " << test << endl; cout << "Parameters = " << concatenated << endl; cout << "Classifier 1 = " << filename1 << endl; cout << "Classifier 2 = " << filename2 << endl; cout << "Swapped 1 = " << String::Format(swapped1.GetBoolean()) << endl; cout << "Swapped 2 = " << String::Format(swapped2.GetBoolean()) << endl; // Do test. if (test == "HANLEYMCNEIL") { DoHanleyMcNeil(parameters[0], parameters[1], filename1, filename2, swapped1.GetBoolean(), swapped2.GetBoolean()); } else if (test == "MCNEMAR") { DoMcNemar(parameters[0].GetFloat(), parameters[1].GetFloat(), filename1, filename2, swapped1.GetBoolean(), swapped2.GetBoolean()); } else { PrintUsageAndExit(argc, argv); } return 1; }