我正在尝试使用5星系统按客户评分对一堆产品进行排序。我为此设置的网站收视率不高,并且会继续添加新产品,因此通常会有一些收视率低的产品。
我尝试使用平均星级,但是当评分较少时,该算法将失败。
例如,具有3x 5星级的产品要比具有100x 5星级和2x 2星级的产品更好。
第二个产品是否应该因为较高的评分数量而在统计上更值得信赖,从而显示出更高的价格?
Answers:
在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);
变量是:
[1, 5]
。,依此类推。)[2, 3, 5, 5]
.C为3.75,即这些数字的平均值。)所有公式的作用是:在计算平均值之前,先添加m个虚构的投票,每个投票的值为C。最初,当没有足够的数据时(即,票数大大少于m),这将导致空白填充平均数据。但是,随着选票的累积,最终虚构的选票将被真实选票淹没。
在此系统中,投票不会导致评分波动剧烈。取而代之的是,他们只是在某个方向上干扰了它。
当票数为零时,仅虚数票存在,且所有票数均为C。因此,每个项目都以等级C开头。
也可以看看:
埃文·米勒(Evan Miller)显示了一种贝叶斯方法来对5星级评分进行排名:
哪里
nk
是-k
星级评分的数量,sk
是k
星星的“价值”(以磅为单位),N
是总票数K
是最大星数(例如,在5星评级系统中,K = 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)]
这表明更多的评级可能会对总体星级产生影响。
您会发现,该公式的总体评级往往低于亚马逊,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公式没有考虑到这一点。
rated5
,rated4
,rated3
,rated2
,和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
starsort([1,0,0,0,0]) 2.4036636531319653
好吧,根据您要制作的复杂程度,您可以根据该人进行的评分以及这些评分分别对评分进行加权。如果该人仅进行了一项评分,则该评分可能是低劣的,并且可能会少计。或者,如果某人在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
这样的东西?您显然可以根据需要调整“因子”值,以获得所需的权重。
如果您只需要一种快速且廉价的解决方案,而该解决方案在不使用大量计算的情况下通常可以正常工作,那么这里是一个选择(假设等级为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
您可以在最底层的评分中看到向上倾斜,但我认为总体上来说这是一个公平的排名。您也可以这样看:
如果您将大理石放在该图的大多数地方,它将自动滚动到得分更高和评级更高的产品上。
经过一会儿,我选择了贝叶斯系统。如果有人在使用Ruby,请在此处查看:
我强烈推荐Toby Segaran(OReilly)ISBN 978-0-596-52932-1一书,该书讨论了如何从人群行为中提取有意义的数据。这些示例在Python中进行,但转换起来很容易。