0.2.0 GST

This commit is contained in:
rob tillaart 2022-06-08 14:39:43 +02:00
parent 3732af1abb
commit dc45c57956
8 changed files with 588 additions and 85 deletions

226
libraries/GST/GST.cpp Normal file
View File

@ -0,0 +1,226 @@
//
// FILE: GST.cpp
// VERSION: 0.1.1
// PURPOSE: Arduino library for Gold Standard Test metrics
// URL: https://github.com/RobTillaart/GST
// https://en.wikipedia.org/wiki/Sensitivity_and_specificity
// https://en.wikipedia.org/wiki/Confusion_matrix
//
// formula's based upon Wikipedia.
#include "GST.h"
GST::GST()
{
clearAll();
};
///////////////////////////////////////////////////////
//
// INPUT FUNCTIONS
//
void GST::setTruePositive(float v)
{
TP = v;
AP = TP + FN;
};
void GST::setTrueNegative(float v)
{
TN = v;
AN = TN + FP;
};
void GST::setFalsePositive(float v)
{
FP = v;
AN = TN + FP;
};
void GST::setFalseNegative(float v)
{
FN = v;
AP = TP + FN;
};
void GST::clearAll()
{
AP = 0;
AN = 0;
TP = 0;
TN = 0;
FP = 0;
FN = 0;
}
// These are used for updating the test matrix
float GST::addTruePositive(float v)
{
TP += v;
AP = TP + FN;
return TP;
};
float GST::addTrueNegative(float v)
{
TN += v;
AN = TN + FP;
return TN;
};
float GST::addFalsePositive(float v)
{
FP += v;
AN = TN + FP;
return FP;
};
float GST::addFalseNegative(float v)
{
FN += v;
AP = TP + FN;
return FN;
};
///////////////////////////////////////////////////////
//
// OUTPUT FUNCTIONS I
//
float GST::getTruePositive() { return TP; };
float GST::getTrueNegative() { return TN; };
float GST::getFalsePositive() { return FP; };
float GST::getFalseNegative() { return FN; };
float GST::getTotal() { return AP + AN; };
float GST::getActualPositive() { return AP; };
float GST::getActualNegative() { return AN; };
float GST::getTestedPositive() { return TP + FP; };
float GST::getTestedNegative() { return TN + FN; };
float GST::sensitivity() { return TPR(); };
float GST::specificity() { return TNR(); };
float GST::truePositiveRate() { return TPR(); };
float GST::TPR() { return TP / AP; };
float GST::trueNegativeRate() { return TNR(); };
float GST::TNR() { return TN / AN; };
float GST::falseNegativeRate() { return FNR(); };
float GST::FNR() { return FN / AP; };
float GST::falsePositiveRate() { return FPR(); };
float GST::FPR() { return FP / AN; };
///////////////////////////////////////////////////////
//
// OUTPUT FUNCTIONS II
//
float GST::positivePredictiveValue() { return PPV(); };
float GST::PPV() { return TP / (TP + FP); };
float GST::negativePredictiveValue() { return NPV(); };
float GST::NPV() { return TN / (TN + FN); };
float GST::falseDiscoveryRate() { return FDR(); };
float GST::FDR() { return FP / (TP + FP); };
float GST::falseOmissionRate() { return FOR(); };
float GST::FOR() { return FN / (TN + FN); };
float GST::positiveLikelihoodRatio() { return LRplus(); };
float GST::LRplus() { return TPR() / FPR(); };
float GST::negativeLikelihoodRatio() { return LRminus(); };
float GST::LRminus() { return FNR() / TNR(); };
float GST::prevalenceThreshold()
{
return sqrt(FPR()) / (sqrt(TPR()) + sqrt(FPR()));
};
float GST::threatScore()
{
return TP / (TP + FN + FP);
};
float GST::criticalSuccessIndex()
{
return threatScore();
};
float GST::prevalence()
{
return AP / (AP + AN);
};
float GST::accuracy()
{
return (TP + TN) / (AP + AN);
};
float GST::balancedAccuracy()
{
return (TPR() + TNR()) * 0.5;
};
float GST::F1Score()
{
return (2 * TP) / (2 * TP + FP + FN);
};
float GST::MatthewsCorrelationCoefficient() { return MCC(); };
float GST::phi() { return MCC(); };
float GST::MCC()
{
return (TP*TN - FP*FN)/sqrt((TP+FP) * (TP+FN) * (TN+FP) * (TN+FN));
};
float GST::FowlkesMallowsIndex() { return FM(); };
float GST::FM()
{
return sqrt(PPV()*TPR());
};
float GST::BookmakerInformedness() { return BM(); };
float GST::BM()
{
return TPR() + TNR() - 1;
};
float GST::markedness() { return MK(); };
float GST::deltaP() { return MK(); };
float GST::MK()
{
return PPV() + NPV() - 1;
};
float GST::diagnosticOddsRatio() { return DOR(); };
float GST::DOR()
{
return LRplus() / LRminus();
};
// -- END OF FILE --

View File

@ -1,110 +1,116 @@
#pragma once
//
// FILE: GST.h
// VERSION: 0.1.0
// VERSION: 0.1.1
// PURPOSE: Arduino library for Gold Standard Test metrics
// URL: https://github.com/RobTillaart/GST
// https://en.wikipedia.org/wiki/Sensitivity_and_specificity
// https://en.wikipedia.org/wiki/Confusion_matrix
//
// formula's based upon wikipedia.
// formula's based upon Wikipedia.
#define GST_LIB_VERSION (F("0.1.1"))
#define GST_LIB_VERSION (F("0.1.0"))
#include "Arduino.h"
class GST
{
public:
GST() {};
GST();
// These 4 need to be filled in.
void setTruePositive(float v) { TP = v; P = TP + FN; };
void setTrueNegative(float v) { TN = v; N = TN + FP; };
void setFalsePositive(float v) { FP = v; N = TN + FP; };
void setFalseNegative(float v) { FN = v; P = TP + FN; };
// These four values of the matrix need to be set to get started.
void setTruePositive(float v = 0);
void setTrueNegative(float v = 0);
void setFalsePositive(float v = 0);
void setFalseNegative(float v = 0);
void clearAll();
float getTruePositive() { return TP; };
float getTrueNegative() { return TN; };
float getFalsePositive() { return FP; };
float getFalseNegative() { return FN; };
float getTotal() { return P + N; };
float getActualPositive() { return P; };
float getActualNegative() { return N; };
float getTestedPositive() { return TP + FP; };
float getTestedNegative() { return TN + FN; };
float sensitivity() { return TPR(); };
float specificity() { return TNR(); };
// These are used for updating the test matrix
float addTruePositive(float v);
float addTrueNegative(float v);
float addFalsePositive(float v);
float addFalseNegative(float v);
// Output functions I
float getTruePositive();
float getTrueNegative();
float getFalsePositive();
float getFalseNegative();
// true positive rate
float TPR() { return TP / P; };
// true negative rate
float TNR() { return TN / N; };
float getTotal();
float getActualPositive();
float getActualNegative();
float getTestedPositive();
float getTestedNegative();
// false negative rate
float FNR() { return FN / (FN + TP); };
// false positive rate
float FPR() { return FP / (FP + TN); };
float sensitivity();
float specificity();
// positive predictive value
float PPV() { return TP / (TP + FP); };
// negative predictive value
float NPV() { return TN / (TN + FN); };
// false discovery rate
float FDR() { return FP / (FP + TP); };
// false omission rate
float FOR() { return FN / (FN + TN); };
float truePositiveRate();
float TPR();
float trueNegativeRate();
float TNR();
float falseNegativeRate();
float FNR();
float falsePositiveRate();
float FPR();
// positive likelihood ratio
float LRplus() { return TPR() / FPR(); };
// negative likelihood ratio
float LRminus() { return FNR() / TNR(); };
// Output functions II
float positivePredictiveValue();
float PPV();
float negativePredictiveValue();
float NPV();
float falseDiscoveryRate();
float FDR();
float falseOmissionRate();
float FOR();
float prevalenceThreshold() { return sqrt(FPR()) / (sqrt(TPR()) + sqrt(FPR())); };
float threatScore() { return TP / (TP + FN + FP); };
float criticalSuccessIndex() { return threatScore(); };
float positiveLikelihoodRatio();
float LRplus();
float negativeLikelihoodRatio();
float LRminus();
float prevalence() { return P / (P + N); };
float accuracy() { return (TP + TN) / (P + N); };
float balancedAccuracy() { return (TPR() + TNR()) / 2; };
float F1Score() { return (2 * TP)/(2 * TP + FP + FN); };
float prevalenceThreshold();
float threatScore();
float criticalSuccessIndex();
// Matthews correlation coefficient
float MCC() { return (TP*TN-FP*FN)/sqrt((TP+FP)*(TP+FN)*(TN+FP)*(TN+FN)); };
float phi() { return MCC(); };
// FowlkesMallows index
float FM() { return sqrt(PPV()*TPR()); };
// Bookmaker informedness
float BM() { return TPR() + TNR() - 1; };
// markedness
float MK() { return PPV() + NPV() - 1; };
float deltaP() { return MK(); };
// diagnostic odds ratio
float DOR() { return LRplus() / LRminus(); };
float prevalence();
float accuracy();
float balancedAccuracy();
float F1Score();
private:
float P = 0;
float N = 0;
float TP = 0;
float TN = 0;
float FP = 0;
float FN = 0;
float MatthewsCorrelationCoefficient();
float phi();
float MCC();
float FowlkesMallowsIndex();
float FM();
float BookmakerInformedness();
float BM();
float markedness();
float deltaP();
float MK();
float diagnosticOddsRatio();
float DOR();
private:
float AP; // actual positive
float AN; // actual negative
float TP; // true positive
float TN; // true negative
float FP; // false positive
float FN; // false positive
};

View File

@ -13,30 +13,140 @@ Arduino library for Gold Standard Test metrics.
## Description
The GST library is **experimental**.
Note: **experimental**
The GST library is an implementation of the **Gold Standard Test**.
#### Links
These sites describe the functions in more detail.
- https://en.wikipedia.org/wiki/Sensitivity_and_specificity
- https://en.wikipedia.org/wiki/Confusion_matrix
#### Performance
The math functions are from pretty straightforward to rather complex.
It is possible to optimize functions with intermediate values if needed.
However the right way to optimize depends on the way the library is used.
#### Related libraries
- https://github.com/RobTillaart/Statistic
## Interface
See .h file
See .h file for all functions. Many function exist in a long descriptive name and an acronym version. Here only the long names are given.
For the definitions please check - https://en.wikipedia.org/wiki/Sensitivity_and_specificity or
https://en.wikipedia.org/wiki/Confusion_matrix
### Input functions
These four numbers should all be set before output functions make sense.
The parameter **value** is typical absolute value measured or counted.
If the parameter is omitted, the default 0 will be used to reset the value.
- **void setTruePositive(float value = 0)** set the internal TP value.
- **void setTrueNegative(float value = 0)** set the internal TN value.
- **void setFalsePositive(float value = 0)** set the internal FP value.
- **void setFalseNegative(float value = 0)** set the internal FN value.
- **void clearAll()** reset all the above to 0.
In tests one often want to increase / change the numbers.
This can be done with the **addTruePositive()** etc functions.
After every addition all output functions can be called.
- **float addTruePositive(float value)** increases the internal TP value.
Use a negative value to decrease.
Returns the new value of TP.
- **float addTrueNegative(float value)** increases the internal TN value.
Use a negative value to decrease.
Returns the new value of TN.
- **float addFalsePositive(float value)** increases the internal FP value.
Use a negative value to decrease.
Returns the new value of FP.
- **float addFalseNegative(float value)** increases the internal FN value.
Use a negative value to decrease.
Returns the new value of FN.
### Output functions I
Basic output
- **float getTruePositive()** returns internal TP.
- **float getTrueNegative()** returns internal TN.
- **float getFalsePositive()** returns internal FP.
- **float getFalseNegative()** returns internal FN.
- **float getTotal()** returns total of four numbers.
- **float getActualPositive()**
- **float getActualNegative()**
- **float getTestedPositive()**
- **float getTestedNegative()**
- **float sensitivity()** equals truePositiveRate().
- **float specificity()** equals trueNegativeRate()
- **float truePositiveRate()**
- **float trueNegativeRate()**
- **float falseNegativeRate()**
- **float falsePositiveRate()**
### Output functions II
These are the more 'complex' functions.
Read the Wikipedia pages for their uses.
- **float positivePredictiveValue()**
- **float negativePredictiveValue()**
- **float falseDiscoveryRate()**
- **float falseOmissionRate()**
- **float positiveLikelihoodRatio()**
- **float negativeLikelihoodRatio()**
- **float prevalenceThreshold()**
- **float threatScore()**
- **float criticalSuccessIndex()**
- **float prevalence()**
- **float accuracy()**
- **float balancedAccuracy()**
- **float F1Score()**
- **float MatthewsCorrelationCoefficient()**
- **float FowlkesMallowsIndex()**
- **float BookmakerInformedness()**
- **float markedness()**
- **float deltaP()**
- **float diagnosticOddsRatio()**
## Future
- documentation
- improve
- more links?
- improve documentation
- add functions
- percentage functions for TP TN FP and FN?
- test
- complete the CI test coverage.
- examples
- add real life examples.
- combination with a sensor? batch testing?
- code
- full name functions instead of acronyms. (wrap?)
- is GST a good class name?

View File

@ -2,7 +2,18 @@
# GST Changelog
## 0.1.0 2022-02-25
## 0.1.1 2022-06-08
- add **addTruePositive()** etc functions.
- add defaults for **setTruePositive(value = 0)** etc functions
- add long descriptive names for the short functions.
- add derived class GoldenStandardTest, for descriptive name
- added some documentation
- split off GST.cpp file, prevent - https://github.com/RobTillaart/CRC/issues/21
## 0.1.0 2022-02-25
- initial version
-

View File

@ -0,0 +1,121 @@
// FILE: GST_add_runtime.ino
// AUTHOR: Rob Tillaart
// PURPOSE: demo
// URL: https://github.com/RobTillaart/GST
#include "Arduino.h"
#include "GST.h"
GST gst;
void setup()
{
Serial.begin(115200);
while (!Serial);
Serial.println(__FILE__);
gst.setTruePositive(0);
gst.setTrueNegative(0);
gst.setFalsePositive(0);
gst.setFalseNegative(0);
}
void loop()
{
// simulate a test result
delay(500);
int score = random(4);
switch (score)
{
case 0:
gst.addTruePositive(1);
break;
case 1:
gst.addTrueNegative(1);
break;
case 2:
gst.addFalsePositive(1);
break;
case 3:
gst.addFalseNegative(1);
break;
}
confusion_matrix();
// confusion_matrix_normalized();
}
void confusion_matrix()
{
Serial.println();
Serial.println(__FUNCTION__);
Serial.println();
// PRINTED IN A MATRIX
Serial.print("\t");
Serial.print(gst.getTotal());
Serial.print("\t");
Serial.print(gst.getTestedPositive());
Serial.print("\t");
Serial.println(gst.getTestedNegative());
Serial.print("\t");
Serial.print(gst.getActualPositive());
Serial.print("\t");
Serial.print(gst.getTruePositive());
Serial.print("\t");
Serial.println(gst.getFalseNegative());
Serial.print("\t");
Serial.print(gst.getActualNegative());
Serial.print("\t");
Serial.print(gst.getFalsePositive());
Serial.print("\t");
Serial.println(gst.getTrueNegative());
Serial.println();
Serial.print("\tSensitivity:\t");
Serial.println(gst.sensitivity(), 4);
Serial.print("\tSpecificity:\t");
Serial.println(gst.specificity(), 4);
}
void confusion_matrix_normalized()
{
Serial.println();
Serial.println(__FUNCTION__);
Serial.println();
// PRINTED IN A MATRIX
Serial.print("\t");
Serial.print("100.00%");
Serial.print("\t");
Serial.print(gst.getTestedPositive());
Serial.print("\t");
Serial.println(gst.getTestedNegative());
Serial.print("\t");
Serial.print(gst.getActualPositive());
Serial.print("\t");
Serial.print(gst.TPR(), 4);
Serial.print("\t");
Serial.println(gst.FNR(), 4);
Serial.print("\t");
Serial.print(gst.getActualNegative());
Serial.print("\t");
Serial.print(gst.FPR(), 4);
Serial.print("\t");
Serial.println(gst.TNR(), 4);
}
// -- END OF FILE --

View File

@ -9,6 +9,12 @@ setTruePositive KEYWORD2
setTrueNegative KEYWORD2
setFalsePositive KEYWORD2
setFalseNegative KEYWORD2
clearAll KEYWORD2
addTruePositive KEYWORD2
addTrueNegative KEYWORD2
addFalsePositive KEYWORD2
addFalseNegative KEYWORD2
getTruePositive KEYWORD2
getTrueNegative KEYWORD2
@ -60,6 +66,29 @@ deltaP KEYWORD2
DOR KEYWORD2
truePositiveRate KEYWORD2
trueNegativeRate KEYWORD2
falseNegativeRate KEYWORD2
falsePositiveRate KEYWORD2
positivePredictiveValue KEYWORD2
negativePredictiveValue KEYWORD2
falseDiscoveryRate KEYWORD2
falseOmissionRate KEYWORD2
positiveLikelihoodRatio KEYWORD2
negativeLikelihoodRatio KEYWORD2
MatthewsCorrelationCoefficient KEYWORD2
FowlkesMallowsIndex KEYWORD2
BookmakerInformedness KEYWORD2
markedness KEYWORD2
diagnosticOddsRatio KEYWORD2
# Constants (LITERAL1)
GST_LIB_VERSION LITERAL1

View File

@ -15,7 +15,7 @@
"type": "git",
"url": "https://github.com/RobTillaart/GST.git"
},
"version": "0.1.0",
"version": "0.1.1",
"license": "MIT",
"frameworks": "arduino",
"platforms": "*",

View File

@ -1,5 +1,5 @@
name=GST
version=0.1.0
version=0.1.1
author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=Arduino library for Golden Standard Test, confusion matrix.