mirror of
https://github.com/Llewellynvdm/php-ml.git
synced 2025-01-23 23:28:24 +00:00
implement ClassificationReport class
This commit is contained in:
parent
76d15e9691
commit
9665457159
148
src/Phpml/Metric/ClassificationReport.php
Normal file
148
src/Phpml/Metric/ClassificationReport.php
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace Phpml\Metric;
|
||||||
|
|
||||||
|
class ClassificationReport
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private $precision = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private $recall = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private $f1score = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private $support = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private $average = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $actualLabels
|
||||||
|
* @param array $predictedLabels
|
||||||
|
*/
|
||||||
|
public function __construct(array $actualLabels, array $predictedLabels)
|
||||||
|
{
|
||||||
|
$truePositive = $falsePositive = $falseNegative = $this->support = self::getLabelIndexedArray($actualLabels);
|
||||||
|
|
||||||
|
foreach ($actualLabels as $index => $actual) {
|
||||||
|
$predicted = $predictedLabels[$index];
|
||||||
|
$this->support[$actual]++;
|
||||||
|
|
||||||
|
if($actual === $predicted) {
|
||||||
|
$truePositive[$actual]++;
|
||||||
|
} else {
|
||||||
|
$falsePositive[$predicted]++;
|
||||||
|
$falseNegative[$actual]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->computeMetrics($truePositive, $falsePositive, $falseNegative);
|
||||||
|
$this->computeAverage();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getPrecision()
|
||||||
|
{
|
||||||
|
return $this->precision;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getRecall()
|
||||||
|
{
|
||||||
|
return $this->recall;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getF1score()
|
||||||
|
{
|
||||||
|
return $this->f1score;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getSupport()
|
||||||
|
{
|
||||||
|
return $this->support;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getAverage()
|
||||||
|
{
|
||||||
|
return $this->average;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $truePositive
|
||||||
|
* @param array $falsePositive
|
||||||
|
* @param array $falseNegative
|
||||||
|
*/
|
||||||
|
private function computeMetrics(array $truePositive, array $falsePositive, array $falseNegative)
|
||||||
|
{
|
||||||
|
foreach ($truePositive as $label => $tp) {
|
||||||
|
$this->precision[$label] = $tp / ($tp + $falsePositive[$label]);
|
||||||
|
$this->recall[$label] = $tp / ($tp + $falseNegative[$label]);
|
||||||
|
$this->f1score[$label] = $this->computeF1Score((float)$this->precision[$label], (float)$this->recall[$label]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function computeAverage()
|
||||||
|
{
|
||||||
|
foreach (['precision', 'recall', 'f1score'] as $metric) {
|
||||||
|
$values = array_filter($this->$metric);
|
||||||
|
$this->average[$metric] = array_sum($values) / count($values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param float $precision
|
||||||
|
* @param float $recall
|
||||||
|
*
|
||||||
|
* @return float
|
||||||
|
*/
|
||||||
|
private function computeF1Score(float $precision, float $recall): float
|
||||||
|
{
|
||||||
|
if(0 == ($divider = $precision+$recall)) {
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 2.0 * (($precision * $recall) / ($divider));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $labels
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private static function getLabelIndexedArray(array $labels): array
|
||||||
|
{
|
||||||
|
$labels = array_values(array_unique($labels));
|
||||||
|
sort($labels);
|
||||||
|
$labels = array_combine($labels, array_fill(0, count($labels), 0));
|
||||||
|
|
||||||
|
return $labels;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
32
tests/Phpml/Metric/ClassificationReportTest.php
Normal file
32
tests/Phpml/Metric/ClassificationReportTest.php
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
namespace tests\Phpml\Metric;
|
||||||
|
|
||||||
|
use Phpml\Metric\ClassificationReport;
|
||||||
|
|
||||||
|
class ClassificationReportTest extends \PHPUnit_Framework_TestCase
|
||||||
|
{
|
||||||
|
|
||||||
|
public function testClassificationReportGenerateWithStringLabels()
|
||||||
|
{
|
||||||
|
$labels = ['cat', 'ant', 'bird', 'bird', 'bird'];
|
||||||
|
$predicted = ['cat', 'cat', 'bird', 'bird', 'ant'];
|
||||||
|
|
||||||
|
$report = new ClassificationReport($labels, $predicted);
|
||||||
|
|
||||||
|
$precision = ['cat' => 0.5, 'ant' => 0.0, 'bird' => 1.0];
|
||||||
|
$recall = ['cat' => 1.0, 'ant' => 0.0, 'bird' => 0.67];
|
||||||
|
$f1score = ['cat' => 0.67, 'ant' => 0.0, 'bird' => 0.80];
|
||||||
|
$support = ['cat' => 1, 'ant' => 1, 'bird' => 3];
|
||||||
|
$average = ['precision' => 0.75, 'recall' => 0.83, 'f1score' => 0.73];
|
||||||
|
|
||||||
|
|
||||||
|
$this->assertEquals($precision, $report->getPrecision(), '', 0.01);
|
||||||
|
$this->assertEquals($recall, $report->getRecall(), '', 0.01);
|
||||||
|
$this->assertEquals($f1score, $report->getF1score(), '', 0.01);
|
||||||
|
$this->assertEquals($support, $report->getSupport(), '', 0.01);
|
||||||
|
$this->assertEquals($average, $report->getAverage(), '', 0.01);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user