logo科技微讯

用户评论排序方法:威尔逊置信区间

作者:科技微讯
日期:2022-12-22
📝 笔记

在 v2ex 有人发帖问:如何优雅处理社交系统的评论权重?

这个帖子引起了我的兴趣,因为我写的微信小程序“通知中心”也有评论系统,我的排序方法综合考虑了点赞数、点踩数、字数、发布时间、是否被删除这五个因素,但点赞、点踩之间的权重计算我一直不太满意。

所以我认真看了这个帖子提到的以下两篇文章:

  • B 站评论系统架构设计:对评论排序,需要先计算每一条评论的排序权重,这篇文章的 “热评设计” 部份表示,计算一个评论的排序权重,需要综合考虑以下因素:点赞数、回复数、内容相关、负反馈数、“时间衰退因子”、字数加权、用户等级加权等等,其中“负反馈数”可通过“威尔逊排序”进行计算;
  • reddit's new comment sorting system:以前的 reddit 评论基本是按照点赞数和点赞率排序的,这导致发布得越早的评论越容易排在最前面,因为发布得早的评论会被更多人看到,所以更容易积累到更多的点赞,而发布得晚的评论,即使写得非常好,点赞数也会偏低,所以排序就靠后了,而靠后的评论又降低了被看到的概率,最后导致发布得晚的评论永无出头之日,后来 reddit 采用了“威尔逊置信区间”算法尝试解决这个问题。

Evan Miller 在 2009 年的一篇文章中分析了为什么要使用威尔逊置信区间(Lower bound of Wilson score confidence interval for a Bernoulli parameter)对项目进行排序,该算法解决了什么问题,以及具体的实现方法。如果你英文或数学不是很好,可以看阮一峰写的基于用户投票的排名算法,这篇文章大体上是 Evan Miller 文章的翻译,但有所补充,更易于理解。

以下是使用 javascript 对威尔逊置信区间算法的实现,核心是 lower_bound() 函数:

const epsilon = 0.0001;

//出处:https://github.com/simple-statistics/simple-statistics/blob/main/src/inverse_error_function.js
function inverseErrorFunction(x) {
  const a = (8 * (Math.PI - 3)) / (3 * Math.PI * (4 - Math.PI));
  const inv = Math.sqrt(
    Math.sqrt(
      Math.pow(2 / (Math.PI * a) + Math.log(1 - x * x) / 2, 2) -
        Math.log(1 - x * x) / a
    ) -
      (2 / (Math.PI * a) + Math.log(1 - x * x) / 2)
  );
  if (x >= 0) {
    return inv;
  } else {
    return -inv;
  }
}

//出处:https://github.com/simple-statistics/simple-statistics/blob/main/src/probit.js
function probit(p) {
  if (p === 0) {
    p = epsilon;
  } else if (p >= 1) {
    p = 1 - epsilon;
  }
  return Math.sqrt(2) * inverseErrorFunction(2 * p - 1);
}

//出处:https://gist.github.com/timelf123/dadca20e7faa17969d3eb6ee375e2c98
//参数 n 表示点赞数和点踩数的和
const lower_bound = (upvotes, n = 0, confidence = 0.95) => {
  if (n === 0) return 0;
  // for performance purposes you might consider memoize the calcuation for z
  const z = probit(1 - (1 - confidence) / 2);
  // p̂, the fraction of upvotes
  const phat = (1.0 * upvotes) / n;
  return (
    (phat +
      (z * z) / (2 * n) -
      z * Math.sqrt((phat * (1 - phat) + (z * z) / (4 * n)) / n)) /
    (1 + (z * z) / n)
  );
};

计算一个评论的权重,我觉得字数也是一个重要依据,有些用户评论就用两三个字,其价值大概率比不上十几二十字的评论,但威尔逊置信区间没有考虑字数,所以计算评论权重不应该只用上述算法。

donation赞赏
thumbsup0
thumbsdown0
暂无评论