威爾遜得分 Wilson Score 排序演算法

SpikeKing發表於2017-09-05

歡迎Follow我的GitHub,關注我的掘金

威爾遜得分排序演算法,Wilson Score,用於質量排序,資料含有好評和差評,綜合考慮評論數好評率,得分越高,質量越高。

Wilson Score
Wilson Score

u表示正例數(好評),v表示負例數(差評),n表示例項總數(評論總數),p表示好評率,z是正態分佈的分位數(引數),S表示最終的威爾遜得分。z一般取值2即可,即95%的置信度。

正太分佈的分位數表:

分位數表
分位數表

演算法性質:

  1. 性質:得分S的範圍是[0,1),效果:已經歸一化,適合排序
  2. 性質:當正例數u為0時,p為0,得分S為0;效果:沒有好評,分數最低;
  3. 性質:當負例數v為0時,p為1,退化為1/(1 + z^2 / n),得分S永遠小於1;效果:分數具有永久可比性;
  4. 性質:當p不變時,n越大,分子減少速度小於分母減少速度,得分S越多,反之亦然;效果:好評率p相同,例項總數n越多,得分S越多;
  5. 性質:當n趨於無窮大時,退化為p,得分S由p決定;效果:當評論總數n越多時,好評率p帶給得分S的提升越明顯;
  6. 性質:當分位數z越大時,總數n越重要,好評率p越不重要,反之亦然;效果:z越大,評論總數n越重要,區分度低;z越小,好評率p越重要;

本文的原始碼

Python實現

def wilson_score(pos, total, p_z=2.):
    """
    威爾遜得分計算函式
    參考:https://en.wikipedia.org/wiki/Binomial_proportion_confidence_interval
    :param pos: 正例數
    :param total: 總數
    :param p_z: 正太分佈的分位數
    :return: 威爾遜得分
    """
    pos_rat = pos * 1. / total * 1.  # 正例比率
    score = (pos_rat + (np.square(p_z) / (2. * total))
             - ((p_z / (2. * total)) * np.sqrt(4. * total * (1. - pos_rat) * pos_rat + np.square(p_z)))) / \
            (1. + np.square(p_z) / total)
    return score複製程式碼

威爾遜得分演算法的分佈圖

分佈
分佈

例項:假設醫生A有100個評價,1個差評99個好評。醫生B有2個評價,都是好評,那哪個應該排前面?
在z=2時,即95%的置信度,醫生A的得分是0.9440,醫生B的得分是0.3333,醫生A排在前面。


PS:評分等級問題:如五星評價體系,或者百分評價體系,該怎麼辦呢?

將威爾遜得分的公式由 伯努利分佈 修改為 正態分佈 即可。

wilson_norm
wilson_norm

注意:均值和方差均是歸一化之後的數值。

Python實現:

def wilson_score_norm(mean, var, total, p_z=2.):
    """
    威爾遜得分計算函式 正態分佈版 支援如5星評價,或百分制評價
    :param mean: 均值
    :param var: 方差
    :param total: 總數
    :param p_z: 正太分佈的分位數
    :return: 
    """
    # 均值方差需要歸一化,以符合正太分佈的分位數
    score = (mean + (np.square(p_z) / (2. * total))
             - ((p_z / (2. * total)) * np.sqrt(4. * total * var + np.square(p_z)))) / \
            (1 + np.square(p_z) / total)
    return score複製程式碼

歸一化的示例:

def test_of_values():
    """
    五星評價的歸一化例項,百分制類似
    :return: 總數,均值,方差
    """
    max = 5.  # 五星評價的最大值
    min = 1.  # 五星評價的最小值
    values = np.array([1., 2., 3., 4., 5.])  # 示例

    norm_values = (values - min) / (max - min)  # 歸一化
    total = norm_values.size  # 總數
    mean = np.mean(norm_values)  # 歸一化後的均值
    var = np.var(norm_values)  # 歸一化後的方差
    return total, mean, var複製程式碼

PS:關於z引數,即正太分位數。正太分位數影響wilson得分的分佈,z引數取值依據就是樣本數的量級。舉個例子:同樣是100個樣本,90個好評,z取值2或6,分數差別很大,體系所容納(或區分)的樣本數也相差較大(同樣是0.82分和90%好評率,z=2需要100個樣本,z=6需要1000個樣本),一般而言,樣本數的量級越大,z的取值大。

print 'score: %s' % wilson_score(90, 90 + 10, p_z=2.)
print 'score: %s' % wilson_score(90, 90 + 10, p_z=6.)
print 'score: %s' % wilson_score(900, 900 + 100, p_z=6.)

# 取值2-100:score: 0.823802352689
# 取值6-100:score: 0.606942322627
# 取值6-1000:score: 0.828475631056複製程式碼

參考:Binomial proportion confidence intervalNormal distributionHow Not To Sort By Average RatingRelationship between Binomial and Normal Distributions

Thanks @boyi老師

相關文章