Last active
January 29, 2021 01:12
-
-
Save itsjavi/adc7ee7a8e033ac66640f6d4f83b7c8f to your computer and use it in GitHub Desktop.
PHP Percentile Rank calculator class for collections of associative arrays
This file contains hidden or 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 | |
declare(strict_types=1); | |
namespace App\Support; | |
class PercentileRankCalculator | |
{ | |
/** | |
* Calculate percentile rank over a field in a collection of associative arrays | |
* @param array[] $collection | |
* @param int|string $analysedKey | |
* @param int|string $newPercentileKey | |
* @return array Returns back the collection with the new percentile property in every item. | |
* The returned collection is sorted by $analysedKey. Original collection array keys are discarded. | |
*/ | |
public function calculate(array $collection, $analysedKey, $newPercentileKey): array | |
{ | |
// Sort provided data in ascending order | |
$collection = self::sort($collection, $analysedKey); | |
// Generate an array of values | |
// Make sure values are of the same type | |
$values = []; | |
foreach ($collection as $i => $arr) { | |
$values[] = (string)(float)$arr[$analysedKey]; | |
} | |
// Number of examinees in the sample | |
$count = count($values); | |
// Array to use when checking scores less than the score of interest | |
$count_less = array_flip(array_unique($values)); | |
// Array to use when checking frequency of the score of interest | |
$count_values = array_count_values($values); | |
foreach ($values as $i => $value) { | |
$freq = $count_values[$value]; | |
$collection[$i][$newPercentileKey] = (($count_less[$value] + 0.5 * $freq) / $count) * 100; | |
} | |
return $collection; | |
} | |
/** | |
* Sort array in ascending order | |
* @param array $data | |
* @param int|string $index | |
* @return array | |
*/ | |
protected static function sort(array $data, $index): array | |
{ | |
usort( | |
$data, | |
function ($a, $b) use ($index) { | |
$item1 = (string)(float)$a[$index]; | |
$item2 = (string)(float)$b[$index]; | |
if ($item1 == $item2) { | |
return 0; | |
} | |
return ($item1 < $item2) ? -1 : 1; | |
} | |
); | |
return $data; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment