Как лучше сортировать по 5-звездочному рейтингу? - PullRequest
62 голосов
/ 11 сентября 2009

Я пытаюсь отсортировать товары по рейтингу клиентов, используя 5-звездочную систему. Сайт, для которого я настраиваюсь, не имеет большого количества оценок и продолжает добавлять новые продукты, поэтому на нем обычно будет несколько продуктов с низким числом оценок.

Я пытался использовать средний рейтинг по звездам, но этот алгоритм не работает при небольшом количестве оценок.

Пример продукта, который имеет 3x 5 звездных оценок, будет отображаться лучше, чем продукт, который имеет 100x 5 звездных оценок и 2x 2 звездных рейтинга.

Разве второй продукт не должен показываться выше, потому что он статистически более надежен из-за большего количества оценок?

Ответы [ 10 ]

69 голосов
/ 11 сентября 2009

До 2015 года База данных фильмов в Интернете (IMDb) публично перечисляла формулу, использованную для ранжирования их списка фильмов Топ 250 . Цитировать:

Формула для расчета 250 наименований с самым высоким рейтингом дает истинную байесовскую оценку :

weighted rating (WR) = (v ÷ (v+m)) × R + (m ÷ (v+m)) × C

где:

  • R = среднее для фильма (среднее)
  • v = количество голосов за фильм
  • m = минимальное количество голосов, необходимое для включения в список 250 лучших (в настоящее время 25000)
  • C = среднее количество голосов по всему отчету (в настоящее время 7,0)

Для Топ-250 учитываются только голоса от обычных избирателей.

Это не так сложно понять. Формула:

rating = (v / (v + m)) * R +
         (m / (v + m)) * C;

Что математически можно упростить до:

rating = (R * v + C * m) / (v + m);

Переменные:

  • R - собственный рейтинг предмета. R - среднее количество голосов за предмет. (Например, если элемент не имеет голосов, его R равно 0. Если кто-то дает ему 5 звезд, R становится 5. Если кто-то дает ему 1 звезду, R становится 3, в среднем [1, 5]. И так далее. )
  • C - средний рейтинг предмета. Найти R каждого элемента в базе данных, включая текущий, и взять среднее из них; это C. (Предположим, что в базе данных есть 4 элемента, и их рейтинги равны [2, 3, 5, 5]. C равно 3.75, среднее значение этих чисел.)
  • v - количество голосов за элемент. (Для другого примера, если 5 человек проголосовали за предмет, v равен 5.)
  • м - настраиваемый параметр. Количество «сглаживания», примененного к рейтингу, основано на количестве голосов (v) по отношению к m. Регулируйте m, пока результаты не удовлетворят вас. И не следует неверно истолковывать описание m в IMDb как «минимальное количество голосов, необходимое для внесения в список» - эта система отлично способна оценивать позиции с меньшим количеством голосов, чем m.

Все, что делает формула: добавьте m мнимых голосов, каждый со значением C, прежде чем вычислять среднее значение. В начале, когда данных недостаточно (т. Е. Количество голосов значительно меньше m), это приводит к заполнению пробелов средними данными. Однако, по мере накопления голосов, в конечном итоге воображаемые голоса будут заглушаться реальными.

В этой системе голоса не приводят к резким колебаниям рейтинга. Вместо этого они просто немного возмущают его в каком-то направлении.

Когда голосов нет, существуют только мнимые голоса, и все они - C. Таким образом, каждый элемент начинается с рейтинга C.

Смотри также:

16 голосов
/ 27 марта 2010

См. на этой странице для хорошего анализа звездных рейтинговых систем и на этой для хорошего анализа систем на основе повышательных / понижательных оценок.

Для голосования «за» и «против» вы хотите оценить вероятность того, что, учитывая ваши рейтинги, «реальная» оценка (если у вас было бесконечное количество оценок) больше некоторой величины (как, скажем, аналогичное число для некоторых пункт, с которым вы сортируете).

См. Вторую статью для ответа, но вывод заключается в том, что вы хотите использовать доверие Уилсона. В статье приводится уравнение и пример кода Ruby (легко переводится на другой язык).

15 голосов
/ 04 декабря 2016

Эван Миллер показывает байесовский подход к ранжированию 5-звездочных рейтингов: enter image description here

где

  • nk - это число k -звездных рейтингов,
  • sk - это «ценность» (в баллах) k звезд,
  • N - общее количество голосов
  • K - максимальное количество звезд (например, K = 5 в 5-звездочной рейтинговой системе)
  • z_alpha/2 - это 1 - alpha/2 квантиль нормального распределения. Если вы хотите на 95% уверенности (основываясь на байесовском апостериорном распределении), что фактический критерий сортировки, по крайней мере, такой же большой, как вычисленный критерий сортировки, выберите z_alpha/2 = 1.65.

В Python критерий сортировки можно вычислить с помощью

def starsort(ns):
    """
    http://www.evanmiller.org/ranking-items-with-star-ratings.html
    """
    N = sum(ns)
    K = len(ns)
    s = list(range(K,0,-1))
    s2 = [sk**2 for sk in s]
    z = 1.65
    def f(s, ns):
        N = sum(ns)
        K = len(ns)
        return sum(sk*(nk+1) for sk, nk in zip(s,ns)) / (N+K)
    fsns = f(s, ns)
    return fsns - z*math.sqrt((f(s2, ns)- fsns**2)/(N+K+1))

Например, если предмет имеет 60 пятизвездочных, 80 четырехзвездочных, 75 трехзвездных, 20 двухзвездных и 25 однозвездных, тогда его общий рейтинг будет примерно 3,4:

x = (60, 80, 75, 20, 25)
starsort(x)
# 3.3686975120774694

и вы можете отсортировать список 5-звездочных рейтингов с

sorted([(60, 80, 75, 20, 25), (10,0,0,0,0), (5,0,0,0,0)], key=starsort, reverse=True)
# [(10, 0, 0, 0, 0), (60, 80, 75, 20, 25), (5, 0, 0, 0, 0)]

Показывает влияние, которое большее количество оценок может оказать на общее звездное значение.


Вы обнаружите, что эта формула имеет тенденцию давать общий рейтинг, который немного ниже, чем общий рейтинг, сообщаемый такими сайтами, как Amazon, Ebay или Wal-mart особенно когда голосов мало (скажем, меньше 300). Это отражает более высокая неопределенность, которая приходит с меньшим количеством голосов. По мере увеличения количества голосов (в тысячах) все в целом эти рейтинговые формулы должны стремиться к (взвешенный) средний рейтинг.


Поскольку формула зависит только от частотного распределения 5-звездочных рейтингов для самого элемента легко объединить рецензии из нескольких источников (или, обновление общий рейтинг в свете новых голосов) путем простого добавления частоты распределения вместе.


В отличие от формулы IMDb, эта формула не зависит от средней оценки по всем пунктам, ни искусственное минимальное количество отсечения голосов.

Более того, эта формула использует полное распределение частот, а не только среднее количество звезд и количество голосов. И имеет смысл, что это следует, так как элемент с десятью 5-звездочными и десятью 1-звездочными должен рассматриваться как иметь большую неопределенность, чем (и, следовательно, не оценивается так высоко, как) предмет с двадцать 3-звездочных оценок:

In [78]: starsort((10,0,0,0,10))
Out[78]: 2.386028063783418

In [79]: starsort((0,0,20,0,0))
Out[79]: 2.795342687927806

В формуле IMDb это не учитывается.

7 голосов
/ 11 сентября 2009

Ну, в зависимости от того, насколько сложным вы хотите это сделать, вы можете иметь дополнительные рейтинги, которые будут взвешиваться на основе того, сколько оценок сделал человек, и каковы эти рейтинги. Если человек сделал только один рейтинг, это может быть рейтинг шилла, и он может рассчитывать на меньшее. Или, если человек оценил многие вещи в категории a, но мало в категории b, и имеет средний рейтинг 1,3 из 5 звезд, это звучит так, как будто категория a может быть искусственно занижена низкой средней оценкой этого пользователя, и следует отрегулировать.

Но достаточно сделать это сложным. Давайте сделаем это просто.

Предполагая, что мы работаем только с двумя значениями, ReviewCount и AverageRating, для конкретного элемента, для меня будет иметь смысл рассматривать ReviewCount как значение «надежности». Но мы не хотим просто снижать баллы за низкие элементы ReviewCount: один рейтинг в одну звездочку, вероятно, столь же ненадежен, как и один рейтинг в 5 звезд. Поэтому то, что мы хотим сделать, это, вероятно, среднее значение к середине: 3.

Итак, в основном, я думаю об уравнении, похожем на X * AverageRating + Y * 3 = рейтинг-мы-хотим. Чтобы сделать это значение правильным, нам нужно, чтобы X + Y было равно 1. Также нам нужно, чтобы значение X увеличивалось по мере увеличения ReviewCount ... со счетчиком обзора 0, x должно быть 0 (что дает нам уравнение « 3 ”), а при бесконечном обзоре счетчик X должен быть равен 1 (что делает уравнение = AverageRating).

Так что же такое уравнения X и Y? Для уравнения X необходимо, чтобы зависимая переменная асимптотически приближалась к 1, когда независимая переменная приближается к бесконечности. Хороший набор уравнений выглядит примерно так: Y = 1 / (коэффициент ^ RatingCount) и (используя тот факт, что X должен быть равен 1-Y) X = 1 - (1 / (коэффициент ^ RatingCount)

Затем мы можем отрегулировать «коэффициент», чтобы он соответствовал диапазону, который мы ищем.

Я использовал эту простую программу на C #, чтобы попробовать несколько факторов:

        // We can adjust this factor to adjust our curve.
        double factor = 1.5;  

        // Here's some sample data
        double RatingAverage1 = 5;
        double RatingCount1 = 1;

        double RatingAverage2 = 4.5;
        double RatingCount2 = 5;

        double RatingAverage3 = 3.5;
        double RatingCount3 = 50000; // 50000 is not infinite, but it's probably plenty to closely simulate it.

        // Do the calculations
        double modfactor = Math.Pow(factor, RatingCount1);
        double modRating1 = (3 / modfactor)
            + (RatingAverage1 * (1 - 1 / modfactor));

        double modfactor2 = Math.Pow(factor, RatingCount2);
        double modRating2 = (3 / modfactor2)
            + (RatingAverage2 * (1 - 1 / modfactor2));

        double modfactor3 = Math.Pow(factor, RatingCount3);
        double modRating3 = (3 / modfactor3)
            + (RatingAverage3 * (1 - 1 / modfactor3));

        Console.WriteLine(String.Format("RatingAverage: {0}, RatingCount: {1}, Adjusted Rating: {2:0.00}", 
            RatingAverage1, RatingCount1, modRating1));
        Console.WriteLine(String.Format("RatingAverage: {0}, RatingCount: {1}, Adjusted Rating: {2:0.00}",
            RatingAverage2, RatingCount2, modRating2));
        Console.WriteLine(String.Format("RatingAverage: {0}, RatingCount: {1}, Adjusted Rating: {2:0.00}",
            RatingAverage3, RatingCount3, modRating3));

        // Hold up for the user to read the data.
        Console.ReadLine();

То есть, вы не копируете его, он выдает:

RatingAverage: 5, RatingCount: 1, Adjusted Rating: 3.67
RatingAverage: 4.5, RatingCount: 5, Adjusted Rating: 4.30
RatingAverage: 3.5, RatingCount: 50000, Adjusted Rating: 3.50

Что-то подобное? Очевидно, что при необходимости вы можете откорректировать значение «фактора», чтобы получить нужный вам вес.

7 голосов
/ 11 сентября 2009

Вы можете сортировать по медиане вместо среднего арифметического. В этом случае в обоих примерах медиана равна 5, поэтому оба алгоритма имеют одинаковый вес в алгоритме сортировки.

Вы можете использовать режим для того же эффекта, но медиана, вероятно, является лучшей идеей.

Если вы хотите назначить дополнительный вес продукту с 100 5-звездочными рейтингами, вам, вероятно, следует перейти к некоторому взвешенному режиму, назначив больший вес рейтингам с той же медианой, но с большим количеством голосов.

3 голосов
/ 12 октября 2010

Если вам просто нужно быстрое и дешевое решение, которое в основном будет работать без большого количества вычислений, вот один из вариантов (с оценкой по шкале от 1 до 5)

SELECT Products.id, Products.title, avg(Ratings.score), etc
FROM
Products INNER JOIN Ratings ON Products.id=Ratings.product_id
GROUP BY 
Products.id, Products.title
ORDER BY (SUM(Ratings.score)+25.0)/(COUNT(Ratings.id)+20.0) DESC, COUNT(Ratings.id) DESC

Суммируя 25 и деля на общее количество рейтингов + 20, вы в основном добавляете 10 худших и 10 лучших баллов к общим рейтингам, а затем сортируете соответствующим образом.

У этого есть известные проблемы. Например, он несправедливо вознаграждает продукты с низким баллом с небольшим рейтингом (как показывает на этом графике , продукты со средним баллом 1 и только с одним рейтингом 1,2 балла, а продукты со средним баллом 1 и 1k + оценок оценка ближе к 1,05). Вы также можете утверждать, что это несправедливо наказывает высококачественные продукты с небольшим рейтингом.

На этом графике показано, что происходит для всех 5 оценок за 1-1000 оценок: http://www.wolframalpha.com/input/?i=Plot3D%5B%2825%2Bxy%29/%2820%2Bx%29%2C%7Bx%2C1%2C1000%7D%2C%7By%2C0%2C6%7D%5D

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

http://www.wolframalpha.com/input/?i=Plot3D%5B6-%28%2825%2Bxy%29/%2820%2Bx%29%29%2C%7Bx%2C1%2C1000%7D%2C%7By%2C0%2C6%7D%5D

Если вы уроните шарик в большинстве мест на этом графике, он автоматически перейдет к продуктам с более высокими оценками и более высокими оценками.

0 голосов
/ 12 января 2018

Через некоторое время я выбираю байесовскую систему. Если кто-то использует Ruby, вот драгоценный камень для него:

https://github.com/wbotelhos/rating

0 голосов
/ 12 октября 2010

Один из вариантов - это что-то вроде системы Microsoft TrueSkill, где оценка дается mean - 3*stddev, где константы могут быть изменены.

0 голосов
/ 11 сентября 2009

Я очень рекомендую книгу «Программирование коллективного интеллекта» Тоби Сегарана (Ореилли) ISBN 978-0-596-52932-1, в которой обсуждается, как извлечь значимые данные из поведения толпы.Примеры написаны на Python, но его достаточно легко конвертировать.

0 голосов
/ 11 сентября 2009

Очевидно, что небольшое количество рейтингов ставит эту проблему в статистическое затруднение. Тем не менее ...

Ключевым элементом повышения качества совокупного рейтинга является «оценка оценщика», то есть отслеживание оценок, предоставленных каждым конкретным «оценщиком» (относительно других). Это позволяет взвешивать их голоса в процессе агрегации.

Другое решение, более удачное, состоит в том, чтобы предоставить конечным пользователям количество (или указание диапазона) голосов за базовый элемент.

...