考虑评分人数的用户评分模型

应用场景

在现实生活中我们会接触到很多评分系统,如豆瓣的书评、YouTube 的影评、StackOverflow 的回答评分等等。在这些评分中一个共同的问题是每个 item 的评分人数是不同的,因此 50000 个人打了 95 分似乎比只有 5 个人打了 95 分更能被相信该 item 是“95”分;而 50000 个人打了 90 分和 40000 个人打了 92 分的比较又如何呢?为了解决这个问题,引入了威尔逊区间法进行评分,并使用贝叶斯平滑对评分做了修正。

威尔逊区间法

威尔逊区间法是基于二项分布的一种计算方法,想法很简单,如果 100 个人打分的平均分为 85 分,那么我们可以把这个平均分看作 100 个人中有 85% 的人给了满分,而另外 15% 的人打零分。就像硬币的正反面,要不就选满分,要不就选零分,保证平均数一样就可以。在这个条件下,威尔逊区间法考虑对一个 item ,有 85% 的人“愿意选择”这件事在置信水平 $\alpha$ 下的置信区间是多少(一般选 $\alpha = 95\%$ ),然后用这个置信区间的下限来当做这个 item 的评价。这样就在一定程度上平滑了人数对评价的影响。

定义:

  • 最大评分:$S_{\mathrm{max}}$
  • 选择该 item 的人的比例:$p$
  • 评价总数:$n$
  • 统计量常数(使用置信水平计算):$K = z_{1-\frac{\alpha}{2}}$

则修正后的得分是:
$$
s = p_{\mathrm{min}} \cdot S_{\mathrm{max}}, \, p_{\mathrm{min}} = \frac{p + \frac{K^{2}}{2n} - K \sqrt{\frac{p(1 - p)}{n} + \frac{K^{2}}{4n^{2}}}}{1 + \frac{K^{2}}{n}}
$$
这个公式,有印象的同学可以发现,我在 之前的一篇博客 中提到过。

贝叶斯平滑

贝叶斯平滑其实并不是评分模式,但是它可以解决一些边界问题,比如对于评分人数过少的 item ,我们可以假设有 $C$ 个不存在的人,这些人都打了全局平均分来给总分做一个平滑。

定义:

  • 补偿人数:$C$
  • 补偿评分:$M$
  • 该 item 评分人数:$n$
  • 该 item 的得分:$s$

则平滑后的得分为:
$$
\hat{s} = \frac{CM + ns}{C + n}
$$

Python 实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
def Wilson(p, n):
"""
威尔逊区间的下限
"""
p = float(p)
K = 1.96 # 95% confidence level
_K2_div_n = (K ** 2) / n
pmin = (p + _K2_div_n / 2.0 -
K * ((p * (1 - p) / n + _K2_div_n / n / 4.0) ** 0.5)) / (1 + _K2_div_n)
return pmin
def WilsonAvgP(n):
"""
这个分数是用来充当 Bayesian 中的 M 的,取法比较随意。
本方法中是取了 0.01~1 这 100 中情况的置信区间的平均值。
其实取所有数据的总平均分也可以,总之,是一个比较平均的合理的得分就好。
"""
totalP = 0.0
totalN = 0
p = 0.01
while True:
totalP += Wilson(p, n, 1);
totalN += 1
p += 0.01
if p >= 1:
break
return totalP / totalN
def Bayesian(C, M, n, s):
"""
贝叶斯平滑
这里的 C 和 M 其实都随意取得,就像上面那个函数中说的,
只要合理并且是一个差不多平均的量就可以。
"""
return (C * M + n * s) / (n + C)