Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save evansims/76f5e255ea0a2aa9f23b9e5491977621 to your computer and use it in GitHub Desktop.
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 …
<?php
/*
* (c) Mark Badolato <mbadolato@gmail.com>
*
* 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);
}
}
<?php
/*
* (c) Mark Badolato <mbadolato@gmail.com>
*
* 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