文章排序的那些事·一

事先说明:这是一篇会让人想吐的文章,如果你看到一半感到身体不适,请果断关闭浏览器。


问题提出

在一个以页为单位的信息交流平台上,一个不可避免的问题就是如何为这些信息做一个恰当的排序。
  这种行为的出发点有很多,比如要找出最有用的信息,最受欢迎的信息,最让人喜欢或者讨厌的信息,最有趣的新闻,最Hot的热点,等等,这都需要排序。
  排序的指标是什么,指标如何量化,这些都不是本文要说的内容,于是忽略不提。
  那么,我们假定已经为文章列表{A_i}订好了一个属性I(A_i),来表示这个量化的排序指标,剩下的事情就容易了,以I(A_i)为指标做降序(或者升序)处理,事情就做完了。
  似乎一切都很简单。

下面,让问题复杂一点,假定一个平台上有N个人,文章A_i被其中的n(A_i)个人看过,并被赋予了指标值I(A_i),请问如何排序?
  乍看之下,这个问题似乎没什么营养,还是根据I排序就好了嘛。
  但,如果我们将问题这么描述,会如何呢——
  给出一篇文章在整个平台上的预期受欢迎程度,并以此来排序(假定I表示的就是受欢迎程度)。
  显然,既得值I(A_i)并无法完全表达“预期受欢迎程度”这个需要的量。
  一个最简单的做法,就是I_pre(A_i)=I(A_i)/n(A_i)*N。
  从这里开始,问题就要开始变得复杂了,而且是越来越复杂。

一个可选的方向,是下面分析文章A_i的兴趣集,并且和人群的兴趣集做分析,以此来给出在离散空间中的耗散动力学,这基本算是网格模拟的问题,我们这里不做进一步考虑。

另一个这里更有兴趣的问题,就是考虑上“时间”的因素,来看看对“预期”这个谓词来说,会带来什么样的影响。
  比如说,如果我们将文章的“点击数”和“点赞数”的比值作为评判一篇文章质量的标准,那么显然这个值是会随着时间的改变而改变的,那么我们如何获得这个值的“真实正确”值,来建立一个合理的排序呢?

所以,下面的内容就是建立各种模型,来模拟N个元素中n个已经参与过投票的情况下,如何推算出最终的弛豫值。


最简模型及其近似解

现在重新明确一下问题,并做恰当的简化:


  现在有两个空间A和B。A中有N个元素,B中有P个元素。
  A中元素可以对B中元素做两个操作x和y,且要执行y必须先执行x,且x和y只能执行一次。
  每一个时间点,A中元素都可以对B中元素进行操作,记为“一次”。
  问题:已知B中元素p第一次操作的结果为n个A中元素对其进行了x操作,m个A元素进行了y操作,求第t次x和y的可能操作数。

问题描述到这里,其实还不够完整,因为A的具体性质对上述问题有着关键的影响,于是下面给出A的性质描述:


A中元素a与b相连的概率为p。
如果a对B中元素m进行过操作y,则在下一次操作时,若b与a相连且没有对m进行过x操作,则b会对m进行x操作。
A中元素q如果对B中元素m进行了x操作,则有一定的概率q进行y操作。

到这里,事情就开始有趣起来了,我们可以建立在这样的系统上y操作的传播动力学,其基本运动方程为:


N_{n+1}=[1-(1-p)^{q N_n}](N-\sum\limit_{i=0}^n N_i)

当然,就实际来说,需要对上述式子加一个取整函数,所以就是:


N_{n+1}=Round{[1-(1-p)^{q N_n}](N-\sum\limit_{i=0}^n N_i)}

到了这一步,用计算机模拟总是没问题的,但如果想要用解析的手法来获得一些结果,则将变得素手无策。
  我们可以用一些近似的手段来处理这个函数,使得不用计算机模拟也能得到一定程度的解析结果。

第一步,是将上述差分方程做一个近似,其近似前提是A的元素总数N足够大、p足够小:


N_{n+1}=p q N_n (N-\sum\limit_{i=0}^n N_i)

第二步,是给出差分方程近似的微分方程:


y: \sum\limit_{i=0}^n N_i
y': N_n
y'': N_{n+1}-N_n
y''=Cy'[pq(N-y)-1]

这里的C是由差分和微分的转变而带来的系统参数,我们可以通过第一代数据的简单计算来作拟合,从而是解析的。
  这个方程的解为:


S_n = \sum \limit_{i = 0}^n N_i) = [p q N - 1 + tanh(C n + A)] / (p q)
N_n = [tanh(C n + A) - tanh(C n + A - C)] / (p q) n > 0

其中A为待定参数,由代数方程y(0)=N_0给出,这里的N_0是第0代的“初始”进行x操作的A的元素的数量,因此参数A也是可以通过初始条件解析得到的:A = arctanh[1 - p q (N - N_0)]
  进而利用第一代数据N_1=y(1)-y(0)给出待定系数C:C = arctanh[1 - p q (N - N_0 - N_1)] - A
  而N_1可以通过已知条件获得:N_1 = [1 - (1 - p) ^ {q N_0}] (N - N_0)

而最后,原本用取整函数来获得的“截断”则由y'(t)   具体截断方程为:


B > [tanh(C m + A) - tanh(C m + A - C)] / (p q)

从而可以得到截断临界时间m,并利用m获得最想要的数据:S_m。
  到这一步,所有数据都可以解析获得,于是我们可以很好地分析传播相关的各种性质,包括一篇B中元素可以获得的最终x操作数X = S_m(最终y操作数显然为Y = X q = q S_m)。

到这里,我们先来看一下对最终的排序来说,这样的模型和最一开始的模型到底有什么不同。

最根本的不同,就在于原来排序的指标是q N,而现在则变为了q S_m。
  而,如果排序是根据当前值(第n代就是q S_n)来做排序的判断,那么可以看到,由于传播的动态性,这样的排序会是很有意思的。
  我们这里主要感兴趣的,是初试y操作数量N_0、相连几率p和x操作转化为y操作的几率q对于最后的稳定值q S_m的影响以及对整个序列q S_n的影响是怎么样的。

由于这里所做的近似都是在N足够大、p足够小这个前提下的(这也就是说,当S_n接近N时上述近似其实已经失效了,也所以截断方程其实是需要通过实验来拟合出合适的B才能正常使用的而不能通过理论分析获得),所以在这个前提下我们可以得到如下近似结果:


M = p q N - 1
S_n = [M + tanh(C n + A)] / (p q)
N_n = [tanh(C n + A) - tanh(C n + A - C)] / (p q)
A = N_0 / N / (1 - M) - arctanh(M)
C = p q N_0 / (1 - M)
N_1 = p q N N_0

So:
m = {arccosh{sqrt[N_0 / B / (1 - M)]} + arctanh(M)} (1 - M) / (p q N_0) - 1 / (p q N)
C m + A = arccosh{sqrt[N_0 / B / (1 - M)]}
S_m = N - {1 - sqrt[1 - (2 - p q N) B / N_0]} / (p q)

从而可以看出,N_0基本上决定了函数的上升速度,p q虽然也能起到类似的作用,但并不是简单的线性关系(p q / (2 - p q N))。
  而最有趣的部分则在于最终的稳定值S_m上:初试值N_0约小,则最终稳定值S_m也约小;而和传播相关的属性pq则在某个特定值前越小,最终稳定值S_m也约小,特定值之后越大则S_m越小,但这个特定值本身却不小,从而打破了p为小值的前提。
  现在,如果我们要排序的话,其实更好的预测值应该是q S_m = q N - {1 - sqrt[1 - (2 - p q N) B / N_0]} / p

不得不说的是,这是利用N足够大和pq足够小这两个前提构造出的近似分析,尤其在截断发生的部分,这种近似本身就值得商榷,所以只是一种定性分析的手段而已。

上面是通过模型,正向推倒出我们可观测的现象,也就是每一段时间x操作和y操作数的变化情况。
  在实际使用的时候,我们往往需要用到的是反向的问题——如何通过x操作和y操作的数据列,来反推出模型种的那些参数?
  也就是,如果我们知道的是N和N_n(代表了x操作数),以及y操作数Y_n,如何求出最重要的参数p和q?

q的获得相对来说很容易q = Y_n / N_n。p的获得也还可以:


p = 1 - [1 - N_{n+1} / (N - S_n)] ^ [1 / q / N_n]

但,这都是理论上的情况,实际上我们所获得数据都不可能是正好的理论值,都有误差,于是下面就要看误差会导致怎么样的改变。

先将上述运动方程用更好的方式来重写一下:


第n代的x操作数为X_n,y操作数为Y_n,x操作总数为R_n,y操作总数为T_n。
R_n = sum{X_i, i = 0 ~ n}
T_n = sum{Y_i, i = 0 ~ n}
Y_n = q X_n
X_{n + 1} = [1 - (1 - p) ^ Y_n] (N - R_n)

在这样的情况下,如果在某一代n上,X_n和上述计算获得的值(|X|_n)相比有一个dX_n的偏差,那么我们就要来看一下这个偏差在下一代数据上会导致什么样的偏离:


X_n = |X|_n + dX_n
Y_n = q |X|_n + qdX_n + dY_n
R_n = |R|n + dX_n
T_n = |T|n + qX_n + dY_n
X
{n + 1} = |X|
{n+1}
- {1 - (1 - p) ^ Y_n [1 - q ln(1 - p) (N - R_n)]} dX_n
- (1 - p) ^ Y_n ln(1 - p) (N - R_n) dY_n

在p和q很小的极限下,上述结果则可以写为:


X_{n + 1} = |X|_{n+1}
-p [Y_n - q (1 - p Y_n) (N- R_n)] dX_n
+ p (1 - p Y_n) (N - R_n) dY_n

这个数据有点意思。
  可以看到,由于n代的Y_n的扰动dY_n引起的n+1代的的扰动的系数,是恒正的,但对于X_n的扰动dX_n来说则不一定。
  更重要的是,这个数据几乎不出意外地是在不断减小的——因为Y_n即便某一次会增大,但其作为一个小于一的数的幂次,产生的影响几乎不能和N - R_n相比,而这个是随着n的增加恒减小的。
  同时,在早期,从上述分析可以看到,dY_n引起的扰动的比例系数近似等于p N,而这个值则近似等于一个节点的“邻点”个数,从而基本是一个大于1的值——因此,这就表示早期扰动对数据的影响是逐渐放大的,会极大地影响到X_n的生成。
  而随着R_n的积累,这种偏差也会被极快地消除——事实上,当Y_n达到一个极大值后开始减小后,Y_n的干扰基本就会自我消除——从前面获得近似解析解可以看到,系数A中由于存在1 - p q (N - N_0),从而在很大程度上A是负值,这就表示sech(C n + A)会是一个先升后降的函数,从而N_n也将在很大程度上是这种函数,而这样的函数在升到最顶端的时候,其实N - R_n便已经积累到接近一半的值了,而Y_n又是最大,从而此时dY_n的影响因子已经变得足够小了。
  所以,总结来说,早期dY_n的影响对整个系统是最大的,此后影响越来越小。而当Y_n开始下降后,dY_n的影响基本可以不做考虑。
  从而,对Y_n来说,早期数据由于扰动过大从而不宜做太多的考虑,后期的Y_n的数据则比较可信。
  而对于X_n的扰动来说,情况则更微妙——
  存在一个临界条件Y_n < q (N - R_n),当条件满足时,dX_n最终对X_{n+1}的影响是正反馈,而当这个条件被破坏时,则变成了负反馈——即使扰动会自己消减。
  可以看到,dY_n的影响始终是累计的,只不过影响因子在不断减小(后期),而dX_n的不单单会累计,还会彼此抵消。
  综合这两项分析可知,当Y_n序列(也即X_n)序列达到最大值的时候开始,是最统计的最佳阶段。在此之前的数据误差起到的作用都会比此后要大。

具体到实际操作中,也就是如果我们获得了文章的点击数序列X_n和点赞数序列Y_n,那么前一段时间的数据可以不计如统计,而从X_n开始下降的时刻开始统计。

不过必须要提醒的是,这么做的一个前提,就是假定只有一篇文章,且模型别的方面不出现别的扰动(比如肯定会有的p和q的扰动,以及系统并不能使用平均场假设这一根本性差异)。

当然,有趣的事情到这里还没有结束。

我们接下来开始引入“相互作用”的环节。

你可能感兴趣的:(文章排序的那些事·一)