一个网络(有向带权图)中节点u的PageRank的计算公式:
![](https://i-blog.csdnimg.cn/blog_migrate/f439a4be4594f848205f3ded581a46ae.png)
PR(u)表示节点u的PageRank值,d为衰减因子(damping factor)或阻尼系数,一般取d=0.85,N为网络中的节点总数,nb(u)表示节点u的所有邻居节点的集合,d(v)表示节点v的出度(如果是无向图,就是度),w(u,v)表示节点v的边<u,v>所占的权重(如果对于无权图或者认为每条边的权重都一样,那么w(u,v)=1),PR(v)表示节点v的PageRank值。
由此可以看出要算出节点u的PR值需要先知道它的每个邻居节点的PR值,似乎是个递归的过程。其实初始状态下,可以给每个节点的PR值都赋值为一个任意正数,例如1,然后通过上述公式不断迭代计算更新每个节点的PR值,数学证明,最终每个节点的PR值都会收敛到一个稳定的PR值(初值PR不同,最终的PR值也不同,但最后各节点之间PR的大小排名不因初值而改变)。编程时如何确定某个节点u的PR值已经收敛?如果这次的PR值与上次的PR值相差很小的时候就可以认为收敛了。很小是多小?越小越好,但不要太小,免得迭代次数太多浪费时间,可取10的-4或-5次方。
PageRank的数学原理的详细说明,可参考:
PageRank on undirected and weighted graph
《集体智慧编程》上的例子:
![](https://i-blog.csdnimg.cn/blog_migrate/43ea834c35c804f8cae4a4a76f90b570.png)
![](https://i-blog.csdnimg.cn/blog_migrate/63d6d2a78a1d0d35ee855224dae3f738.png)
Java实现代码:
Program.java:
1 package dd.lt;
2
3 import dd.lt.entity.Node;
4
5 public class Program
6 {
7 //计算每个节点的PageRank值
8 public static void CalcPageRank(ArrayList<Node> graph)
9 {
10 double distance = 0.00001;
11 double d = 0.85;// damping factor
12 double common = (1 - d) / graph.size();
13 while (true)
14 {
15 for (Node n : graph)
16 {
17 double sum = 0.0;
18 for (int nodeId : n.getNeighbors())
19 {
20 Node nb = getNodeById(nodeId,graph);
21 sum += nb.getPR() / nb.getDegree();
22 }
23 double newPR = common + d * sum;
24 //如果尚未收敛,赋新值,否则结束迭代
25 if (Math.abs(n.getPR() - newPR) > distance)
26 n.setPR(newPR);
27 else
28 return;
29 }
30 }
31 }
32
33 public static Node getNodeById(int nodeId,ArrayList<Node> graph)
34 {
35 for(Node n:graph)
36 {
37 if (n.nodeId==nodeId)
38 return n;
39 }
40 return null;
41 }
42
43
44 public static ArrayList<Node> buildGraph()
45 {
46 ArrayList<Node> graph = new ArrayList<Node>();//图以节点集合形式来表示
47 //加载数据,组装好图结构
48 ....
49 return graph;
50 }
51
52 public static void main(String[] args)
53 {
54 ArrayList<Node> graph = buildGraph();
55 CalcPageRank(graph);
56 for(Node n:graph)
57 {
58 System.out.println("PageRank of %d is %.2f",n.nodeId,n.getPR());
59 }
60 }
61 }
Node.java:
1 package dd.lt.entity;
2
3 import java.util.ArrayList;
4
5 public class Node implements Comparable<Node>
6 {
7 public int nodeId;
8 private ArrayList<Integer> neighbors = new ArrayList<Integer>();//以邻接表的形式表示图结构【无向图】
9 private double pr=1; //每个节点的初始PageRank值设为1
10 public Node(int nodeId)
11 {
12 this.nodeId = nodeId;
13 }
14
15 public int getDegree()
16 {
17 return this.neighbors.size();
18 }
19
20 public ArrayList<Integer> getNeighbors()
21 {
22 return this.neighbors;
23 }
24 public void setNeighbors(ArrayList<Integer> neighbors)
25 {
26 this.neighbors=neighbors;
27 }
28
29 public double getPR()
30 {
31 return pr;
32 }
33 public void setPR(double val)
34 {
35 this.pr=val;
36 }
37
38 // 按PageRank值排序
39 public int compareTo(Node anotherNode)
40 {
41 if (this.neighbors != null && anotherNode.neighbors != null)
42 {
43 // 降序排列
44 if (anotherNode.getPR() >this.getPR())
45 return 1;
46 else if (anotherNode.getPR() <this.getPR())
47 return -1;
48 else
49 return 0;
50 // 升序排列
51 // return this.getPR()-anotherNode.getPR();
52 }
53 return 0;
54 }
55 }