数学之美:Reddit的排名算法
上一篇文章介绍了 Hacker News 的排名规则。这次要介绍的是另外一个社会化新闻类网站 Reddit 。Reddit对文章和评论使用了不同的排名算法,这边文章要介绍的是前者,后面的关于评论的排名在后面的文章作再作介绍。 Reddit与Hacker News有很大的不同点就是,Hacker News文章标题前面只有一个向上的小箭头,即只能投赞成票,而Reddit的每个文章标题前会有两个箭头,即一个向上,一个像下。分别代表“赞成”与“反对”。 Reddit已经把他们的所有源代码进行了公开,你可通过如下地址( https://github.com/reddit/reddit)进行下载研究。具体涉及到排序部分的代码如下: https://github.com/reddit/reddit/blob/master/r2/r2/lib/db/_sorts.pyx。为了效率,由于此部分代码是使用Python的C语言扩展来写,下面是用Python重写的代码:
from datetime import datetime, timedelta from math import log epoch = datetime(1970, 1, 1) def epoch_seconds(date): """Returns the number of seconds from the epoch to date.""" td = date - epoch return td.days * 86400 + td.seconds + (float(td.microseconds) / 1000000) def score(ups, downs): return ups - downs def hot(ups, downs, date): """The hot formula. Should match the equivalent function in postgres.""" s = score(ups, downs) order = log(max(abs(s), 1), 10) sign = 1 if s > 0 else -1 if s < 0 else 0 seconds = epoch_seconds(date) - 1134028003 return round(order + sign * seconds / 45000, 7)
从上面的代码中可以看到整个逻辑并不复杂,下面就来深入研究下起实现的方式。以下为对于代码中使用到的数学公式的描述。
从上面的代码级公式中我们可以了解到Reddit的排名算法主要与以下内容有关:
1、文章的发表时间t
t = 发表时间 – 2005 年 12 月 8 日7:46:43
在上一篇 Hacker News的文章中,用来标注文章新旧程度的单位为小时,而Reddit的单位为秒,其使用Unix时间戳(从1970年1月1日到当前时间的秒数)进行的计算,代码中的1134028003代表的日期为2005 年 12 月 8 日7:46:43。这个应该是Reddit这个网站的上线时间。通过上面的公式可以看到一旦帖子发表,t就是固定值,不会随时间改变,而且帖子越新,t值越大。
发表时间和话题排名的影响可以被概括如下:
- 发表时间对排名有很大影响,该算法使得新的话题比旧的话题排名靠前
- 话题的得分不会因为时间的流失而减少,但是新的话题会比旧的话题得分高。这与 Hacker New 的算法不同 (随着时间的发展降低话题的得分)
下图展示了话题得分在好评和差评的数量不变时,随着时间而变化的情况:
2、赞成票与反对票的差x
x = 赞成票 – 反对票
真是由于Reddit提供了投反对票的功能,所以可以使一些具有争议的话题会排的较后,下图展示了在好评和差评不变时,随着时间而变化的情况:
3、投票方向y
y 是一个符号变量,表示对文章的总体看法。如果赞成票居多,y就是 +1;如果反对票居多,y就是-1;如果赞成票和反对票相等,y就是0。y是文章评价的一种定性表达,0表示没有倾向,大于0表示正面评价,小于0表示负面评价。
4、帖子的受肯定程度z
z 表示赞成票超过反对票的数量。如果赞成票少于或等于反对票,那么z就等于1。
结合以上几个变量,Reddit 的最终得分计算公式如下:
这个公式可以分成两个部分来讨论:
1、logZ
这个部分表示,赞成票超过反对票的数量越多,得分越高。 需要注意的是,这里用的是以 10 为底的对数,意味着z=10可以得到 1 分,z=100可以得到 2 分。也就是说,前 10 个投票人与后 90 个投票人(乃至再后面 900 个投票人)的权重是一样的,即如果一个帖子特别受到欢迎,那么越到后面投赞成票,对得分越不会产生影响。而当反对票超过或等于赞成票,z=1,因此这个部分等于0,也就是不产生得分。
Reddit 的热排序算法使用了对数函数来衡量前面的投票与其他投票的差距使其前十个好评和之后的100个,1000个投票有相同的权重。 参见下面的图:
如果不采用对数,而使用线性函数的效果如下:
Reddit敢于如此消弱投票的作用,其实与其庞大的流量和用户参与度相关。如果没有以上因素算法很难实现很好的推荐。
2、yt/45000
这个部分表示,t越大,得分越高,即新帖子的得分会高于老帖子。它起到自动将老帖子的排名往下拉的作用。 分母的 45000 秒,等于 12.5 个小时,也就是说,后一天的帖子会比前一天的帖子多得 2 分。结合前一部分,可以得到结论,如果前一天的帖子在第二天还想保持原先的排名,在这一天里面,它得到的净赞成票必须增加100 倍。
y 的作用是用来产生正分和负分。当赞成票超过反对票时,得分为正;当赞成票少于反对票时,得分为负;当两者相等,得分为0。这就保证了得到大量净赞成票的文章,会排在前列;得到大量净反对票的文章,会排在最后。投票对于总分的贡献不大,但是当投票的意见倾向发生变化时(由正面评价转向负面评价),投票对于总分的作用却是决定性(Y的取值)。
总结
以上内容分析这么多,是该进行总结的时候了,关于Reddit的排名,基本上是由发表时间决定的,只有相同时段的文章才有可比性。晚半天,投票就要翻10倍,只能同时段的文章相比。只有超级受欢迎的文章才会排在最前面,有争议或者一般性的文章很难靠前。基于上述也就决定了 Reddit是一个符合大众胃口的网站,并不是一个很激进可以展示少数派想法的地方。
说了这么多,再来看下Reddit与Hacker News的区别,到底哪一个的算法更好一些呢?其实算法并没有优劣之分,两种方法更有千秋,重要的是你打算用在什么地方。Reddit流量大,所以可以减少投票的权重,而也因为流量大,使得每篇文章在没有收到新的投票的时候无需重新计算得分,也可大大的减少服务器的运算成本。
参考文章: http://amix.dk/blog/post/19588
Related posts: