Правильный рейтинг на PHP

Несколько лет тому назад специально для одного проекта необходимо было рассчитывать рейтинг.  Требования были несколько выше, чем простое суммирование голосов и деление на количество проголосовавших. Хотелось более объективной оценки при рейтинге и выдачи результатов (к тому же на данном проекте необходимо было учитывать еще и количество отзывов).

После относительно не долгих поисков на просторах сети интернет нашлось интересное решение, которое основывалось на доверительном интервале Вильсона. Источником для вдохновения послужил всем известный Хабрахабр и его статья «Как правильно сортировать контент на основе оценок пользователей«.

Доверительный интервал Вильсона можно использовать везде, где вы хотите с уверенностью знать, какова пропорция людей, совершающих определенный поступок.

А вот и сама формула, на которой основываются расчеты:

Доверительный интервал Вильсона

Словесное описание функции звучит как Рейтинг = Нижняя граница доверительного интервала Вильсона (Wilson) для параметра Бернулли.

Естественно, данная формула была адаптирована под произвольную шкалу голосов.

Вашему вниманию предлагаю функцию на PHP:

/**
 * Расчет рейтинга на основе шкалы голосов
 * 
 * @param $sumVotes Сумма всех голосов
 * @param $totalVotes Кол-во голосов
 * @param array $votesRange Диапазон возможных значений голосов
 * @return float|int
 */
function wilsonScore($sumVotes, $totalVotes, $votesRange = [1, 2, 3, 4, 5])
{
  if ($sumVotes > 0 && $totalVotes > 0) {
    $z = 1.64485;
    $vMin = min($votesRange);
    $vWidth = floatval(max($votesRange) - $vMin);

    $phat = ($sumVotes - $totalVotes * $vMin) / $vWidth / floatval($totalVotes);

    $rating = ($phat + $z * $z / (2 * $totalVotes) - $z * sqrt(($phat * (1 - $phat) + $z * $z / (4 * $totalVotes)) / $totalVotes)) / (1 + $z * $z / $totalVotes);

    return round($rating * $vWidth + $vMin, 6);
  }

  return 0;
}

На авторство не претендую, мне лишь понравилась сама функция на Python, которую я переделал под PHP, т.к. сайт работал именно на нем. Возможно кто-то использует более интересное решение. Буду рад всем вашим комментариям.

А вот таблица с тестовыми данными:

Сумма голосов Какие были поставлены оценки Кол-во голосов Рейтинг
5 5 1 2,079467
5 1+4 2 1,291229
5 2+2+1 3 1,093307
5 1+1+2+1 4 1,019701
5 1+1+1+1+1 5 1
15 5+5+5 3 3,103222
15 5+3+5+2 4 2,231445
15 5+2+5+3 4 2,231445
30 5+2+4+5+1+1+4+5+3 9 2,305087
30 4+4+5+4+3+5+5 7 3,042607
30 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1 +1+1+1+1+1+1 30 1
30 1+1+1+1+1+1+1+1+1+2+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1 +1+1+1 29 1,002707

 

Если вы нашли ошибку, пожалуйста, выделите фрагмент текста и нажмите Ctrl+Enter.

Добавить комментарий

Сообщить об опечатке

Текст, который будет отправлен нашим редакторам: