Правильный рейтинг на 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, т.к. сайт работал именно на нем. Возможно кто-то использует более интересное решение. Буду рад всем вашим комментариям.

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

Сумма голосовКакие были поставлены оценкиКол-во голосовРейтинг
5512,079467
51+421,291229
52+2+131,093307
51+1+2+141,019701
51+1+1+1+151
155+5+533,103222
155+3+5+242,231445
155+2+5+342,231445
305+2+4+5+1+1+4+5+392,305087
304+4+5+4+3+5+573,042607
301+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+1301
301+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+1291,002707

 

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

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

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

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