有什么更好的方法可以对5星级进行排序?


71

我正在尝试使用5星系统按客户评分对一堆产品进行排序。我为此设置的网站收视率不高,并且会继续添加新产品,因此通常会有一些收视率低的产品。

我尝试使用平均星级,但是当评分较少时,该算法将失败。

例如,具有3x 5星级的产品要比具有100x 5星级和2x 2星级的产品更好。

第二个产品是否应该因为较高的评分数量而在统计上更值得信赖,从而显示出更高的价格?

Answers:


81

在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,包括当前的R,取其平均值;(假设为C。(假设数据库中有4个项目,它们的等级为[2, 3, 5, 5].C为3.75,即这些数字的平均值。)
  • v –项目的票数。(举另一个例子,如果5个人对该项目投了票,则v为5。)
  • m –可调参数。应用于评分的“平滑”量基于相对于m的票数(v)。调整m直到结果满意。并且不要将IMDb对m的描述误解为“需要列出的最低票数” –该系统完全能够对票数少于m的项目进行排名。

所有公式的作用是:在计算平均值之前,先添加m个虚构的投票,每个投票的值为C。最初,当没有足够的数据时(即,票数大大少于m),这将导致空白填充平均数据。但是,随着选票的累积,最终虚构的选票将被真实选票淹没。

在此系统中,投票不会导致评分波动剧烈。取而代之的是,他们只是在某个方向上干扰了它。

当票数为零时,仅虚数票存在,且所有票数均为C。因此,每个项目都以等级C开头。

也可以看看:

  • 一个演示。点击“解决”。
  • IMDb系统的另一种解释
  • 类似贝叶斯星级系统的解释

引用的Wiki答案文章建议该公式为WR =(v * R + m * C)/(v + m),当考虑到C并且我得到的值似乎更好时,这似乎更有可能。
理查德·加赛德

2
公式实际上是同一公式,您必须将原始公式错误地放入,因为(v /(v + m))* R +(m /(v + m))* C与(v * R + m * C)/(v + m)。链接:goo.gl/IW9s1A
ParoX

我认为,如果我做对的话,对5级的1票大于对4级的5票。排名系统并不正确
Daniel

23

埃文·米勒(Evan Miller)显示了一种贝叶斯方法来对5星级评分进行排名: 在此处输入图片说明

哪里

  • nk是-k星级评分的数量,
  • skk星星的“价值”(以磅为单位),
  • N 是总票数
  • K 是最大星数(例如,在5星评级系统中,K = 5)
  • z_alpha/21 - 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)]

这表明更多的评级可能会对总体星级产生影响。


您会发现,该公式的总体评级往往低于亚马逊,Ebay或沃尔玛等网站所报告的总体评级,尤其是在票数很少(例如,少于300票)的情况下。这反映出票数越少,不确定性越高。随着投票数的增加(成千上万),所有这些评分公式都应该趋向于(加权)平均评分。


由于公式仅取决于商品本身的5星级评分的频率分布,因此很容易通过简单地将频率分布加在一起来合并来自多个来源的评论(或 根据新的投票来更新总体评分)。


与IMDb公式不同,该公式不依赖于所有项目的平均得分,也不依赖于人为的最小投票截止数。

而且,此公式利用了整个频率分布-不仅是平均星数和票数。这是有道理的,因为应该将具有十个五星级和十个一星级的商品比具有二十个三星级的商品具有更大的不确定性(因此,不被评为最高):

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公式没有考虑到这一点。


2
非常感谢!我将此答案移植到了JavaScript。gist.github.com/dfabulich/fc6b13a8bffc5518c4731347de642749
Dan Fabulich

3
我也移植这个答案SQL,假设列rated5rated4rated3rated2,和rated1,这是多少人给了该等级计数。select ((5*(rated5+1)+4*(rated4+1)+3*(rated3+1)+2*(rated2+1)+1*(rated1+1))/(5+rated5+rated4+rated3+rated2+rated1))-1.65*SQRT((((25*(rated5+1)+16*(rated4+1)+9*(rated3+1)+4*(rated2+1)+1*(rated1+1))/(5+rated5+rated4+rated3+rated2+rated1)) - POWER(((5*(rated5+1)+4*(rated4+1)+3*(rated3+1)+2*(rated2+1)+1*(rated1+1))/(5+rated5+rated4+rated3+rated2+rated1)), 2))/(6+rated5+rated4+rated3+rated2+rated1)) as x from mytable
Dan Fabulich

这是最好的答案。
Cypher

因此,如果只有一个5的开始评分,那么平均值是2.5?例如。starsort([1,0,0,0,0]) 2.4036636531319653
eozzy

18

请参阅此页面,以对基于星级的评分系统进行很好的分析,而这一页的upvote- / downvote-基础的系统的一个很好的分析。

对于上下投票,您希望估算出给定的评级,“真实”得分(如果您拥有无限的评级)大于某个数量(例如,某些其他项目的相似数字)的概率重新排序)。

答案参见第二篇文章,但结论是您想使用Wilson信心。本文提供了等式和示例Ruby代码(可轻松转换为另一种语言)。


4
威尔逊置信区间仅适用于二项式分布(例如,+ 1 / -1样式等级);目前尚不清楚采用哪种方法来评估5星评级方案。
亚历克2015年

7

您可以按中位数而不是算术平均值进行排序。在这种情况下,两个示例的中位数均为5,因此在排序算法中,两个示例的权重相同。

您可以使用一种模式达到相同的效果,但是中位数可能是一个更好的主意。

如果您想为具有100个5星评级的产品分配额外的权重,则可能需要采用某种加权模式,即为具有相同中位数但总体票数更高的评级分配更多的权重。


如果我要使用中位数方法,您将如何确定哪个评级应为5x 5星级(4x 2星级)或5x 5星级(4x 1星级)?两者都会给出5分的评分。
Vizjerai

那时候取决于您。这取决于您认为哪个更好。也许您首先按中位数排序,然后按均值排序。或者,也许首先是通过中位数,然后是投票总数。
Welbog

加权中位数:先按中位数排序,然后再按均值排序。总票数可以提高分数的可靠性(置信度),但是对于分数本身并没有说明。
richardtallent

7

好吧,根据您要制作的复杂程度,您可以根据该人进行的评分以及这些评分分别对评分进行加权。如果该人仅进行了一项评分,则该评分可能是低劣的,并且可能会少计。或者,如果某人在a类中对许多事物进行了评分,但在b类中却很少,并且在5星中的平均评分为1.3,则听起来该用户的低平均得分可能会人为地压低a类,并且应该调整。

但是足够复杂。让我们简单点。

假设对于一个特定的项目,我们只使用两个值,ReviewCount和AverageRating,那么将ReviewCount本质上视为“可靠性”值对我来说是有意义的。但是,我们不仅仅希望降低低ReviewCount项的得分:单颗一星级的评价可能与单颗5星的评价一样不可靠。因此,我们想做的大概是平均水平:3。

因此,基本上,我在考虑一个方程,例如X * AverageRating + Y * 3 =我们想要的评分。为了使该值正确显示,我们需要X + Y等于1。此外,随着ReviewCount的增加,我们需要X的值增加...当评论数量为0时,x应该为0(给我们一个等式3”),并且具有无限次审核计数,X应该为1(这使得等式= AverageRating)。

那么X和Y方程是什么?对于X方程,当自变量接近无穷大时,希望因变量渐近地接近1。一组好的方程式如下:Y = 1 /(factor ^ RatingCount)和(利用X必须等于1-Y的事实)X = 1 –(1 /(factor ^ 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

这样的东西?您显然可以根据需要调整“因子”值,以获得所需的权重。


3

如果您只需要一种快速且廉价的解决方案,而该解决方案在不使用大量计算的情况下通常可以正常工作,那么这里是一个选择(假设等级为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)。您也可以辩称,它不公平地惩罚了评级很少的高质量产品。

该图表显示了1-1000个评分中所有5个评分的结果: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

显然,收视率低使这个问题成为统计上的障碍。永远不要少...

改善综合评分质量的关键要素是对评分者进行“评分”,即保持每个“评分者”已提供(相对于其他)的评分标签。这样可以在汇总过程中权衡他们的选票。

另一个解决方案,更多是应付的,是为最终用户提供基础项目的投票计数(或其范围指示)。


0

一种选择是类似于Microsoft的TrueSkill系统,其中分数由给出mean - 3*stddev,在其中可以调整常量。



-2

我强烈推荐Toby Segaran(OReilly)ISBN 978-0-596-52932-1一书,该书讨论了如何从人群行为中提取有意义的数据。这些示例在Python中进行,但转换起来很容易。


1
即使我可以将本书推荐给对该领域感兴趣的每个人,您的回答也无法提供所提出问题的解决方案。
Christian Stade-Schuldt,2010年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.