基于用户投票的排名算法(五):威尔逊区间

作者: 阮一峰

日期: 2012年3月20日

迄今为止,这个系列都在讨论,如何给出"某个时段"的排名,比如"过去24小时最热门的文章"。

但是,很多场合需要的是"所有时段"的排名,比如"最受用户好评的产品"。

这时,时间因素就不需要考虑了。这个系列的最后两篇,就研究不考虑时间因素的情况下,如何给出排名。

一种常见的错误算法是:

  得分 = 赞成票 - 反对票

假定有两个项目,项目A是60张赞成票,40张反对票,项目B是550张赞成票,450张反对票。请问,谁应该排在前面?按照上面的公式,B会排在前面,因为它的得分(550 - 450 = 100)高于A(60 - 40 = 20)。但是实际上,B的好评率只有55%(550 / 1000),而A为60%(60 / 100),所以正确的结果应该是A排在前面。

Urban Dictionary就是这种错误算法的实例。

  

另一种常见的错误算法是

  得分 = 赞成票 / 总票数

如果"总票数"很大,这种算法其实是对的。问题出在如果"总票数"很少,这时就会出错。假定A有2张赞成票、0张反对票,B有100张赞成票、1张反对票。这种算法会使得A排在B前面。这显然错误。

Amazon就是这种错误算法的实例。

  

那么,正确的算法是什么呢?

我们先做如下设定:

  (1)每个用户的投票都是独立事件。

  (2)用户只有两个选择,要么投赞成票,要么投反对票。

  (3)如果投票总人数为n,其中赞成票为k,那么赞成票的比例p就等于k/n。

如果你熟悉统计学,可能已经看出来了,这是一种统计分布,叫做"二项分布"(binomial distribution)。这很重要,下面马上要用到。

我们的思路是,p越大,就代表这个项目的好评比例越高,越应该排在前面。但是,p的可信性,取决于有多少人投票,如果样本太小,p就不可信。好在我们已经知道,p是"二项分布"中某个事件的发生概率,因此我们可以计算出p的置信区间。所谓"置信区间",就是说,以某个概率而言,p会落在的那个区间。比如,某个产品的好评率是80%,但是这个值不一定可信。根据统计学,我们只能说,有95%的把握可以断定,好评率在75%到85%之间,即置信区间是[75%, 85%]。

这样一来,排名算法就比较清晰了:

  第一步,计算每个项目的"好评率"(即赞成票的比例)。

  第二步,计算每个"好评率"的置信区间(以95%的概率)。

  第三步,根据置信区间的下限值,进行排名。这个值越大,排名就越高。

这样做的原理是,置信区间的宽窄与样本的数量有关。比如,A有8张赞成票,2张反对票;B有80张赞成票,20张反对票。这两个项目的赞成票比例都是80%,但是B的置信区间(假定[75%, 85%])会比A的置信区间(假定[70%, 90%])窄得多,因此B的置信区间的下限值(75%)会比A(70%)大,所以B应该排在A前面。

置信区间的实质,就是进行可信度的修正,弥补样本量过小的影响。如果样本多,就说明比较可信,不需要很大的修正,所以置信区间会比较窄,下限值会比较大;如果样本少,就说明不一定可信,必须进行较大的修正,所以置信区间会比较宽,下限值会比较小。

二项分布的置信区间有多种计算公式,最常见的是"正态区间"(Normal approximation interval),教科书里几乎都是这种方法。但是,它只适用于样本较多的情况(np > 5 且 n(1 − p) > 5),对于小样本,它的准确性很差。

1927年,美国数学家 Edwin Bidwell Wilson提出了一个修正公式,被称为"威尔逊区间",很好地解决了小样本的准确性问题。

  

在上面的公式中,表示样本的"赞成票比例",n表示样本的大小,表示对应某个置信水平的z统计量,这是一个常数,可以通过查表或统计软件包得到。一般情况下,在95%的置信水平下,z统计量的值为1.96。

威尔逊置信区间的均值为

  

它的下限值为

  

可以看到,当n的值足够大时,这个下限值会趋向。如果n非常小(投票人很少),这个下限值会大大小于。实际上,起到了降低"赞成票比例"的作用,使得该项目的得分变小、排名下降。

Reddit的评论排名,目前就使用这个算法。

  

[参考文献]

  * How Not To Sort By Average Rating

(完)

留言(42条)

这个算法很好啊,可以用在paper里边了。我是做机械工程的。多谢多谢。

顶,又是一个不错的算法!

很好的系列

概率论又一次立功了,赌徒的艺术!

整个系列看下来,收获很多

其实我觉得一个简单函数就可以解决此问题: score = 赞成比例 * min(投票数, 100)

1. 当投票数100时,score取决于赞成比例。

2. 若一个

2. 若一个小于100投票数的物品要排到大于100投票数且好评率为n%的物品前面,就必须有至少n个好评。或积累100个投票后,靠好评率胜出。

引用suranxu的发言:

2. 若一个小于100投票数的物品要排到大于100投票数且好评率为n%的物品前面,就必须有至少n个好评。或积累100个投票后,靠好评率胜出。

如果我没理解错,赞成比例应该是这样计算:赞成比例 = 好评数/投票数。

则,当投票数小于100,score = (好评数/投票数)*投票数 = 好评数

当投票数大于等于100, score = (好评数/投票数)*100

因为投票数大于等于100,所以此时score应该是等于好评数乘以一个小于等于1的系数,该系数与投票数成反比。

也就是说,相同的好评数,投票数越多,得分越低。

挺好的。

楼主您好:

我拜读了这篇文章,收获很多.但是我对该文章对二项式分析一个地方有点质疑:

文章说"如果投票总人数为n,其中赞成票为k,那么赞成票的比例p就等于k/n。如果你熟悉统计学,可能已经看出来了,p服从一种统计分布,叫做"两项分布"(binomial distribution)。"

我觉得得票比例p不符合二项分布. 应该是 总票数为n,在得票比例为p情况下,获得赞成票的次数k的概率 符合二项分布 P(X=k) = C(n,k) * p^k * (1-p)^(n-k)

k= 0,1,2,3....n 其中C(n,k) = n!/ (k!*(n-k)!)

如果 比例p不符合二项分布,那么后面的结论就都不对了.

还望楼主帮忙分析下我的理解对不对. 谢谢!

引用Wesker的发言:

楼主您好:

我拜读了这篇文章,收获很多.但是我对该文章对二项式分析一个地方有点质疑:

文章说"如果投票总人数为n,其中赞成票为k,那么赞成票的比例p就等于k/n。如果你熟悉统计学,可能已经看出来了,p服从一种统计分布,叫做"两项分布"(binomial distribution)。"

我觉得得票比例p不符合二项分布. 应该是 总票数为n,在得票比例为p情况下,获得赞成票的次数k的概率 符合二项分布 P(X=k) = C(n,k) * p^k * (1-p)^(n-k)

k= 0,1,2,3....n其中C(n,k) = n!/ (k!*(n-k)!)

如果 比例p不符合二项分布,那么后面的结论就都不对了.

还望楼主帮忙分析下我的理解对不对. 谢谢!

嗯,应该是k服从二项分布。在计算p的置信区间时,可假设p是渐近正态的,从而算出置信区间。

@Wesker:

你说得对,应该是K服从二项分布。

我对统计还是不熟,这里已经改过来了。谢谢指出。

这个地方不影响下面的结论,那些公式本来就是针对p的(二项分布的比例)。

理解了“置信区间”的意义,多谢阮哥

亚马逊里面的那个例子,用户可不是只有两个选择,而是从一星到五星的评级。虽然从结果来讲也是不合适的,但是也不适用两项分布、威尔逊区间的吧。

「两项分布」,这个说法从来没听过,以至于我以为是什么新东西呢。。。

还是按国内的习惯改成二项分布吧

用Bayesian inference,共轭函数选Binomial不就行了,不需要搞这么复杂的公式。

引用yangwenli的发言:

还是按国内的习惯改成二项分布吧

谢谢指出,已经更正了。

好算法,我以前一直以为热门文章的算法很简单,就是挑浏览量最大的,我的wordpress博客就是这样的

哥哥好哦~追你博蛮久了,偶是名大四女生,热爱写作、分享idea.之前全在门户网站的空间写blog,但到这后,自己开独立blog的想法非常强烈,我希望也能开一个像这里一样的自由独立的博~~~泪求哥哥指点一二啊。。。
前面看过如何开的日志说明,但那些对我还是难了点。。还有,请问要money吗?要向谁申请吗?申请困难吗?

引用Janet的发言:

自己开独立blog的想法非常强烈,我希望也能开一个像这里一样的自由独立的博~~~

如果你不懂技术,还是不要开独立Blog了,非常麻烦,还要花钱。

要是能翻墙,我非常推荐Blogger和Tumblr的服务。

书到用时方恨少啊!
以前学概率和统计的时候感觉很枯燥,不知道学了有什么用,现在发现很多领域都要用到这些知识。如果以前在学的时候早点接触到这些需要用到这方面知识的领域时就可以更加针对性的学了,有动力,也不会感到枯燥了。得补补了~

让我对置信上下界的理解加深了,也就是说,我们在考虑用统计值来估计真实情况的时候,都应该考虑置信界限,否则在采样不够的时候,会有差别较大的判断。

Thanks....

写的好复杂,简单地说,就是根据置信区间的下限进行排名嘛。

引用爱早起的发言:

好算法,我以前一直以为热门文章的算法很简单,就是挑浏览量最大的,我的wordpress博客就是这样的

最简单的就是按照浏览量的。就一个权。
除了浏览量,还需要考虑回复,文章引用,回复的引用,打分等等!

这种东西都是需要加权的,各种权重有自己的比例,然后综合运算。

引用zisasign的发言:

如果我没理解错,赞成比例应该是这样计算:赞成比例 = 好评数/投票数。

则,当投票数小于100,score = (好评数/投票数)*投票数 = 好评数

当投票数大于等于100, score = (好评数/投票数)*100

因为投票数大于等于100,所以此时score应该是等于好评数乘以一个小于等于1的系数,该系数与投票数成反比。

也就是说,相同的好评数,投票数越多,得分越低。

挺好的。

A好评数10,总投票数10,那得分是10
B好评数500,总投票数5000,得分也是10
这样到底合不合理呢

这里的回复系统是不是有问题,前几天我发了个回复,今天回来看就不见了

这个系列读下来,收获很多。4年开始学习计算机的时候,不明白为什么“软件的本质是数学”,今天终于领悟一点点了, 谢谢LZ!!

现在才发现概率论是有用的。

引用suranxu的发言:

2. 若一个小于100投票数的物品要排到大于100投票数且好评率为n%的物品前面,就必须有至少n个好评。或积累100个投票后,靠好评率胜出。

关键是你的那个100如何确定的?

百度搜索排名算法找过来的,认真拜读了博主的“基于用户投票的排名算法”多篇文章,收获颇多。如果不基于用户投票,而且一个商品的评价数、评分,应该如何排名呢?

> 表示对应某个置信水平的z统计量,这是一个常数,可以通过查表或统计软件包得到。一般情况下,在95%的置信水平下,z统计量的值为1.96。

请问这个常数表是什么表,哪里可以得到?

我用这个算法做 了一些实践,发现有些区间边界不理想,想调整这个常数试试。

引用quady的发言:

A好评数10,总投票数10,那得分是10
B好评数500,总投票数5000,得分也是10
这样到底合不合理呢


如果只看这一瞬间快照的话,好像很不合理,明显A商品吃亏了。

但其实我觉得把时间跨度放长一些,这并不是一个系统性问题。一方面,如果A商品确实是一个被广泛认可的好商品(而不是一个极其小众的“好商品”),它会快速积累到更多投票(想象一个新出的电影,或者一个性价比卓越的新卖家,它的投票不不会因为默认排名不靠前就积累不到新的投票),很快就会超过B商品。另一方面,如果A商品真的就此止步于此,没有人再给它投票,如此小众的商品真的应该排在B的前面吗。比如“日常用品”频道首页到底应该排除一个劣质的马桶垫,还是排出一款非常好用便宜实惠的“宇航员太空便便吸收器”?真的要选择其一吗?

引用丕子的发言:

关键是你的那个100如何确定的?

我...拍脑袋想的。Orz请各位学院派大大们原谅我的暴虐吧。>_

其实写100主要是它数学形式上看起来比较好看,同时100这个数基本又能满足可信性。这其实这就是一个票数少于阈值时降权的山炮模型,参数值可以调,个数也可以再加。

我想表达的是,其实一些复杂模型数学上可能很漂亮,但实际效果相对简单规则模型往往提升了了,甚至会下降,而巨大的性能消耗在真实的线上环境上很多并不适用。(其实博主的例子比较特殊,因为投票毕竟不是一个频繁行为,如果换个场景,把好评换成点击,投票换成PV呢,点击每秒都在发生,PV每秒可能成千上万了,都这么算根本吃不消呵)

有一个小问题,假如赞成票和反对票都是0时下限值应该怎么计算?

大家好,我在我的网站上采用了阮先生介绍的这个威尔逊区间算法,
来决定1个词条下不同定义的排位顺序。
我的网站是用python下的Django开发的,
因此实现起来也有现成的代码可用。
欢迎来参观指导。
http://liyuwiki.com/technologies.html

有个疑问,请问置信区间怎么取?

请问这个常数表在哪里查的啊?能给个链接么?


引用闲耘的发言:

> 表示对应某个置信水平的z统计量,这是一个常数,可以通过查表或统计软件包得到。一般情况下,在95%的置信水平下,z统计量的值为1.96。

请问这个常数表是什么表,哪里可以得到?

我用这个算法做 了一些实践,发现有些区间边界不理想,想调整这个常数试试。

置信区间,你假设的依据是什么?同样都是80%的好评,为什么一个的置信区间75%-85% 另一个是70%-90%, 这个依据什么?

要用二项分布做估计,用户投票的独立假设其实是比较重要的一点,像是知乎这样社交关系影响比较大的网站,独立性其实很弱,需要进行一些修正了。

能不能不要抄别人的文章。。。

我要发表看法

«-必填

«-必填,不公开

«-我信任你,不会填写广告链接