I have a rating system where users can vote between 1-6. I'd like to normalize the votes a bit to better accommodate for extreme voting, where individuals tend to vote as high or as low as possible. To do this, I have the following algorithm which seems to work well. However, it's extremely inefficient and not very well written.
What might I do to improve it?
protected function calculateWeightedAverage($ratings)
{
$values = array_values($ratings);
sort($values);
$count = count($values);
$weights = array_fill(0, $count, 1);
$out = (int) ($count / 3);
$out2 = pow($out + 1, 2);
$max = $count - 1;
$min = 0;
for ($i = 0; $i < $out; $i++) {
$j = $i + 1;
$weights[$min + $i] = $j * $j / $out2;
$weights[$max - $i] = $j * $j / $out2;
}
$sum = array_sum($weights);
for ($i = 0; $i < $count; $i++) {
$weights[$i] /= $sum;
}
$rating = 0;
for ($i = 0; $i < $count; $i++) {
$rating += $values[$i] * $weights[$i];
}
return $rating;
}
$ratings
and give us something concrete. \$\endgroup\$$ratings
comes in as an array[userid => vote, ... ]
but we're usingarray_values()
so$values
is just an array of integers 1-6. \$\endgroup\$count / 3
) and lower third items in the array, giving majority weight to values in the middle. For instance, if the votes were[1, 4, 7]
, the weight of the 1 and 7 would be decreased before calculating the average. If it were[2, 2, 3, 4, 4, 7]
the weights of the 2, 2, second 4, and 7 would be lowered. \$\endgroup\$