内容选自《程序员的数学基础课》
你好,我是黄申。今天我来说说矩阵。
矩阵由多个长度相等的向量组成,其中的每列或者每行就是一个向量。从数据结构的角度来看,我们可以把向量看作一维数组,把矩阵看作二维数组。
具有了二维数组的特性,矩阵就可以表达二元关系了,例如图中结点的邻接关系,或者是用户对物品的评分关系。而通过矩阵上的各种运算操作,我们就可以挖掘这些二元关系,在不同的应用场景下达到不同的目的。今天我就从图的邻接矩阵出发,展示如何使用矩阵计算来实现 PageRank 算法。
回顾 PageRank 链接分析算法在讲马尔科夫模型的时候,我已经介绍了 PageRank 链接分析算法。所以,在展示这个算法和矩阵操作的关系之前,我们快速回顾一下它的核心思想。
PageRank 是基于马尔科夫链的。它假设了一个“随机冲浪者”模型,冲浪者从某张网页出发,根据 Web 图中的链接关系随机访问。在每个步骤中,冲浪者都会从当前网页的链出网页中,随机选取一张作为下一步访问的目标。此外,PageRank 还引入了随机的跳转操作,这意味着冲浪者不是按 Web 图的拓扑结构走下去,只是随机挑选了一张网页进行跳转。
基于之前的假设,PageRank 的公式定义如下:
其中,pi 表示第 i 张网页,Mi 是 pi 的入链接集合,pj 是 Mi 集合中的第 j 张网页。PR(pj) 表示网页 pj 的 PageRank 得分,L(pj) 表示网页 pj 的出链接数量,1/L(pj) 就表示从网页 pj 跳转到 pi 的概率。α是用户不进行随机跳转的概率,N 表示所有网页的数量。
PageRank 的计算是采样迭代法实现的:一开始所有网页结点的初始 PageRank 值都可以设置为某个相同的数,例如 1,然后我们通过上面这个公式,得到每个结点新的 PageRank 值。每当一张网页的 PageRank 发生了改变,它也会影响它的出链接所指向的网页,因此我们可以再次使用这个公式,循环地修正每个网页结点的值。由于这是一个马尔科夫过程,所以我们能从理论上证明,所有网页的 PageRank 最终会达到一个稳定的数值。整个证明过程很复杂,这里我们只需要知道这个迭代计算的过程就行了。
简化 PageRank 公式
那么,这个计算公式和矩阵操作又有什么联系呢?为了把问题简化,我们暂时不考虑随机跳转的情况,而只考虑用户按照网页间链接进行随机冲浪。那么 PageRank 的公式就简化为:
这个公式只包含了原公式中的Σ(PR(pj)/L(pj)) 部分。我们再来对比看看矩阵点乘的计算公式。
以上两个公式在形式上是基本一致的。因此,我们可以把Σ(PR(pj)/L(pj)) 的计算,分解为两个矩阵的点乘。一个矩阵是当前每张网页的 PageRank 得分,另一个矩阵就是邻接矩阵。所谓邻接矩阵,其实就是表示图结点相邻关系的矩阵。
假设 xi,j 是矩阵中第 i 行、第 j 列的元素,那么我们就可以使用 xi,j 表示从结点 i 到结点 j 的连接,放到 PageRank 的应用场景,xi,j 就表示网页 pi 到网页 pj 的链接。最原始的邻接矩阵所包含的元素是 0 或 1,0 表示没有链接,而 1 表示有链接。
考虑到 PageRank 里乘积是 1/L(pj),我们可以对邻接矩阵的每一行进行归一化,用原始的值(0 或 1)除以 L(pj),而 L(pj) 表示有某张网页 pj 的出链接,正好是矩阵中 pj 这一行的和。所以,我们可以对原始的邻接矩阵,进行基于行的归一化,这样就能得到每个元素为 1/L(pj) 的矩阵,其中 j 表示矩阵的第 j 行。注意,这里的归一化是指让所有元素加起来的和为 1。
为了方便你理解,我用下面这个拓扑图作为例子给你详细解释。
基于上面这个图,原始矩阵为:
其中第 i 行、第 j 列的元素值表示从结点 i 到 j 是不是存在链接。如果是,那么这个值为 1;否则就为 0。
按照每一行的和,分别对每一行进行归一化之后的矩阵就变为:
有了上述这个邻接矩阵,我们就可以开始最简单的 PageRank 计算。PageRank 的计算是采样迭代法实现的。这里我把初始值都设为 1,并把第一次计算的结果列在这里。
好了,我们已经成功迈出了第一步,但是还需要考虑随机跳转的可能性。
考虑随机跳转经过上面的步骤,我们已经求得Σ(PR(pj)/L(pj)) 部分。不过,PageRank 引入了随机跳转的机制。这一部分其实也是可以通过矩阵的点乘来实现的。我们把Σ(PR(pj)/L(pj)) 部分用 A 表示,那么完整的 PageRank 公式就可以表示为:
于是,我们可以把上述公式分解为如下两个矩阵的点乘:
我们仍然使用前面的例子,来看看经过随机跳转之后,PageRank 值变成了多少。这里α取 0.9。
我们前面提到,PageRank 算法需要迭代式计算。为了避免计算后的数值越来越大甚至溢出,我们可以进行归一化处理,保证所有结点的数值之和为 1。经过这个处理之后,我们得到第一轮的 PageRank 数值,也就是下面这个行向量:
[0.37027027 0.24864865 0.37027027 0.00540541 0.00540541]
接下来,我们只需要再重复之前的步骤,直到每个结点的值趋于稳定就可以了。
使用 Python 进行实现说到这里,我已经把如何把整个 PageRank 的计算,转换成多个矩阵的点乘这个过程讲完了。这样一来,我们就可以利用 Python 等科学计算语言提供的库,来完成基于 PageRank 的链接分析。为了展示具体的代码,我以之前的拓扑图为例,给你详细讲述每一步。
首先,我们要进行一些初始化工作,包括设置结点数量、确定随机跳转概率的α、代表拓扑图的邻接矩阵以及存放所有结点 PageRank 值的数组。下面是一段示例代码,在代码中我提供了注释供你参考。
复制代码
import numpy as np # 设置确定随机跳转概率的 alpha、网页结点数alpha = 0.9N = 5 # 初始化随机跳转概率的矩阵jump = np.full([2,1], [[alpha], [1-alpha]], dtype=float) # 邻接矩阵的构建adj = np.full([N,N], [[0,0,1,0,0],[1,0,1,0,0],[1,0,0,0,0],[0,0,0,0,0],[0,1,0,0,0]], dtype=float) # 对邻接矩阵进行归一化row_sums = adj.sum(axis=1) # 对每一行求和row_sums[row_sums == 0] = 0.1 # 防止由于分母出现 0 而导致的 Nanadj = adj / row_sums[:, np.newaxis] # 除以每行之和的归一化 # 初始的 PageRank 值,通常是设置所有值为 1.0pr = np.full([1,N], 1, dtype=float)之后,我们就能采用迭代法来计算 PageRank 值。一般我们通过比较每个结点最近两次计算的值是否足够接近,来确定数值是不是已经稳定,以及是不是需要结束迭代。这里为简便起见,我使用了固定次数的循环来实现。如果你的拓扑图比较复杂,需要更多次迭代,我把示例代码和注释列在这里。
复制代码
# PageRank 算法本身是采样迭代方式进行的,当最终的取值趋于稳定后结束。for i in range(0, 20): # 进行点乘,计算Σ(PR(pj)/L(pj)) pr = np.dot(pr, adj) # 转置保存Σ(PR(pj)/L(pj)) 结果的矩阵,并增加长度为 N 的列向量,其中每个元素的值为 1/N,便于下一步的点乘。 pr_jump = np.full([N, 2], [[0, 1/N]]) pr_jump[:,:-1] = pr.transpose() # 进行点乘,计算α(Σ(PR(pj)/L(pj))) (1-α)/N) pr = np.dot(pr_jump, jump) # 归一化 PageRank 得分 pr = pr.transpose() pr = pr / pr.sum() print("round", i 1, pr)如果成功运行了上述两段代码,你就能看到每个结点最终获得的 PageRank 分数是多少。
Python 中还有一些很不错的库,提供了直接构建拓扑图和计算 PageRank 的功能,例如networkx。你可以尝试使用这种库,构建样例拓扑图并计算每个结点的 PageRank 得分,最后和上述代码所计算的 PageRank 得分进行比较,验证一下上述代码的结果是不是合理。
总结我们可以把向量看作一维数组,把矩阵看作二维数组。矩阵的点乘,是由若干个向量的点乘组成的,所以我们可以通过矩阵的点乘操作,挖掘多组向量两两之间的关系。
今天我们讲了矩阵的点乘操作在 PageRank 算法中的应用。通过表示网页的邻接二元关系,我们可以使用矩阵来计算 PageRank 的得分。在这个应用场景下,矩阵点乘体现了多个马尔科夫过程中的状态转移。
矩阵点乘和其他运算操作,还可以运用在很多其他的领域。例如,我在上一节介绍 K 均值聚类算法时,就提到了需要计算某个数据点向量、其他数据点向量之间的距离或者相似度,以及使用多个数据点向量的平均值来获得质心点的向量,这些都可以通过矩阵操作来完成。
另外,在协同过滤的推荐中,我们可以使用矩阵点乘,来实现多个用户或者物品之间的相似程度,以及聚集后的相似程度所导致的最终推荐结果。下一节,我会使用矩阵来表示用户和物品的二元关系,并通过矩阵来计算协同过滤的结果。
pagerank简单算法
用matlab来处理,代码如下:A = [
0,1,1,1;
1,0,1,0;
0,1,0,1;
1,0,1,0;
];
A = A;
M = A ./ repmat(sum(A),size(A,1),1);
[V, D]= eig(M);
EigenVector = V(:, abs(diag(D))==max(abs(diag(D))));
PageRank = abs(EigenVector)./ norm(EigenVector,1);
解释一下解题的过程:
1、
ABCD4个网页,用序号1234来代替,那么
A有链接到BCD,表示为:0,1,1,1;
B有连接到AC,表示为: 1,0,1,0;
C有连接到BD,表示为: 0,1,0,1;
D有连接到AC,表示为: 1,0,1,0;
即得到矩阵A
A =
0 1 1 1
1 0 1 0
0 1 0 1
1 0 1 0
2、对矩阵A做转置得到A,并对A的权重做调整得到M
A =
0 1 0 1
1 0 1 0
1 1 0 1
1 0 1 0
M =
0 0.5000 0 0.5000
0.3333 0 0.5000 0
0.3333 0.5000 0 0.5000
0.3333 0 0.5000 0
可以看出M的每一列的和都等于1
3、
求出矩阵M的特征值V和特征向量D
V =
-0.4575 -0.8384 -0.6229 -0.0000
-0.4575 0.1772 0.4913 -0.7071
-0.6100 0.4841 -0.3596 -0.0000
-0.4575 0.1772 0.4913 0.7071
D =
1.0000 0 0 0
0 -0.2113 0 0
0 0 -0.7887 0
0 0 0 0
4、
找出特征值最大的特征向量EigenVector
EigenVector =
-0.4575
-0.4575
-0.6100
-0.4575
5、
对EigenVector 做归一化,得到PageRank
PageRank =
0.2308
0.2308
0.3077
0.2308
对结果的解释
ABD网页的权值都是0.2308,C网页的权值最大,为0.3077.
参考这篇文章《Google 的秘密
PageRank彻底解说 中文版 》,你可以百度到链接。
对pagerank算法的整理
1、首先先大致介绍下pagerank,pagerank是Google排名算法法则的一部分,是用来标记网页的等级的一种方法,也是用来衡量一个网页好坏的唯一标准。pagerank他采用PR值来划分网页的受欢迎度,PR值越高,则表名受欢迎度越高,PR最高为10,最低为0,一般PR达到4,则表名网站已经不错了。PR为4的网站比PR为3的网站不是单纯的好一点来形容,他是一种里氏震级的形式来形容的,就好比地震的等级,是指数刻度增长的,因此可以想象PR为10的网站是一种什么程度。因为这个算法是Google提出的,因此Google将自己的网站PR值设置为10,所以想要自己的网站PR达到10,是非常难的,如果你的网站可以达到Google的水平。2、介绍完了pagerank是一个什么东西后,我们就来介绍一下pagerank如何计算的。
2.1、用个例子来说明下PageRank算法
在网页A中有B、C、D三个链接,在网页B中有A、C两个个链接,在网页C中有D链接,网页D中有A、B两个链接。(可以看出这个图是强链接的,任何一个节点都可以到达另一个节点)。
我们假设每一个链接访问的概率是相同的,为了计算方便我们将每一个网页的PageRank设置为1。
先给出计算公式
PR(pj) 表示网页 pj 的 PageRank 得分,L(pj) 表示网页 pj 的出链接数量,1/L(pj) 就表示从网页 pj 跳转到 pi 的概率。
所以我们来计算第一次迭代后的PR值:
PR(A)=PR(B)/2 PR(D)/2
PR(B)=PR(A)/3 PR(D)/2
PR(C)=PR(A)/3 PR(B)/2
PR(D)=PR(A)/3 PR(C)/1
PR(A) PR(B) PR(C) PR(D)=1
PR(A)=0.265, PR(B)=0.235, PR(C)=0.206, PR(D)=0.294
通过上面的公式在不断的进行迭代,可以得到一个收敛值,大概是在(0.265,0.235,2.206,0.294)附近。
2.2看完公式之后,我们来考虑俩种特殊的情况
2.2.1终止问题
上面过程要满足收敛性,需要具备一个条件:图是强连通的,即从任意网页可以到达其他任意网页。
互联网中存在网页不满足强连通的特性,因为有一些网页不指向任何网页,按照上面公式迭代计算下去,导致前面累计得到的转移概率被清零,最终得到的概率分布向量所有元素几乎都为0。
假设把上面图中C到D的链接丢掉,C变成了一个终止点,得到下面这个图:
转移矩阵M为:
不断迭代,最终得到所有元素都为0。
2.2.2 、陷阱问题
陷阱问题:是指有些网页不存在指向其他网页的链接,但存在指向自己的链接。比如下面这个图:
这种情况下,PageRank算法不断迭代会导致概率分布值全部转移到c网页上,这使得其他网页的概率分布值为0,从而整个网页排名就失去了意义。如果按照上面图则对应的转移矩阵M为:
不断迭代,最终得倒如下结果:
为了解决终止点问题和陷阱问题 ,下面需要对算法进行改进。假设选取下一个跳转页面时,既不选 当前页面 ,也不选 当前网页上的其他链接 ,而是以一定概率跳转到其他不相关网页,那么上面两个问题就能得到很好的解决,这就是 完整 PageRank 算法思想 。
N表示的时网页链接的个数,α表示不进行随机跳转的概率。
利用上面公式继续迭代下去,直到收敛,得到最终rank值。
PageRank 的计算是采样迭代法实现的:一开始所有网页结点的初始 PageRank 值都可以设置为某个相同的数,例如 1,然后我们通过上面这个公式,得到每个结点新的 PageRank 值。每当一张网页的 PageRank 发生了改变,它也会影响它的出链接所指向的网页,因此我们可以再次使用这个公式,循环地修正每个网页结点的值。由于这是一个马尔科夫过程,所以我们能从理论上证明,所有网页的 PageRank 最终会达到一个稳定的数值。整个证明过程很复杂,这里我们只需要知道这个迭代计算的过程就行了。
3、基于本文主题叫做数学建模之美,也是一篇读后感,所以我们还是写一下感受吧。
这个算法的优美之处,就在于巧妙地将网页内容的好坏,根据链接数的形式,用PR值进行了排名,它不仅激发网页越做越好,也促进了各个网页之间的联系。
同时在结构方面,他将一个复杂的问题,进行了简单的类比,用图结构的形式代替链接的形式,用户访问的顺序,也就是节点的走向。所以数学之美就在于他是非常的简单,用简单的原理,向我们展示了一个复杂的问题。