PageRank基本模型:
如果当前在A网页,上网者将会各以1/3的概率跳转到B、C、D,这里的3表示A有3条出链,如果一个网页有k条出链,那么跳转任意一个出链上的概率是1/k,同理D到B、C的概率各为1/2,而B到C的概率为0。一般用转移矩阵表示上网者的跳转概率,如果用n表示网页的数目,则转移矩阵M是一个n*n的方阵;如果网页j有k个出链,那么对每一个出链指向的网页i,有M[i][j]=1/k,而其他网页的M[i][j]=0
初始时,假设上网者在每一个网页的概率都是相等的,即1/n,于是初试的概率分布就是一个所有值都为1/n的n维列向量V0,用V0去右乘转移矩阵M,就得到了第一步之后上网者的概率分布向量MV0,(nXn)*(nX1)依然得到一个nX1的矩阵。下面是V1的计算过程:
矩阵M中M[i][j]不为0表示用一个链接从j指向i,M的第一行乘以V0,表示累加所有网页到网页A的概率即得到9/24。得到了V1后,再用V1去右乘M得到V2,一直下去,最终V会收敛,即Vn=MV(n-1),上面的图示例,不断的迭代,最终V=[3/9,2/9,2/9,2/9]’:
终止点问题(所有连接最终到达终止点而无法再流动,全部网站概率趋向于0)
互联网上的网页不满足强连通的特性,因为有一些网页不指向任何网页,如果按照上面的计算,上网者到达这样的网页后便走投无路、四顾茫然,导致前面累计得到的转移概率被清零,这样下去,最终的得到的概率分布向量所有元素几乎都为0。假设我们把上面图中C到A的链接丢掉,C变成了一个终止点,得到下面这个图:
对应的转移矩阵为:
连续迭代下去,最终所有元素都为0:
陷阱问题(所有连接最终到达终止点而不断循环,其他网站概率趋向于0,本网站趋向于1)
即有些网页不存在指向其他网页的链接,但存在指向自己的链接。比如下面这个图:
上网者跑到C网页后,就像跳进了陷阱,陷入了漩涡,再也不能从C中出来,将最终导致概率分布值全部转移到C上来,这使得其他网页的概率分布值为0,从而整个网页排名就失去了意义。如果按照上面图对应的转移矩阵为:
不断的迭代下去,就变成了这样:
解决终止点问题和陷阱问题
上面过程,我们忽略了一个问题,那就是上网者是一个悠闲的上网者,而不是一个愚蠢的上网者,我们的上网者是聪明而悠闲,他悠闲,漫无目的,总是随机的选择网页,他聪明,在走到一个终结网页或者一个陷阱网页(比如两个示例中的C),不会傻傻的干着急,他会在浏览器的地址随机输入一个地址,当然这个地址可能又是原来的网页,但这里给了他一个逃离的机会,让他离开这万丈深渊。模拟聪明而又悠闲的上网者,对算法进行改进,每一步,上网者可能都不想看当前网页了,不看当前网页也就不会点击上面的连接,而上悄悄地在地址栏输入另外一个地址,而在地址栏输入而跳转到各个网页的概率是1/n。假设上网者每一步查看当前网页的概率为a,那么他从浏览器地址栏跳转的概率为(1-a),于是原来的迭代公式转化为:
现在我们来计算带陷阱的网页图的概率分布:
重复迭代下去:
代码
import java.util.Arrays;
public class PageRank {
private double m[][] = null;
private double e[] = null;
private double a = 0.0;
private int iteration = 0;
public PageRank(double[][] m, double a, int iteration) {
super();
this.m = m;
this.a = a;
this.iteration = iteration;
for (int i = 0, len = m.length; i < len; i++) {
e[i] = 1.0 / len;
}
}
public PageRank(int[][] map, double a, int iteration) {
super();
this.a = a;
this.iteration = iteration;
this.m = new double[map.length][map.length];
for (int i = 0, n = map.length; i < n; i++) {
int sum = 0;
for (int j = 0, len = map[i].length; j < len; j++) {
sum += map[i][j];
}
for (int j = 0, len = map[i].length; j < len; j++) {
if (map[i][j] == 1) {
m[j][i] = 1.0 / sum;
}
}
}
this.e = new double[map.length];
for (int i = 0, len = m.length; i < len; i++) {
e[i] = 1.0 / len;
}
}
private double[] multiMatrix(double a[][], double b[]) {
double c[] = new double[b.length];
for (int i = 0, n = a.length; i < n; i++) {
double sum = 0.0;
for (int j = 0, m = b.length; j < m; j++) {
sum += a[i][j] * b[j];
}
c[i] = sum;
}
return c;
}
private double[] multiMatrixNumber(double a[], double b) {
double c[] = new double[a.length];
for (int i = 0, n = a.length; i < n; i++) {
c[i] = a[i] * b;
}
return c;
}
private double[] sumMatrix(double a[], double b[]) {
double c[] = new double[a.length];
for (int i = 0, len = a.length; i < len; i++) {
c[i] = a[i] + b[i];
}
return c;
}
public double[] getRank() {
double v[] = Arrays.copyOf(e, e.length);
for (int i = 0; i < iteration; i++) {
double x[] = multiMatrixNumber(multiMatrix(m, v), (this.a));
double y[] = multiMatrixNumber(e, 1 - (this.a));
v = sumMatrix(x, y);
}
return v;
}
public static void main(String[] args) {
int map[][] = new int[][] { { 0, 1, 1, 1 }, { 1, 0, 0, 1 },
{ 0, 0, 1, 0 }, { 0, 1, 1, 0 } };
PageRank pageRank = new PageRank(map, 0.8, 5);
pageRank.getRank();
}
}