Forked from mbadolato/WilsonConfidenceIntervalCalculator.php
Created
April 10, 2017 23:03
-
-
Save evansims/76f5e255ea0a2aa9f23b9e5491977621 to your computer and use it in GitHub Desktop.
PHP translation of the Wilson ConfidenceInterval Calculator. Ported from Ruby and uses a hardcoded (pre-calculated) confidence (z value) instead of a dynamic calculation with a translation of Ruby's Statistics2.pnormaldist method. Since z doesn't change once it's computed, nor is the computation dependant on the passed-in values, calculating it …
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/* | |
* (c) Mark Badolato <[email protected]> | |
* | |
* This content is released under the {@link http://www.opensource.org/licenses/MIT MIT License.} | |
*/ | |
namespace Bado\ScoreCalculator; | |
/** | |
* Calculate a score based on a Wilson Confidence Interval | |
* | |
* Based on concepts discussed at @link http://www.evanmiller.org/how-not-to-sort-by-average-rating.html | |
*/ | |
class WilsonConfidenceIntervalCalculator | |
{ | |
/** | |
* Computed value for confidence (z) | |
* | |
* These values were computed using Ruby's Statistics2.pnormaldist function | |
* 1.959964 = 95.0% confidence | |
* 2.241403 = 97.5% confidence | |
*/ | |
const CONFIDENCE = 2.241403; | |
public function getScore($positiveVotes, $totalVotes, $confidence = self::CONFIDENCE) | |
{ | |
return $totalVotes ? $this->lowerBound($positiveVotes, $totalVotes, $confidence) : 0; | |
} | |
private function lowerBound($positiveVotes, $totalVotes, $confidence) | |
{ | |
$phat = 1.0 * $positiveVotes / $totalVotes; | |
$numerator = $this->calculationNumerator($totalVotes, $confidence, $phat); | |
$denominator = $this->calculationDenominator($totalVotes, $confidence); | |
return $numerator / $denominator; | |
} | |
private function calculationDenominator($total, $z) | |
{ | |
return 1 + $z * $z / $total; | |
} | |
private function calculationNumerator($total, $z, $phat) | |
{ | |
return $phat + $z * $z / (2 * $total) - $z * sqrt(($phat * (1 - $phat) + $z * $z / (4 * $total)) / $total); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/* | |
* (c) Mark Badolato <[email protected]> | |
* | |
* This content is released under the {@link http://www.opensource.org/licenses/MIT MIT License.} | |
*/ | |
namespace Bado\Tests\ScoreCalculator; | |
use Bado\ScoreCalculator\WilsonConfidenceIntervalCalculator; | |
class WilsonConfidenceIntervalCalculatorTest extends \PHPUnit_Framework_TestCase | |
{ | |
/** @var WilsonConfidenceIntervalCalculator */ | |
private $calculator; | |
/** @test */ | |
public function calculateFiftyTwoPositiveOutOfSeventySixTotal() | |
{ | |
$this->floatAssertion(0.556480, $this->getScore(52, 76)); | |
} | |
/** @test */ | |
public function calculateNoPositiveOutOfTenTotal() | |
{ | |
$this->floatAssertion(0, $this->getScore(0, 10)); | |
} | |
/** @test */ | |
public function calculateNoVotes() | |
{ | |
$this->floatAssertion(0, $this->getScore(0, 0)); | |
} | |
/** @test */ | |
public function calculateOneOutOfTwo() | |
{ | |
$this->floatAssertion(0.077136, $this->getScore(1, 2)); | |
} | |
/** @test */ | |
public function calculateTenPositiveOutOfTenTotal() | |
{ | |
$this->floatAssertion(0.665607, $this->getScore(10, 10)); | |
} | |
/** @test */ | |
public function calculateTenPositiveOutOfTwentyTotal() | |
{ | |
$this->floatAssertion(0.275967, $this->getScore(10, 20)); | |
} | |
protected function setUp() | |
{ | |
$this->calculator = new WilsonConfidenceIntervalCalculator(); | |
} | |
private function floatAssertion($expected, $result) | |
{ | |
$this->assertEquals($expected, $result, '', 0.000001); | |
} | |
private function getScore($positiveVotes, $totalVotes) | |
{ | |
return $this->calculator->getScore($positiveVotes, $totalVotes); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment