如何调整友链的位次使访客流量分发均等化

2020-04-17

引子

友链是指网站和网站之间为了吸引流量和提高搜索引擎权重而在网页上显示的超链接,用户点击一个这样的超链接之后网页浏览器会跳转到另外一个网站,相应地,跳转到的那个网站也会有指向这个网站的超链接,这样的互链称为友链或者叫做友情链接.有两个问题,可能大多数站长都想过:第一,如果说按照添加顺序决定友链的摆放位置靠前还是靠后,这样公平么?第二,如果说这样不公平,那怎样调整友链的摆放位次才能变得公平呢?注意这里的公平是指,如果一个网站给咱带来的流量多,咱给这个网站带去的流量(即访客点击这个友链的次数)也多,反之如果一个网站给咱带来的流量少,那相应地咱带去的流量也少,谓之公平,也就是对方带给咱的流量和咱带给对方的流量成比例.至此希望您已经对我们即将要在这篇文章中讲的基本内容有了大概的了解.

几个实验

即将模拟这样的情形:一个博客,随着时间的发展,加上的友链越来越多,访客量也越来越多,在这样的背景下,我们来看:1)随着时间推移访客累积点击了各个位置的友链多少下;2)随着时间推移各个位置累积给我们带来了多少流量.具体地,会是这样:假如说我们要模拟总共$N$天的情况,那就会有一个$N$行的表格,这个表格的每一行对应每一天的情况,怎么说呢?在每一行,会有这么几个字段:该天访客数,该天已有的友链数,该天访客都点击了哪些友链,该天收到了来着哪些友链的流量,根据这些信息,我们可以总结出实验数据用于分析,现在先看一下这张表的原型,没有标明天数,因为第几行就是第几天

访客数 友链数 访客点击 友链流量
328 15 1->4,2->1,3->9,… 1->20,2->9,3->7,4->3,…
348 15 1->3,2->7,3->6,… 1->2,2->4,3->1,4->6,…
297 16 1->0,2->5,3->4,… 1->14,2->5,3->0,4->1,…
356 17 1->7,2->9,3->1,… 1->22,2->4,3->1,4->8,…

上表举例的是4天的模拟,例如说第一行,1->4就表示有4个访客点击了排第1位的友链,3->9表示9个访客点击了排第3位的友链,而1->20表示排第1位的友链为咱们带来了20个访客,其他行也是类似的道理.就像这样的一张表呢,它可以通过收集访客数据获得,但是我们实际上没有收集这些数据,所以只能对这些数据所服从的分布,做一些假设,然后生成服从特定分布的数据来模拟这张表,这样做其实也还是有一定意义的,因为我们会考虑几种典型的情况,而这几种典型的情况都可以用几种经典的概率分布来建模.

首先,访客数和友链数,其实一般来说,都是随着时间推移而缓慢线性增长的,这是比较自然的情况,友链数可能前期增加快点因为有些站长希望快速提高访问量,但是不管是访客数还是友链数经过前期的线性增长后,到了后期整个增长速度就逐渐趋于平衡了.然后是访客点击,这一列的数据我们怎么产生呢?我们假定第$n$天已经有了$l_n$个友链,那么,我们会设这样一个权重或者说分布列

$$ { \omega_1 \to 1, \omega2 \to 2, \cdots, \omega{l_n} \to l_n } $$

在每一天,也就是表格的每一行,我们假设当天第$n$天的访客数是$v_n$,那么就会随机产生$v_n$个随机数,这$v_n$个随机数范围也是在$1$到$l_n$,取到各个数的概率就由上面这些$\omega$来决定,这些$\omega$也可以称为访客点击权重.而至于友链流量那一列呢?友链带给我们流量的过程可以看做是一个泊松过程,如果你不知道泊松过程也没关系,主要是单个友链一天带给我们多少访客,我们假设有$X$个,那么这个$X$服从一种概率分布比如说$X$取1的概率是$p_1$,取2的概率是$p_2$,取3的概率是$p_3$,取$k$的概率是$p_k$,那么这个$p_k$一般是短暂地递增之后就一直递减的,泊松分布(描述泊松过程的随机变量服从的分布)类似就是这样,就这样,第一个友链我给它生成一个服从泊松分布的随机数,第二个友链也来个服从泊松分布的随机数,第三个,第四个,其余的,都同理,这样就可以得到第四列的数据.

更具体的描述

为了简单起见,我们不妨假定有$n$个友情链接的位置或者叫排位,数字越小,位置越靠前,数字越大,位置越靠后,然后呢,因为一个友情链接的位置,或者说一个排位,只能放下一个友情链接,因此呢,友情链接的数量也是等于$n$,即,有$n$个友链排位,和$n$个友链.

这样一来,我们的问题就可以描述清楚了,我们想知道,针对每一次用户对友链页面的访问,第1个友链应该放在哪个位置,是放在前面还是后面还是中间哪个位置,第2个友链应该放在哪个位置,……,这样一直到第n个友链应该放在哪个位置.或者同样的,第1个排位应该分配给哪个友链,第2个排位应该分配给哪个友链,……,第n个排位应该分配给哪个友链.我们设$x{ij}=1$表示第$i$个排位分配给了第$j$个友链,而当$x{ij}=0$时则表示第$i$个排位没有分配给第$j$个友链,显然,每个排位只能分配给一个友链,因此

$$ \sum{j=1}^{n} x{ij} = 1 $$

同样地,每个友链也只能被分配到一个排位

$$ \sum{i=1}^{n} x{ij} = 1 $$

这样的由$x{ij}$作为第i行第j列的元素组成的矩阵$X$,我们把它叫做「决策矩阵」或者说叫做「布局矩阵」,而$x{ij}$则是我们设置的决策变量

$$ X{n \times n} = \begin{bmatrix} x{ij} \end{bmatrix}_{n \times n} $$

例如,设想有如下的这么一个4行4列的决策矩阵$X$

$$ X = \begin{bmatrix} 0 & 0 & 1 & 0 \
1 & 0 & 0 & 0 \
0 & 0 & 0 & 1 \
0 & 1 & 0 & 0 \end{bmatrix} $$

表示的就是有4个友链(当然也就是有4个放友链的位置),第1个位置分配给了第3个友链,第2个位置分配给了第1个友链,第3个位置分配给了第4个友链,而第4个位置则分配给了第2个友链.友链在添加时就可以为其分配一个唯一标识符(例如按照添加时间决定友链的序号1,2,3等),而友链位置的标识符则是按照前后次序决定,因此,是可以把友链自身,和存放友链的槽位,是可以分别编码的.

这样一来,访客单击第1个,第2个,……,第n个友链位置的频数可以记做一组数据,例如可以统计访客点击了第1个友链位置132次,第2个友链位置87次,第3个友链位置66次,第4个友链位置62次等等,但是,用户单击第i个友链而非第i个友链位置的频数呢?如果友链按添加时间排序,那么第1个,第2个,第3个,和第4个友链的点击频数是和第1个,第2个,第3个,第4个友链位置的点击频数是相等的,但是,假如说我们每次随机决定或者按照某种算法决定一个友链是放在哪个位置,即,第1个添加的友链不一定放在第1位,第2个添加的友链不一定放在第2位,这样,第i个友链的「实际」点击频数就会和第i个友链位置的点击频数不同,这样,按照我们举的这个例子,第1个友链的点击频数就不等于第1个友链位置的点击频数132,第2个的也不等于87,我们把第i个友链位置的点击频数记做$v_i$,把第i个友链的实际点击频数记做$v_i^{\star}$,会有

$$ \sum v_i = \sum v_i^{\star} $$

$$ \exists i, j, \quad v_i \neq v_i^{\star}, v_j \neq v_j^{\star} $$

这样的现象.事实上我们无法调整$v_i$,因为访客是偏爱点击前面的友链还是偏爱点击后面的友链还是点击每个位置的友链的概率均等我们不知道,但是,如果我们假设用户点击第1个,第2个,第3个友链位置的概率分别是$p_1$,$p_2$,$p_3$,……,我们就可以每一次决定$X$是多少,从而调整$v_i^{\star}$和$v_i$的差距,从而使$v_i^{\star}$会变得大致与第i个友链为我们贡献的流量$c_i$成比例.

因此呢,我们希望,在每一次用户打开我们的友链页面时决定友链的位置布局$X$是多少,使得长久以往,我们为每个友链带去的实际流量$v_i^{\star}$,会大致和每个友链为我们带来的流量$c_i$成近似等比例关系

$$ c_1 : c_2 : c_3 : \cdots = v_1 : v_2 : v_3 : \cdots $$

譬如说,假设第1个友链,第2个友链,第3个友链和第4个友链给我们带来的流量分别是1000,378,549,1013,假设我们为这四个友链带去的流量分别是$v_1$,$v_2$,$v_3$和$v_4$,那么我们希望大致有这样的等比例关系

$$ 1000 : 378 : 549: 1013 = v_1 : v_2 : v_3 : v_4 $$

大致意思就是如果一个友链累积为我们带来的流量多,那么我们给这个友链带去的友链也相应地多,如果一个友链累积为我们带来的流量少,那么我们通过调整友链的实际放置位置,也使得我们实际为该友链带去的流量稍微减小一些.为什么这么说呢?是因为友链有添加次序,如果我们假设一个友链一天能为我们带来10个访客,第1天就加了友链1,第5天加了友链2,第7天加了友链3,第10天加了友链4,这样,到第31天,第1个友链为我们累积带来了300个访客,第2个则累积为我们带来了260个访客,第3个带来了240个访客,第4个带来了200个访客,因此,因为添加时间有差异,每个友链累积带给我们的流量是不一样的.

有多种假设

事实上,一个访客打开了友链页面后,具体点击哪一个位置的友链,是由多种可能性的,为简单起见,无妨假设一个访客打开咱们的友链页面后只会点击1个友链,用离散型随机变量$Y$表示该访客点击的友链的位置,例如$Y=1$就表示访客点击的是排在第1个位置的友链,$Y=i$表示访客点击了排在第$i$个位置的友链,$Y$既然是个随机变量,那它就有一个概率分布,对于特定的事件$Y=i$,也有特定的概率,而$Y$的分布要想知道只有两种途径,一是通过收集数据然后用非参数方法拟合出分布来,二是通过假设,假设$Y$具有某某分布,我们暂时还没有收集数据,所以,我们会考虑$Y$服从的几种假设的分布.

离散型随机变量$Y$的概率分布可以用一张表来表示

||| |:—|:—|:—|:—|:—| |$Y=i$|$1$|$2$|$\cdots$|$n$| |$p_i$|$p_1$|$p_2$|$\cdots$|$p_n$|

表格中的$p_i$取了什么值,就决定了$Y$服从着什么样的分布,例如,我们也可以假定$Y$是等概率分布的

||| |:—|:—|:—|:—|:—| |$Y=i$|$1$|$2$|$\cdots$|$n$| |$p_i$|$1/n$|$1/n$|$\cdots$|$1/n$|

在这种假设下,访客点击第$i$的友链位置的概率是$p_i = 1/n$,只和$n$有关而和$i$无关,因此这种假设的意义就是「当n给定时,访客点击任何一个友链位置的概率都是相等的」.

还有另外一种假设,假设访客更倾向于点击排在前面的友链,懒得翻到页尾去点击后面的友链,这种假设用符号表示出来就是

$$ p_1 \geq p_2 \geq \cdots \geq p_n $$

作为一个这种假设$(pi \geq p{i+1})$的特例,我们可以考虑一种阶梯状的分布,或者等差分布,我不知道一般叫什么名字,不过你只要知道这种分布下$pi - p{i-1} = p{i-1} - p{i-2}$就够了,例如这样的分布

||| |:—|:—|:—|:—|:—| |$Y=i$|$1$|$2$|$\cdots$|$n$| |$p_i$|$n/s$|$(n-1)/s$|$\cdots$|$1/s$|

其中,$s$也被称作「归一化因子」,$s=1+2+\cdots +n$,这样,你可以验证$\sum p_i$是等于1的不论当n等于几,并且,可以看到$pi - p{i-1}$是相等的是等于$1/s$,对所有$i=2,\cdots ,n$的情况,在这种假设下,排在第i位的友链的被点击的频率一般会比第i+1位的友链的被点击的频率多一个数量单位$1/s$.

为什么我们会关心$Y$的概率分布也就是$p_i$的值呢?因为,前面我们已经提到过了每个友链位置的点击次数$v_i$和每个友链的实际被点击次数$v_i^{\star}$,注意到我们已经说了友链不一定会按照添加次序排列所以$v_i$和$v_i^{\star}$是不一定相等的,根据大数定律(Law of large numbers),概率$p_i$实际上就是n个访客点击友链位置i的频率的极限,例如,10000个访客点击了3827次第4个友链,那么$p_4$近似的为$382710000$,你可以理解为每个友链位置的被点击次数(由大数定律)是由$Y$的分布(也就是$p_i$的值)确定的,因为为了简化模型,我们要假设不管我们怎么更换友链的位置都不影响$p_i$的值.而实际的每个友链被访问的次数$v_i^{\star}$才是关键,因为这个值是可以部分受我们控制的,例如,在$pi \geq p{i+1}$的假设下,我们想让哪个友链被点击的次数多,我们就把哪个友链排在前面从而使它的实际被点击次数远超过其他的友链,这也是通过调整友链位次得以实现流量分发均等的理论基础.

一句话概括之,就是访客点击哪个位置的友链不由我们确定,但是可以用一个服从某种假设分布的随机变量来建模,而每个友链实际被点击次数的多与少我们可以部分的去控制.

数值仿真模拟

在一个博客网站的实际运行过程中,访客的数量和友链的数目都会随时间变化的,一般来说,在前期是近似线性增长,在中期是缓慢线性增长,而到了后期则是大概在某个水平上下波动.所以呢,由于$Y$的分布还要受友链个数$n$的影响,$Y$也是随时间变化的,而由于访客数量随时间变化,$vi$和$v{i}^{\star}$也随时间变化,考虑到这些因素,纯粹的符号讨论会显得有些力不从心,而借助计算机数值仿真模拟(基于蒙特卡罗方法)则更容易得到直观的结果.

首先我们来看看一种比较简单的假设:访客点击每个友链位置的概率是相等的,那么,访客点击每个友链的位置就只受总友链的个数影响,从而,就只受时间影响.网站每天的访客的数量是变化的,实际上更确切的说,是网站每天的访客作为一个随机变量,它的分布是变化的,泊松分布可以很好的对每一天的访客数量进行建模,例如,我们可以合理地假设,随着时间一天天的过去,我们总是能期待网站的访客越来越多,我们可以设每一天的访客数量是$Z$,在第$i$天$Z$是服从参数为$\lambda_i$的泊松分布,这里的$\lambda_i$实际上就是每天的期望访客量,$\lambda_i$应该会随着天数$i$的增加而缓慢线性地增加.还可以假设友链的数量随着时间线性缓慢增长.有了这么一个关于访客数和友链数「缓慢线性增加」的假设,我们就可以模拟出每一天的访客量和截止当天的友链的数量了.

我们可以构造一个分段函数来表示每一天的平均访客数量,或者,用概率论的术语,叫做每一天的访客数量的「数学期望」:

averageVisitors[dayn_Integer] := Round[
    50 + (dayn/30)*50
] /; dayn >= 1 && dayn <= 365;

averageVisitors[dayn_Integer] := Round[
    averageVisitors[365] + ((dayn - 365)/30)*20
] /; dayn >= 366 && dayn <= 699;

averageVisitors[dayn_Integer] := Round[
    averageVisitors[699] + ((dayn - 699)/30)*10
] /; dayn >= 700;

这里我们定义了一个分段函数用来表示每天的平均访客数量,这个分段函数画出来是这样子的:

表示每天平均访客数量的分段函数

表示每天平均访客数量的分段函数

实际上我们要模拟的是这种「前期访客数增加得较快,中期访客数增速放慢,后期增速基本稳定」的假设.这个分段函数是分段线性的.那么设定好了每天的平均访客数之后,我们就可以得到每一天的访客数:

visitorsDistribution[dayn_Integer] := 
    PoissonDistribution[averageVisitors[dayn]];

visitors = Table[
    RandomVariate[visitorsDistribution[dayn]], 
    {dayn, 1, 3*365}
];
得到每天的访客数

得到每天的访客数

同样,可以合理地假设友链数目是缓慢线性增长的,并且初期增长得比较快,后期相对放缓:

links[dayn_] := Max[1, Round[(dayn/30)*0.8]] 
    /; dayn <= 365;

links[dayn_] := Round[
    visitorsCounts[365] + 0.4*((dayn - 365)/30)
] /; dayn >= 366;

这个函数表示每个月平均增加0.8个友链,而一年之后,每个月只平均增加0.4个友链,画出来是这样子的:

友链数目缓慢增加

友链数目缓慢增加

知道了每天的访客数,和每天已经有了多少个友链,就可以统计每一天每个友链位置分别得到了多少次点击:

visitors[dayn_Integer] := RandomVariate[visitorsDistribution[dayn]];

visitorsHitsDistribution[dayn_Integer] := EmpiricalDistribution[
   Table[1, links[dayn]] -> Table[i, {i, 1, links[dayn]}]
];

visitorsHits[dayn_Integer] := RandomVariate[
   visitorsHitsDistribution[dayn],
   visitors[dayn]
];

hitsLogs = Join @@ Table[
    visitorsHits[dayn], {dayn, 1, 3*365}
];

统计结果如下:

访客单击友链的次数统计

访客单击友链的次数统计

这意味着,假如说,面对n个友链,访客点击每个位置的友链都是相等的,那么随着时间的推移,第i个位置的友链总是比第i+1个位置的友链被点击的数量多出一个相差不大的值.假如说友链是按照添加顺序排列的,那么添加得晚一些的那些友链,被点击的次数总是会比添加得早的哪些友链少一些,然而,这种差别仅仅是线性的(从图上也可以看出来),也就是大概是和添加的时间的差是线性关系.

如果友链是以添加次序排列的话,我们再来看一下每个友链累积给我们带来的访客数,不妨假定,在每一天,每个友链给我们带来的访客数是服从某个参数的泊松分布的:

averageReferrals = 10;

referrals[dayn_Integer] := Flatten[Table[
    Table[
        i, 
        RandomVariate[PoissonDistribution[averageReferrals]]
    ],
    {i, 1, links[dayn]}
]];

accumulatedRefs = Join @@ Table[
    referrals[dayn], 
    {dayn, 1, 3*365}
];

上面这段代码的意思是,假设每天每个友链平均能给我们带来10个访客(当然具体带来多少是一个服从泊松分布的随机变量),然后对具体的dayn天,把来自第i个友链的访客记做i,i的数目是服从一个泊松分布,最后得到的accumulatedRefs是一个有很多重复数字的列表,例如在里面1重复了100次,2重复了70次,3重复了50次就代表有100个来自友链1的访客,70个来自友链2的访客,50个来自友链3的访客,是这样一种表示.具体地,在$3 \times 365 = 1095$天的时间里,每个友链累积给我们带来的访客数也是和添加时间差有着线性的关系:

每个友链给我们带来的访客数量统计

每个友链给我们带来的访客数量统计

添加得早的友链给我们带来的访客多,而添加得晚的友链给我们带来的访客少,但是,这个差别也是线性的,对比刚才那张统计每个位置得到的流量的图,我们有结论:当访客点击每个友链位置的概率相等的时候,每个友链带给我们的流量和我们给每个友链带去的流量是成比例的,这个时候,友链按照添加次序排列就已经是公平的了,前提只不过是访客点击每个友链位置的概率均等.

刚才讨论的是访客点击每个位置的友链的概率都相等的情况.下面我们来看一下,如果访客点击每个位置的友链的概率不等,比如说,访客点击第i个友链的概率总是不小于点击第i+1个友链的概率,这个时候,每个友链累积为我们带来的流量还能和我们为它带去的流量成比例吗?

首先,仍然假设每个友链每天为我们带来固定数目(或者逐渐增多)的流量,那么第1个,第2个,第3个,……,一直到最后一个友链累积为我们带来的流量仍然是阶梯状递减的,就像我们刚才话的那幅图.但是,这个时候,变化了的应该是我们为每个友链带去的流量:

visitorsHitsDistribution[dayn_Integer] := EmpiricalDistribution[
   Reverse[Table[i, {i, 1, links[dayn]}]] -> Table[i, {i, 1, links[dayn]}]
];

hitsLogs = Join @@ Table[
    visitorsHits[dayn], {dayn, 1, 3*365}
];

仍然可以复用模拟每个访客点击友链的那部分代码,需要修改的仅仅是访客点击的友链的位次的那个分布,也就是visitorsHitsDistribution,对应我们上一节用符号$Y$表示的随机变量,那么新的友链点击统计就变成了:

访客友链点击统计

访客友链点击统计

这个时候点击次数已经不是随着友链位次i的增加而线性递减了,这个时候,这个趋势看起来更像是一条抛物线,简单来说就是,排在前面的友链被点击的次数特别多,而排在后面的友链被点击的次数特别少,这个点击次数的差别已经不足以用添加时间的差别来解释了.为了更加清楚地验证这一点,我们用第i个友链位置的点击量去除第i个友链位置的贡献访客量,看这个比值的走势是随i减小还是和i的关系不大:

友链点击量和友链贡献访客数的比值

友链点击量和友链贡献访客数的比值

我们首先算得,对每个友链位置,平均每给我们带来一个访客,我们能为他带去多少访客,这张图表明,在$pi \geq p{i+1}$的假设下,排在后边的友链更加亏,平均而言,排在第1位的友链,每给我们带来1个访客,我们能给他回报11个访客,而排在最后面的友链,每给我们带来3个访客,我们只能给他带去1个访客,所以,如果访客总是倾向于点击前面的友链而较少点击排在后面的友链,那么出于公平考虑,就有必要时时调整友链的位次而不能按照添加顺序排列,从而使得访问量较少的友链排在前面的次数多一些,而访问量较多的友链,则移到后面去,这样子,友链的点击量和友链的贡献度才能成比例,才能实现公平.

与$pi \geq p{i+1}$的假设相比,在$pi = p{i+1}$的情况下,这个点击率与贡献量的比例,相差得就比较小:

友链点击率和友链贡献访客数的比值

友链点击率和友链贡献访客数的比值

这幅图是说,如果访客点击每个位置的友链的概率都是一样的,那即使友链是按照添加时间决定放置位次,也不会有太大的不公平,因为最赚的友链是每贡献1个访客能收到6.52个点击,而即使是最亏的每贡献1个访客仍能收到5.13个点击,平均而言,相差不大.至少6.52491和5.13115的差别是小于11.2318和0.398907的差别的.

unclassifiedany

一个由规则定义的系统:使用元胞自动机模拟并预测传染病传播

一切都从掷硬币开始:谈常见几大概率分布之间的联系