写在前面: 我是
「nicedays」
,一枚喜爱做特效,听音乐,分享技术的大数据开发猿
。这名字是来自world order乐队的一首HAVE A NICE DAY
。如今,走到现在很多坎坷和不顺,如今终于明白nice day是需要自己赋予的。
白驹过隙,时光荏苒,珍惜当下~~
写博客一方面是对自己学习的一点点总结及记录
,另一方面则是希望能够帮助更多对大数据感兴趣的朋友。如果你也对大数据与机器学习
感兴趣,可以关注我的动态https://blog.csdn.net/qq_35050438
,让我们一起挖掘数据与人工智能的价值~
每个网页为一个点
A到B的链接抽象为一条有向边
整张网页链接抽象成一份有向图
M = [ 0 1 2 0 1 2 1 3 0 0 1 2 1 3 1 2 0 0 1 3 0 1 0 ] M = \begin{bmatrix}0 & \frac{1}{2} & 0 & \frac{1}{2} \\\frac{1}{3} & 0 & 0 & \frac{1}{2} \\\frac{1}{3} & \frac{1}{2} & 0 & 0 \\\frac{1}{3} & 0 & 1 & 0\end{bmatrix} M=⎣⎢⎢⎡03131312102100001212100⎦⎥⎥⎤
不加权重的话,本意是当前页面点击一次后停留在自己页面的概率
P 0 = [ 1 4 1 4 1 4 1 4 ] T P_0 = \begin{bmatrix}\frac{1}{4} & \frac{1}{4} & \frac{1}{4} & \frac{1}{4} \\\end{bmatrix}^T P0=[41414141]T
现在我们需要求根据当他点击一次继续停留在当前页面的概率
如果初始状态为B页面来说,当他点击一次继续停留在A页面的概率我们应该这样考虑:
情况一:B页面是从A走到B的,同时点击一次继续留在该页面,
两个事件必须同时发生,第一个事件发生概率为1/3,第二个事件发生概率为1/4
P ( A B ) = P ( A ) P ( B ) P(AB) = P(A)P(B) P(AB)=P(A)P(B)
所以情况一概率为1/12
情况二:B页面是从D走到B的,同时点击一次继续留在该页面,
两个事件必须同时发生,第一个事件发生概率为1/2,第二个事件发生概率为1/4,同理情况二概率为1/8
总概率为两个情况之和:5/24
所有的页面停留概率可以用矩阵相乘来得到:
P 1 = M ∗ P 0 = [ 0 1 2 0 1 2 1 3 0 0 1 2 1 3 1 2 0 0 1 3 0 1 0 ] ∗ [ 1 4 1 4 1 4 1 4 ] = [ 1 4 5 24 5 24 1 3 ] P_1 = M*P_0=\begin{bmatrix}0 & \frac{1}{2} & 0 & \frac{1}{2} \\\frac{1}{3} & 0 & 0 & \frac{1}{2} \\\frac{1}{3} & \frac{1}{2} & 0 & 0 \\\frac{1}{3} & 0 & 1 & 0\end{bmatrix}*\begin{bmatrix}\frac{1}{4} \\ \frac{1}{4} \\ \frac{1}{4} \\ \frac{1}{4} \\ \end{bmatrix}=\begin{bmatrix}\frac{1}{4} \\ \frac{5}{24} \\ \frac{5}{24} \\ \frac{1}{3} \\ \end{bmatrix} P1=M∗P0=⎣⎢⎢⎡03131312102100001212100⎦⎥⎥⎤∗⎣⎢⎢⎡41414141⎦⎥⎥⎤=⎣⎢⎢⎡4124524531⎦⎥⎥⎤
每乘以1/4的向量相当于我计算每点击一次继续停留在该页面的概率,在不断点击迭代后,由于马尔科夫性,最终会收敛到一个值。
先前所举的例子是一个理想状态:
假设所有网页组成的有向图是强连通的,即从一个网页可以到达任意网页。但实际的网络链接环境没有这么理想,有一些网页不指向任何网页,或不存在指向自己的链接。
如果存在没有出度的点,那么当我们不断迭代上面的矩阵方程时,最终一定会收敛于0,也就是最后大家都会跳到那个没有出度的点上。
陷阱指的是只有指向自身链接的网页
上网者浏览到 C 网页将陷入无休止的循环之中
M = [ 0 1 2 0 0 1 3 0 0 1 2 1 3 0 1 1 2 1 3 1 2 0 0 ] M = \begin{bmatrix}0 & \frac{1}{2} & 0 & 0 \\\frac{1}{3} & 0 & 0 & \frac{1}{2} \\\frac{1}{3} & 0 & 1 & \frac{1}{2} \\\frac{1}{3} & \frac{1}{2} & 0 & 0\end{bmatrix} M=⎣⎢⎢⎡03131312100210010021210⎦⎥⎥⎤
根据公式
P n = M ⋅ P n − 1 = M n ⋅ P 0 P_n=M⋅P_{n−1}=M^n⋅P_0 Pn=M⋅Pn−1=Mn⋅P0
迭代计算出 PR 值向量。
我们可以通过阻尼系数来解决陷阱问题和孤立点问题了。
假定一个上网者从一个随机的网页开始浏览,此时有两种选择:
由此,上网者从点击链接来跳转的概率变为d,此时PageRank模型变为:在每一个页面,用户都有d概率点击链接,1-d概率输入地址栏跳转,而输入地址栏跳转到任一页面的概率为1/N(N为页面)。
P n = d ∗ [ 0 1 2 0 1 2 1 3 0 0 1 2 1 3 1 2 0 0 1 3 0 1 0 ] ∗ [ 1 4 1 4 1 4 1 4 ] + ( 1 − d ) ∗ [ 1 4 1 4 1 4 1 4 ] P_n = d*\begin{bmatrix}0 & \frac{1}{2} & 0 & \frac{1}{2} \\\frac{1}{3} & 0 & 0 & \frac{1}{2} \\\frac{1}{3} & \frac{1}{2} & 0 & 0 \\\frac{1}{3} & 0 & 1 & 0\end{bmatrix}*\begin{bmatrix}\frac{1}{4} \\ \frac{1}{4} \\ \frac{1}{4} \\ \frac{1}{4} \\ \end{bmatrix} + (1-d)*\begin{bmatrix}\frac{1}{4} \\ \frac{1}{4} \\ \frac{1}{4} \\ \frac{1}{4} \\ \end{bmatrix} Pn=d∗⎣⎢⎢⎡03131312102100001212100⎦⎥⎥⎤∗⎣⎢⎢⎡41414141⎦⎥⎥⎤+(1−d)∗⎣⎢⎢⎡41414141⎦⎥⎥⎤
而阻尼系数d我们经过实验测算一般归纳为0.85
import org.apache.spark.HashPartitioner
val links = sc.parallelize(List(("A",List("B","C")),("B",List("A","C")),("C",List("A","B","D")),("D",List("C")))).partitionBy(new HashPartitioner(100)).persist()
var ranks=links.mapValues(v=>1.0)
for (i <- 0 until 10) {
val contributions=links.join(ranks).flatMap {
case (pageId,(links,rank)) => links.map(dest=>(dest,rank/links.size))
}
ranks=contributions.reduceByKey((x,y)=>x+y).mapValues(v=>0.15+0.85*v)
}
ranks.sortByKey().collect()