1 /**
2  * @file core/cv/metrics/f1_impl.hpp
3  * @author Kirill Mishchenko
4  *
5  * Implementation of the class F1.
6  *
7  * mlpack is free software; you may redistribute it and/or modify it under the
8  * terms of the 3-clause BSD license.  You should have received a copy of the
9  * 3-clause BSD license along with mlpack.  If not, see
10  * http://www.opensource.org/licenses/BSD-3-Clause for more information.
11  */
12 #ifndef MLPACK_CORE_CV_METRICS_F1_IMPL_HPP
13 #define MLPACK_CORE_CV_METRICS_F1_IMPL_HPP
14 
15 #include <mlpack/core/cv/metrics/accuracy.hpp>
16 #include <mlpack/core/cv/metrics/facilities.hpp>
17 
18 namespace mlpack {
19 namespace cv {
20 
21 template<AverageStrategy AS, size_t PC /* PositiveClass */>
22 template<typename MLAlgorithm, typename DataType>
Evaluate(MLAlgorithm & model,const DataType & data,const arma::Row<size_t> & labels)23 double F1<AS, PC>::Evaluate(MLAlgorithm& model,
24                             const DataType& data,
25                             const arma::Row<size_t>& labels)
26 {
27   return Evaluate<AS>(model, data, labels);
28 }
29 
30 template<AverageStrategy AS, size_t PC /* PositiveClass */>
31 template<AverageStrategy _AS, typename MLAlgorithm, typename DataType, typename>
Evaluate(MLAlgorithm & model,const DataType & data,const arma::Row<size_t> & labels)32 double F1<AS, PC>::Evaluate(MLAlgorithm& model,
33                             const DataType& data,
34                             const arma::Row<size_t>& labels)
35 {
36   AssertSizes(data, labels, "F1<Binary>::Evaluate()");
37 
38   arma::Row<size_t> predictedLabels;
39   model.Classify(data, predictedLabels);
40 
41   size_t tp = arma::sum((labels == PC) % (predictedLabels == PC));
42   size_t numberOfPositivePredictions = arma::sum(predictedLabels == PC);
43   size_t numberOfPositiveClassInstances = arma::sum(labels == PC);
44 
45   double precision = double(tp) / numberOfPositivePredictions;
46   double recall = double(tp) / numberOfPositiveClassInstances;
47 
48   return (precision + recall == 0.0) ? 0.0 :
49       2.0 * precision * recall / (precision + recall);
50 }
51 
52 template<AverageStrategy AS, size_t PC /* PositiveClass */>
53 template<AverageStrategy _AS, typename MLAlgorithm, typename DataType, typename,
54     typename>
Evaluate(MLAlgorithm & model,const DataType & data,const arma::Row<size_t> & labels)55 double F1<AS, PC>::Evaluate(MLAlgorithm& model,
56                             const DataType& data,
57                             const arma::Row<size_t>& labels)
58 {
59   AssertSizes(data, labels, "F1<Micro>::Evaluate()");
60 
61   // Microaveraged F1 is really the same as microaveraged precision and
62   // microaveraged recall, which are in turn the same as accuracy.
63   return Accuracy::Evaluate(model, data, labels);
64 }
65 
66 template<AverageStrategy AS, size_t PC /* PositiveClass */>
67 template<AverageStrategy _AS, typename MLAlgorithm, typename DataType, typename,
68     typename, typename>
Evaluate(MLAlgorithm & model,const DataType & data,const arma::Row<size_t> & labels)69 double F1<AS, PC>::Evaluate(MLAlgorithm& model,
70                             const DataType& data,
71                             const arma::Row<size_t>& labels)
72 {
73   AssertSizes(data, labels, "F1<Macro>::Evaluate()");
74 
75   arma::Row<size_t> predictedLabels;
76   model.Classify(data, predictedLabels);
77 
78   size_t numClasses = arma::max(labels) + 1;
79 
80   arma::vec f1s = arma::vec(numClasses);
81   for (size_t c = 0; c < numClasses; ++c)
82   {
83     size_t tp = arma::sum((labels == c) % (predictedLabels == c));
84     size_t positivePredictions = arma::sum(predictedLabels == c);
85     size_t positiveLabels = arma::sum(labels == c);
86 
87     double precision = double(tp) / positivePredictions;
88     double recall = double(tp) / positiveLabels;
89     f1s(c) = (precision + recall == 0.0) ? 0.0 :
90         2.0 * precision * recall / (precision + recall);
91   }
92 
93   return arma::mean(f1s);
94 }
95 
96 } // namespace cv
97 } // namespace mlpack
98 
99 #endif
100