From ab81675e7247fdc58c8bc497f9af34c0a9f6deb1 Mon Sep 17 00:00:00 2001 From: luav Date: Thu, 16 May 2019 15:27:20 +0200 Subject: [PATCH] Mixed precision and recall fixed for F1, description refined --- args.ggo | 12 ++++++------ autogen/cmdline.c | 15 +++++++-------- autogen/cmdline.h | 19 ++++++++----------- include/interface.h | 18 +++++++++--------- include/interface.hpp | 44 +++++++++++++++++++++++-------------------- src/main.cpp | 22 +++++++++++----------- 6 files changed, 65 insertions(+), 65 deletions(-) diff --git a/args.ggo b/args.ggo index 79e67f2..79ff2cb 100644 --- a/args.ggo +++ b/args.ggo @@ -4,7 +4,7 @@ package "xmeasures" version "4.0.4" versiontext "Author: (c) Artem Lutov Sources: https://github.com/eXascaleInfolab/xmeasures -Paper: \"Accuracy Evaluation of Overlapping and Multi-resolution Clustering Algorithms on Large Datasets\" by Artem Lutov, Mourad Khayati and Philippe Cudré-Mauroux, BigComp 2018 +Paper: \"Accuracy Evaluation of Overlapping and Multi-resolution Clustering Algorithms on Large Datasets\" by Artem Lutov, Mourad Khayati and Philippe Cudré-Mauroux, BigComp 2019 " purpose "Extrinsic measures evaluation: Omega Index (a fuzzy version of the\ @@ -99,8 +99,8 @@ Precision and recall are evaluated relative to the FIRST clustering dataset (gro " values="partprob","harmonic","average" enum default="partprob" argoptional option "kind" k "kind of the matching policy: - - w - Weighted by the number of nodes in each cluster - - u - Unweighed, where each cluster is treated equally + - w - Weighted by the number of nodes in each cluster (known as micro weighting, MF1_micro) + - u - Unweighed, where each cluster is treated equally (known as macro weighting, MF1_macro) - c - Combined(w, u) using geometric mean (drops the value not so much as harmonic mean) " values ="weighted","unweighed","combined" enum default="weighted" argoptional @@ -115,7 +115,6 @@ NOTE: If 'sync' option is specified then the file name of the clusters labels\ The file name can be either a separate or an evaluating CNL file, in the\ latter case this option should precede the evaluating filename not repeating it. Precision and recall are evaluated relative to the FIRST clustering dataset (ground-truth, gold standard). - " string typestr="gt_filename" option "policy" p "Labels matching policy: @@ -124,7 +123,8 @@ option "policy" p "Labels matching policy: " values="partprob","harmonic" enum default="harmonic" argoptional dependon="label" option "unweighted" u "Labels weighting policy on F1 evaluation: weighted by the number\ - of instances in each label or unweighed, where each label is treated equally" + of instances in each label by default (micro weighting, F1_micro) or unweighed,\ + where each label is treated equally (i.e. macro weighting, F1_macro)" flag off dependon="label" option "identifiers" i "output labels (identifiers) of the evaluating clusters\ as lines of space-separated indices of the ground-truth clusters (.cll - clusters\ @@ -148,7 +148,7 @@ args "--default-optional --unamed-opts=clusterings" # = Changelog = -# v4.0.4 - Precision and recall added to the MF1 output +# v4.0.4 - Precision and recall added to the MF1 output, mixed Prc, Rec in F1 fixed # v4.0.3 - Renamed F1s -> F1a to be synced with the paper, description refined # v4.0.2 - Description and output measures notations refined # v4.0.1 - Aggregated output for multiple measures added diff --git a/autogen/cmdline.c b/autogen/cmdline.c index f24764b..275f16d 100644 --- a/autogen/cmdline.c +++ b/autogen/cmdline.c @@ -29,7 +29,7 @@ const char *gengetopt_args_info_purpose = "Extrinsic measures evaluation: Omega const char *gengetopt_args_info_usage = "Usage: xmeasures [OPTIONS] clustering1 clustering2\n\n clustering - input file, collection of the clusters to be evaluated.\n \nExamples:\n $ ./xmeasures -fp -kc networks/5K25.cnl tests/5K25_l0.825/5K25_l0.825_796.cnl\n $ ./xmeasures -fh -kc -i tests/5K25.cll -ph -l networks/5K25.cnl\ntests/5K25_l0.825/5K25_l0.825_796.cnl\n $ ./xmeasures -ox tests/clsevalsx/omega_c4.3-1.cnl\ntests/clsevalsx/omega_c4.3-2.cnl\n"; -const char *gengetopt_args_info_versiontext = "Author: (c) Artem Lutov \nSources: https://github.com/eXascaleInfolab/xmeasures\nPaper: \"Accuracy Evaluation of Overlapping and Multi-resolution Clustering\nAlgorithms on Large Datasets\" by Artem Lutov, Mourad Khayati and Philippe\nCudré-Mauroux, BigComp 2018\n"; +const char *gengetopt_args_info_versiontext = "Author: (c) Artem Lutov \nSources: https://github.com/eXascaleInfolab/xmeasures\nPaper: \"Accuracy Evaluation of Overlapping and Multi-resolution Clustering\nAlgorithms on Large Datasets\" by Artem Lutov, Mourad Khayati and Philippe\nCudré-Mauroux, BigComp 2019\n"; const char *gengetopt_args_info_description = "Extrinsic measures are evaluated, i.e. two input clusterings (collections of\nclusters) are compared to each other. Optionally, a labeling of the evaluating\nclusters with the specified ground-truth clusters is performed.\nNOTE:\n - Multiple evaluating measures can be specified.\n - Each cluster should contain unique members, which is ensured only if the\n'unique' option is specified.\n - All clusters should be unique to not affect Omega Index evaluation, which\ncan be ensured by the [resmerge](https://github.com/eXascaleInfolab/resmerge)\nutility.\n - Non-corrected unequal node base in the clusterings is allowed, it penalizes\nthe match.Use [OvpNMI](https://github.com/eXascaleInfolab/OvpNMI) or\n[GenConvNMI](https://github.com/eXascaleInfolab/GenConvNMI) for NMI evaluation\nin the arbitrary collections (still each cluster should contain unique\nmembers).\n\nEvaluating measures are:\n - OI - Omega Index (a fuzzy version of the Adjusted Rand Index, identical to\nthe Fuzzy Rand Index), which yields the same value as Adjusted Rand Index when\napplied to the non-overlapping clusterings.\n - [M]F1 - various [mean] F1 measures of the Greatest (Max) Match including\nthe Average F1-Score (suggested by J. Leskovec) with the optional weighting.\nNOTE: There are 3 matching policies available for each kind of F1. The most\nrepresentative evaluation is performed by the F1p with combined matching\npolicy (considers both micro and macro weighting).\n - NMI - Normalized Mutual Information, normalized by either max or also\nsqrt, avg and min information content denominators.\nATTENTION: This is a standard NMI, which should be used ONLY for the HARD\npartitioning evaluation (non-overlapping clustering on a single resolution).\nIt penalizes overlapping and multi-resolution structures.\n"; @@ -46,11 +46,11 @@ const char *gengetopt_args_info_help[] = { " -x, --extended evaluate extended (Soft) Omega Index, which\n does not excessively penalize distinctly\n shared nodes. (default=off)", "\nMean F1:", " -f, --f1[=ENUM] evaluate mean F1 of the [weighted] average of\n the greatest (maximal) match by F1 or partial\n probability.\n NOTE: F1h <= F1a, where:\n - p (F1p or Ph) - Harmonic mean (F1) of two\n [weighted] averages of the Partial\n Probabilities, the most indicative as\n satisfies the largest number of the Formal\n Constraints (homogeneity, completeness and\n size/quantity except the rag bag in some\n cases);\n - h (F1h) - Harmonic mean (F1) of two\n [weighted] averages of all local F1 (harmonic\n means of the Precision and Recall of the best\n matches of the clusters);\n - a (F1a) - Arithmetic mean (average) of\n two [weighted] averages of all local F1, the\n least discriminative and satisfies the lowest\n number of the Formal Constraints.\n Precision and recall are evaluated relative\n to the FIRST clustering dataset\n (ground-truth, gold standard).\n (possible values=\"partprob\",\n \"harmonic\", \"average\" default=`partprob')", - " -k, --kind[=ENUM] kind of the matching policy:\n - w - Weighted by the number of nodes in\n each cluster\n - u - Unweighed, where each cluster is\n treated equally\n - c - Combined(w, u) using geometric mean\n (drops the value not so much as harmonic\n mean)\n (possible values=\"weighted\",\n \"unweighed\", \"combined\"\n default=`weighted')", + " -k, --kind[=ENUM] kind of the matching policy:\n - w - Weighted by the number of nodes in\n each cluster (known as micro weighting,\n MF1_micro)\n - u - Unweighed, where each cluster is\n treated equally (known as macro weighting,\n MF1_macro)\n - c - Combined(w, u) using geometric mean\n (drops the value not so much as harmonic\n mean)\n (possible values=\"weighted\",\n \"unweighed\", \"combined\"\n default=`weighted')", "\nClusters Labeling & F1 evaluation with Precision and Recall:", - " -l, --label=gt_filename label evaluating clusters with the specified\n ground-truth (gt) cluster indices and\n evaluate F1 (including Precision and Recall)\n of the (best) MATCHED labeled clusters only\n (without the probable subclusters).\n NOTE: If 'sync' option is specified then the\n file name of the clusters labels should be\n the same as the node base (if specified) and\n should be in the .cnl format. The file name\n can be either a separate or an evaluating CNL\n file, in the latter case this option should\n precede the evaluating filename not repeating\n it.\n Precision and recall are evaluated relative\n to the FIRST clustering dataset\n (ground-truth, gold standard).\n\n", + " -l, --label=gt_filename label evaluating clusters with the specified\n ground-truth (gt) cluster indices and\n evaluate F1 (including Precision and Recall)\n of the (best) MATCHED labeled clusters only\n (without the probable subclusters).\n NOTE: If 'sync' option is specified then the\n file name of the clusters labels should be\n the same as the node base (if specified) and\n should be in the .cnl format. The file name\n can be either a separate or an evaluating CNL\n file, in the latter case this option should\n precede the evaluating filename not repeating\n it.\n Precision and recall are evaluated relative\n to the FIRST clustering dataset\n (ground-truth, gold standard).\n", " -p, --policy[=ENUM] Labels matching policy:\n - p - Partial Probabilities (maximizes\n gain)\n - h - Harmonic Mean (minimizes loss,\n maximizes F1)\n (possible values=\"partprob\", \"harmonic\"\n default=`harmonic')", - " -u, --unweighted Labels weighting policy on F1 evaluation:\n weighted by the number of instances in each\n label or unweighed, where each label is\n treated equally (default=off)", + " -u, --unweighted Labels weighting policy on F1 evaluation:\n weighted by the number of instances in each\n label by default (micro weighting, F1_micro)\n or unweighed, where each label is treated\n equally (i.e. macro weighting, F1_macro)\n (default=off)", " -i, --identifiers=labels_filename\n output labels (identifiers) of the evaluating\n clusters as lines of space-separated indices\n of the ground-truth clusters (.cll - clusters\n labels list)\n NOTE: If 'sync' option is specified then the\n reduced collection is outputted to the\n .cnl besides the\n \n", "\nNMI:", " -n, --nmi evaluate NMI (Normalized Mutual Information),\n applicable only to the non-overlapping\n clusters (default=off)", @@ -826,8 +826,8 @@ cmdline_parser_internal ( break; case 'k': /* kind of the matching policy: - - w - Weighted by the number of nodes in each cluster - - u - Unweighed, where each cluster is treated equally + - w - Weighted by the number of nodes in each cluster (known as micro weighting, MF1_micro) + - u - Unweighed, where each cluster is treated equally (known as macro weighting, MF1_macro) - c - Combined(w, u) using geometric mean (drops the value not so much as harmonic mean) . */ @@ -844,7 +844,6 @@ cmdline_parser_internal ( case 'l': /* label evaluating clusters with the specified ground-truth (gt) cluster indices and evaluate F1 (including Precision and Recall) of the (best) MATCHED labeled clusters only (without the probable subclusters). NOTE: If 'sync' option is specified then the file name of the clusters labels should be the same as the node base (if specified) and should be in the .cnl format. The file name can be either a separate or an evaluating CNL file, in the latter case this option should precede the evaluating filename not repeating it. Precision and recall are evaluated relative to the FIRST clustering dataset (ground-truth, gold standard). - . */ @@ -872,7 +871,7 @@ cmdline_parser_internal ( goto failure; break; - case 'u': /* Labels weighting policy on F1 evaluation: weighted by the number of instances in each label or unweighed, where each label is treated equally. */ + case 'u': /* Labels weighting policy on F1 evaluation: weighted by the number of instances in each label by default (micro weighting, F1_micro) or unweighed, where each label is treated equally (i.e. macro weighting, F1_macro). */ if (update_arg((void *)&(args_info->unweighted_flag), 0, &(args_info->unweighted_given), diff --git a/autogen/cmdline.h b/autogen/cmdline.h index df7fe0e..4930cf4 100644 --- a/autogen/cmdline.h +++ b/autogen/cmdline.h @@ -86,34 +86,31 @@ struct gengetopt_args_info Precision and recall are evaluated relative to the FIRST clustering dataset (ground-truth, gold standard). help description. */ enum enum_kind kind_arg; /**< @brief kind of the matching policy: - - w - Weighted by the number of nodes in each cluster - - u - Unweighed, where each cluster is treated equally + - w - Weighted by the number of nodes in each cluster (known as micro weighting, MF1_micro) + - u - Unweighed, where each cluster is treated equally (known as macro weighting, MF1_macro) - c - Combined(w, u) using geometric mean (drops the value not so much as harmonic mean) (default='weighted'). */ char * kind_orig; /**< @brief kind of the matching policy: - - w - Weighted by the number of nodes in each cluster - - u - Unweighed, where each cluster is treated equally + - w - Weighted by the number of nodes in each cluster (known as micro weighting, MF1_micro) + - u - Unweighed, where each cluster is treated equally (known as macro weighting, MF1_macro) - c - Combined(w, u) using geometric mean (drops the value not so much as harmonic mean) original value given at command line. */ const char *kind_help; /**< @brief kind of the matching policy: - - w - Weighted by the number of nodes in each cluster - - u - Unweighed, where each cluster is treated equally + - w - Weighted by the number of nodes in each cluster (known as micro weighting, MF1_micro) + - u - Unweighed, where each cluster is treated equally (known as macro weighting, MF1_macro) - c - Combined(w, u) using geometric mean (drops the value not so much as harmonic mean) help description. */ char * label_arg; /**< @brief label evaluating clusters with the specified ground-truth (gt) cluster indices and evaluate F1 (including Precision and Recall) of the (best) MATCHED labeled clusters only (without the probable subclusters). NOTE: If 'sync' option is specified then the file name of the clusters labels should be the same as the node base (if specified) and should be in the .cnl format. The file name can be either a separate or an evaluating CNL file, in the latter case this option should precede the evaluating filename not repeating it. Precision and recall are evaluated relative to the FIRST clustering dataset (ground-truth, gold standard). - . */ char * label_orig; /**< @brief label evaluating clusters with the specified ground-truth (gt) cluster indices and evaluate F1 (including Precision and Recall) of the (best) MATCHED labeled clusters only (without the probable subclusters). NOTE: If 'sync' option is specified then the file name of the clusters labels should be the same as the node base (if specified) and should be in the .cnl format. The file name can be either a separate or an evaluating CNL file, in the latter case this option should precede the evaluating filename not repeating it. Precision and recall are evaluated relative to the FIRST clustering dataset (ground-truth, gold standard). - original value given at command line. */ const char *label_help; /**< @brief label evaluating clusters with the specified ground-truth (gt) cluster indices and evaluate F1 (including Precision and Recall) of the (best) MATCHED labeled clusters only (without the probable subclusters). NOTE: If 'sync' option is specified then the file name of the clusters labels should be the same as the node base (if specified) and should be in the .cnl format. The file name can be either a separate or an evaluating CNL file, in the latter case this option should precede the evaluating filename not repeating it. Precision and recall are evaluated relative to the FIRST clustering dataset (ground-truth, gold standard). - help description. */ enum enum_policy policy_arg; /**< @brief Labels matching policy: - p - Partial Probabilities (maximizes gain) @@ -127,8 +124,8 @@ struct gengetopt_args_info - p - Partial Probabilities (maximizes gain) - h - Harmonic Mean (minimizes loss, maximizes F1) help description. */ - int unweighted_flag; /**< @brief Labels weighting policy on F1 evaluation: weighted by the number of instances in each label or unweighed, where each label is treated equally (default=off). */ - const char *unweighted_help; /**< @brief Labels weighting policy on F1 evaluation: weighted by the number of instances in each label or unweighed, where each label is treated equally help description. */ + int unweighted_flag; /**< @brief Labels weighting policy on F1 evaluation: weighted by the number of instances in each label by default (micro weighting, F1_micro) or unweighed, where each label is treated equally (i.e. macro weighting, F1_macro) (default=off). */ + const char *unweighted_help; /**< @brief Labels weighting policy on F1 evaluation: weighted by the number of instances in each label by default (micro weighting, F1_micro) or unweighed, where each label is treated equally (i.e. macro weighting, F1_macro) help description. */ char * identifiers_arg; /**< @brief output labels (identifiers) of the evaluating clusters as lines of space-separated indices of the ground-truth clusters (.cll - clusters labels list) NOTE: If 'sync' option is specified then the reduced collection is outputted to the .cnl besides the . */ diff --git a/include/interface.h b/include/interface.h index 5367ba6..d705f7c 100644 --- a/include/interface.h +++ b/include/interface.h @@ -536,12 +536,12 @@ bool xwmatch(Match m) noexcept; bool xumatch(Match m) noexcept; //! Precision and recall -struct PrecRec { - Prob prec; //!< Precision +struct PrcRec { + Prob prc; //!< Precision Prob rec; //!< Recall // Explicit members initialization by value to avoid uninitialized members - PrecRec(Prob prec=0, Prob rec=0): prec(prec), rec(rec) {} + PrcRec(Prob prc=0, Prob rec=0): prc(prc), rec(rec) {} }; //! Collection describing cluster-node relations @@ -640,8 +640,8 @@ class Collection: public NodeBaseI { //! treat each label equally //! \param flname=nullptr const char* - resulting label indices filename (.cll format) //! \param verbose=false bool - print intermediate results to the stdout - //! \return PrecRec - resulting precision and recall for the labeled items - static PrecRec label(const CollectionT& gt, const CollectionT& cn, const RawIds& lostcls + //! \return PrcRec - resulting precision and recall for the labeled items + static PrcRec label(const CollectionT& gt, const CollectionT& cn, const RawIds& lostcls , bool prob, bool weighted=true, const char* flname=nullptr, bool verbose=false); //! \brief Specified F1 evaluation of the Greatest (Max) Match for the @@ -664,13 +664,13 @@ class Collection: public NodeBaseI { //! \param kind F1 - kind of F1 to be evaluated //! \param rec Prob& - recall of cn2 relative to the ground-truth cn1 or //! 0 if the matching strategy does not have the precision/recall notations - //! \param prec Prob& - precision of cn2 relative to the ground-truth cn1 or + //! \param prc Prob& - precision of cn2 relative to the ground-truth cn1 or //! 0 if the matching strategy does not have the precision/recall notations //! \param mkind=Match::WEIGHTED Match - matching kind //! \param verbose=false bool - print intermediate results to the stdout //! \return Prob - resulting F1_gm static Prob f1(const CollectionT& cn1, const CollectionT& cn2, F1 kind - , Prob& rec, Prob& prec, Match mkind=Match::WEIGHTED, bool verbose=false); + , Prob& rec, Prob& prc, Match mkind=Match::WEIGHTED, bool verbose=false); //! \brief NMI evaluation //! \note Undirected (symmetric) evaluation @@ -697,11 +697,11 @@ class Collection: public NodeBaseI { //! treat each label equally //! \param csls=nullptr ClsLabels* - resulting labels as clusters of the //! ground-truth collection if not nullptr - //! \return PrecRec - resulting average over all labels Precision and Recall + //! \return PrcRec - resulting average over all labels Precision and Recall //! for all nodes of the marked clusters, where each label can be assigned //! to multiple cn clusters and then all nodes of that clusters are matched //! to the ground truth cluster (label) nodes - PrecRec mark(const CollectionT& cn, bool prob, bool weighted=true, ClsLabels* csls=nullptr) const; + PrcRec mark(const CollectionT& cn, bool prob, bool weighted=true, ClsLabels* csls=nullptr) const; // F1-related functions ---------------------------------------------------- //! \brief Average of the maximal matches (by F1 or partial probabilities) diff --git a/include/interface.hpp b/include/interface.hpp index 55f110d..8fa82cc 100644 --- a/include/interface.hpp +++ b/include/interface.hpp @@ -408,7 +408,7 @@ void Collection::clearcounts() const noexcept } template -PrecRec Collection::label(const CollectionT& gt, const CollectionT& cn, const RawIds& lostcls +PrcRec Collection::label(const CollectionT& gt, const CollectionT& cn, const RawIds& lostcls , bool prob, bool weighted, const char* flname, bool verbose) { // Initialized accessory data for evaluations if has not been done yet @@ -463,7 +463,7 @@ PrecRec Collection::label(const CollectionT& gt, const CollectionT& cn, c } template -PrecRec Collection::mark(const CollectionT& cn, bool prob, bool weighted, ClsLabels* csls) const +PrcRec Collection::mark(const CollectionT& cn, bool prob, bool weighted, ClsLabels* csls) const { // Reserve space for all clusters of the collection (but not more than the number of labels) to avoid reallocations if(csls) @@ -477,7 +477,7 @@ PrecRec Collection::mark(const CollectionT& cn, bool prob, bool weighted, using MarkNodes = unordered_set; MarkNodes mnds; // Aggregated precision and recall - AccProb prec = 0; + AccProb prc = 0; AccProb rec = 0; #if TRACE >= 2 Id nmlbs = 0; // The number of labels with multiple clusters @@ -557,8 +557,13 @@ PrecRec Collection::mark(const CollectionT& cn, bool prob, bool weighted, AccProb gm = mcl.counter(); // Matches if(weighted) gm *= gtc->members.size(); - prec += gm / static_cast(m_overlaps ? gtc->cont() : gtc->members.size()); - rec += gm / static_cast(m_overlaps ? mcl.cont() : mcl.members.size()); + prc += gm / static_cast(m_overlaps ? mcl.cont() : mcl.members.size()); + rec += gm / static_cast(m_overlaps ? gtc->cont() : gtc->members.size()); +#if TRACE >= 3 + printf(" > mark(), gmatch: %G, gm: %G, accumulated prc: %G (mcl cont: %G), rec: %G (gtc cont: %G)\n" + , gmatch, gm, prc, static_cast(m_overlaps ? mcl.cont() : mcl.members.size()) + , rec, static_cast(m_overlaps ? gtc->cont() : gtc->members.size())); +#endif // TRACE } else { // The label marked multiple clusters, compared it's nodes with the // nodes of the merged respective clusters @@ -578,9 +583,9 @@ PrecRec Collection::mark(const CollectionT& cn, bool prob, bool weighted, #endif // TRACE if(weighted) accgm *= gtc->members.size(); - prec += accgm / static_cast(gtc->cont()); + prc += accgm / static_cast(accont); // Note: mnds.size() <= mcands.size() - rec += accgm / static_cast(accont); + rec += accgm / static_cast(gtc->cont()); } else { // Evaluate the number of matched nodes from the aggregated clusters (<= sum(cls_matches)) for(auto nid: gtc->members) @@ -591,8 +596,8 @@ PrecRec Collection::mark(const CollectionT& cn, bool prob, bool weighted, #endif // TRACE if(weighted) accgm *= gtc->members.size(); - prec += accgm / static_cast(gtc->members.size()); - rec += accgm / static_cast(mnds.size()); + prc += accgm / static_cast(mnds.size()); + rec += accgm / static_cast(gtc->members.size()); } mnds.clear(); } @@ -612,7 +617,7 @@ PrecRec Collection::mark(const CollectionT& cn, bool prob, bool weighted, assert(equal(accw, m_cls.size()) && "mark(), total weight on unweighted eval" " should be equal to the number of labels"); #endif // VALIDATE - return PrecRec(prec / accw, rec / accw); + return PrcRec(prc / accw, rec / accw); } template @@ -635,7 +640,7 @@ void Collection::initconts(const CollectionT& cn) noexcept template Prob Collection::f1(const CollectionT& cn1, const CollectionT& cn2, F1 kind - , Prob& rec, Prob& prec, Match mkind, bool verbose) + , Prob& rec, Prob& prc, Match mkind, bool verbose) { if(kind == F1::NONE || mkind == Match::NONE) { fputs("WARNING f1(), f1 or match kind is not specified, the evaluation is skipped\n", stderr); @@ -658,26 +663,25 @@ Prob Collection::f1(const CollectionT& cn1, const CollectionT& cn2, F1 ki // it should be called only once for each collection and with the same value of prob const auto gmats1 = cn1.gmatches(cn2, prob); const AccProb f1ga1 = cn1.avggms(gmats1, mkind==Match::WEIGHTED); - rec = f1ga1; + prc = f1ga1; // cn1 (ground-truth) relative to cn2 #if TRACE >= 3 fputs("f1(), F1 Max Avg of the second collection\n", stderr); #endif // TRACE const auto gmats2 = cn2.gmatches(cn1, prob); const AccProb f1ga2 = cn2.avggms(gmats2, mkind==Match::WEIGHTED); if(kind != F1::AVERAGE) - prec = f1ga2; - else rec = prec = 0; // Note: Precision and recall are not defined for the MF1a -#if TRACE <= 1 - if(verbose) -#endif // TRACE - fprintf(verbose ? stdout : stderr, "f1(), f1ga1: %G, f1ga2: %G\n", f1ga1, f1ga2); + rec = f1ga2; // cn2 relative to cn1 (ground-truth) + else prc = rec = 0; // Note: Precision and recall are not defined for the MF1a const AccProb res = kind != F1::AVERAGE ? hmean(f1ga1, f1ga2) : (f1ga1 + f1ga2) / 2; - fprintf(verbose ? stdout : stderr, "f1(), f1ga: %G\n", res); +#if TRACE <= 1 + if(verbose) +#endif // TRACE + fprintf(verbose ? stdout : stderr, "f1(), f1ga: %G (f1ga1: %G, f1ga2: %G)\n", res, f1ga1, f1ga2); if(mkind == Match::COMBINED) { - rec = prec = 0; // There are no precision and recall notations for combined matching strategy + prc = rec = 0; // There are no precision and recall notations for combined matching strategy // ATTENTION: gmats already evaluated and should be reused, their reevaluation would // affect internal states of the collections (counters) and requires reset of the state const AccProb f1ga1w = cn1.avggms(gmats1, true); diff --git a/src/main.cpp b/src/main.cpp index d8503a6..183d587 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -190,20 +190,20 @@ int main(int argc, char **argv) //if(args_info.nmi_flag) // fputs("; ", stdout); - Prob prec, rec; // Precision and recall of cn2 relative to ground-truth cn1 - const auto f1val = Collection::f1(cn1, cn2, f1kind, rec, prec, mkind, args_info.detailed_flag); + Prob prc, rec; // Precision and recall of cn2 relative to ground-truth cn1 + const auto f1val = Collection::f1(cn1, cn2, f1kind, rec, prc, mkind, args_info.detailed_flag); printf("MF1%c_%c (%s, %s):\n%G", f1suf, kindsuf, to_string(f1kind).c_str() , to_string(mkind).c_str(), f1val); - if(prec || rec) - printf(" (Prc: %G, Rec: %G)", prec, rec); + if(prc || rec) + printf(" (Prc: %G, Rec: %G)", prc, rec); fputc('\n', stdout); if(--outsnum || aggouts.tellp()) { if(aggouts.tellp()) aggouts << "; "; aggouts << "MF1" << f1suf << '_' << kindsuf << ": " << f1val; - // Note: prec and rec are zeroized if the matching strategy does not support them - if(prec || rec) - aggouts << " (Prc: " << prec << ", Rec: " << rec << ')'; + // Note: prc and rec are zeroized if the matching strategy does not support them + if(prc || rec) + aggouts << " (Prc: " << prc << ", Rec: " << rec << ')'; } } // Label clusters with the ground-truth clusters indices and output F1 for the labels if required @@ -219,19 +219,19 @@ int main(int argc, char **argv) } const bool prob = args_info.policy_arg == policy_arg_partprob; // Partial Probabilities matching policy const bool weighted = !args_info.unweighted_flag; - PrecRec pr = Collection::label(cn1, cn2, lostcls, prob, weighted + PrcRec pr = Collection::label(cn1, cn2, lostcls, prob, weighted , args_info.identifiers_arg, args_info.detailed_flag); // Note: each measure name should form a single world to be properly parsed in a uniform way (see Clubmark), // that is why doubled underscore is used rather than a single space. printf("F1%c_%c__labels: %G (Prc: %G, Rec: %G)\n" , prob ? 'p' : 'h', weighted ? 'w' : 'u' - , hmean(pr.prec, pr.rec), pr.prec, pr.rec); + , hmean(pr.prc, pr.rec), pr.prc, pr.rec); if(--outsnum || aggouts.tellp()) { if(aggouts.tellp()) aggouts << "; "; aggouts << "F1" << (prob ? 'p' : 'h') << '_' << (weighted ? 'w' : 'u') - << "__labels: " << hmean(pr.prec, pr.rec) - << " (Prc: " << pr.prec << ", Rec: " << pr.rec << ')'; + << "__labels: " << hmean(pr.prc, pr.rec) + << " (Prc: " << pr.prc << ", Rec: " << pr.rec << ')'; } } if(args_info.omega_flag) {