Permalink
Browse files

Added missing measures and operators in Detector::Threshold, finished…

… optimal threshold search and small errors fixes + test
  • Loading branch information...
1 parent 8aa009d commit 61d1e512036d699b4c78ff0d435d48d05fc1116c @hamstah committed Mar 16, 2012
Showing with 74 additions and 13 deletions.
  1. +10 −8 Detector.cpp
  2. +48 −4 Detector.h
  3. +16 −1 tests/TestDetector.cpp
View
@@ -31,34 +31,36 @@ Detector::Threshold Detector::evaluateThresholdValue(float threshold) const
bool lut = m_hs.normalizedValue(i) >= threshold;
result.truePositive += lut * m_hs.value(i);
result.falsePositive += lut * m_hc.value(i);
+ result.positiveCount += m_hs.value(i);
+ result.negativeCount += m_hc.value(i);
}
return result;
}
-Detector::Threshold Detector::computeOptimalThreshold(unsigned int steps, float minimumPositiveRate, float maximumNegativeRate) const
+Detector::Threshold Detector::computeOptimalThreshold(unsigned int steps, float minimumTruePositiveRate, float maximumFalseNegativeRate) const
{
const float delta = 1.0/steps;
float threshold = 0.0f;
- const int minPositiveCount = minimumPositiveRate*m_hs.sum();
- const int maxNegativeCount = maximumNegativeRate*m_hs.sum();
-
+ const int minTruePositiveCount = minimumTruePositiveRate*m_hs.sum();
+ const int maxFalseNegativeCount = maximumFalseNegativeRate*m_hc.sum();
Threshold best = evaluateThresholdValue(0.0f);
for(unsigned int i = 0; i <= steps; ++i, threshold += delta)
{
Threshold current = evaluateThresholdValue(threshold);
- if( current.truePositive >= minPositiveCount &&
- current.falsePositive <= maxNegativeCount &&
+
+ if( current.truePositive >= minTruePositiveCount &&
+ current.falsePositive <= maxFalseNegativeCount &&
best < current)
{
best = current;
}
}
- if( best.truePositive >= minPositiveCount &&
- best.falsePositive <= maxNegativeCount )
+ if( best.truePositive >= minTruePositiveCount &&
+ best.falsePositive <= maxFalseNegativeCount )
{
return best;
}
View
@@ -1,6 +1,9 @@
#pragma once
#include "Histogram.h"
+#include "math.h"
+
+#include <iostream>
class Detector
{
@@ -13,34 +16,75 @@ class Detector
{
}
- Threshold(float _threshold, int _truePositive = 0, int _falsePositive = 0)
+ Threshold(float _threshold, int _truePositive = 0, int _falsePositive = 0,
+ int _positiveCount = 0, int _negativeCount = 0)
: threshold(_threshold)
, truePositive(_truePositive), falsePositive(_falsePositive)
+ , positiveCount(_positiveCount), negativeCount(_negativeCount)
{}
+ bool isValid() const
+ {
+ return truePositive >= 0;
+ }
+
+ float truePositiveRate() const
+ {
+ return (truePositive/static_cast<float>(positiveCount));
+ }
+
+ float falsePositiveRate() const
+ {
+ return (falsePositive/static_cast<float>(negativeCount));
+ }
+
+ /* Matthews Correlation Coefficient */
+ float mcc() const
+ {
+ int trueNegative = negativeCount - falsePositive;
+ int falseNegative = positiveCount - truePositive;
+
+ int num = (truePositive*trueNegative) - (falsePositive*falseNegative);
+ int denom = (truePositive+falsePositive)*(trueNegative+falseNegative)
+ *positiveCount*negativeCount;
+ if( denom == 0 )
+ {
+ return 0;
+ }
+ return num/static_cast<float>(sqrt(denom));
+ }
+
bool operator==(const Threshold& other)
{
return other.threshold == threshold &&
other.truePositive == truePositive &&
- other.falsePositive == falsePositive;
+ other.falsePositive == falsePositive &&
+ other.positiveCount == positiveCount &&
+ other.negativeCount == negativeCount;
+ }
+ friend ostream& operator<<(ostream& out, const Threshold& threshold)
+ {
+ return out << threshold.threshold<<" ("<<threshold.truePositive<<","<<threshold.falsePositive<<") = "<<threshold.mcc();
}
bool operator<(const Threshold& other)
{
- return other.truePositive < other.truePositive;
+ return mcc() < other.mcc();
}
float threshold;
int truePositive;
int falsePositive;
+ int positiveCount;
+ int negativeCount;
};
Detector(const Histogram& hs, const Histogram& hc);
Detector(const vector<int>& positive, const vector<int>& negative);
Threshold evaluateThresholdValue(float delta) const;
- Threshold computeOptimalThreshold(unsigned int steps, float minimumPositiveRate, float maximumNegativeRate) const;
+ Threshold computeOptimalThreshold(unsigned int steps, float minimumTruePositiveRate, float maximumFalseNegativeRate) const;
protected:
View
@@ -64,6 +64,21 @@ void TestDetector::testComputeOptimalThreshold()
// [1.00, +oo[ -> ( 4, 0) == ( 40%, 0%)
Detector::Threshold threshold = detector.computeOptimalThreshold(100, 0.90, 0.10);
- threshold = detector.computeOptimalThreshold(100, 0.40, 0.10);
+
+ // no threshold can satisfy (90%, 10%)
+ CPPUNIT_ASSERT(! threshold.isValid());
+
+ // check that a solution is found for each ranges
+ threshold = detector.computeOptimalThreshold(100, 0.30, 0.10);
+ CPPUNIT_ASSERT( threshold.truePositive == 4 && threshold.falsePositive == 0);
+
threshold = detector.computeOptimalThreshold(100, 0.80, 0.15);
+ CPPUNIT_ASSERT( threshold.truePositive == 8 && threshold.falsePositive == 1);
+
+ threshold = detector.computeOptimalThreshold(100, 0.99, 1.10);
+ CPPUNIT_ASSERT( threshold.truePositive == 10 && threshold.falsePositive == 9);
+
+ // check that the best solution is returned
+ threshold = detector.computeOptimalThreshold(100, 0.50, 0.50);
+ CPPUNIT_ASSERT( threshold.truePositive == 8 && threshold.falsePositive == 1);
}

0 comments on commit 61d1e51

Please sign in to comment.