PageRank算法及Java代码实现(代码有详解)

PageRank算法及Java代码实现

更改了一些参数的设置,以及加入阻尼系数变量,并且输出时提示是第几次的迭代输出:


 *        相关参数获取

   * 将邻接矩阵放在文本文件中,规则如下:

   * 第一行:节点数;

   * 第二行:迭代的初始PR值,个数与节点数一致,以逗号分隔;

   * 第三行开始:每一行对应邻接矩阵的一行,共N行N列,N同节点数目,其中:

   * 每个节点以逗号分隔,9代表节点自身,1代表有链接关系,0代表无链接关系。

初始PR值一般为1,代码如下:


package org.jazz;


import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;


/**
 * 
 * PageRank代码实现 支持从文件中读取邻接矩阵
 */


public class PageRank {


<span style="white-space:pre">	</span>public static void main(String[] args) throws IOException {


<span style="white-space:pre">		</span>int nodeNum = 100; // 节点数


<span style="white-space:pre">		</span>int TIMES = 20; // 迭代次数
<span style="white-space:pre">		</span>
<span style="white-space:pre">		</span>float alpha = 0.85f; // 阻尼系数d或称为alpha 


<span style="white-space:pre">		</span>int[] outLink = new int[nodeNum]; // 存放节点的外链数A>>>>Z


<span style="white-space:pre">		</span>float rank = 0f; // 中间变量,保存rank值得中间值


<span style="white-space:pre">		</span>float value = 0f; // 计算后的pagerank值


<span style="white-space:pre">		</span>float[] copyPR = new float[nodeNum]; // 迭代完成后由新数组拷贝过来的副本


<span style="white-space:pre">		</span>boolean flag = true;


<span style="white-space:pre">		</span>/*
<span style="white-space:pre">		</span> * --------------------------------------------------------*
<span style="white-space:pre">		</span> * 
<span style="white-space:pre">		</span> * 相关参数获取
<span style="white-space:pre">		</span> * 
<span style="white-space:pre">		</span> * 将邻接矩阵放在文本文件中,规则如下:
<span style="white-space:pre">		</span> * 
<span style="white-space:pre">		</span> * 第一行:节点数;
<span style="white-space:pre">		</span> * 
<span style="white-space:pre">		</span> * 第二行:迭代的初始PR值,个数与节点数一致,以逗号分隔;
<span style="white-space:pre">		</span> * 
<span style="white-space:pre">		</span> * 第三行开始:每一行对应邻接矩阵的一行,共N行N列,N同节点数目,其中:
<span style="white-space:pre">		</span> * 
<span style="white-space:pre">		</span> * 每个节点以逗号分隔,9代表节点自身,1代表有链接关系,0代表无链接关系。
<span style="white-space:pre">		</span> * 
<span style="white-space:pre">		</span> * --------------------------------------------------------
<span style="white-space:pre">		</span> */


<span style="white-space:pre">		</span>FileReader reader = new FileReader("D:\\PRinput-2.txt"); // 邻接矩阵文件存放位置


<span style="white-space:pre">		</span>BufferedReader br = new BufferedReader(reader);


<span style="white-space:pre">		</span>String paramLine = br.readLine();


<span style="white-space:pre">		</span>String initPR = br.readLine();


<span style="white-space:pre">		</span>/*
<span style="white-space:pre">		</span> * -----------------------------*
<span style="white-space:pre">		</span> * 
<span style="white-space:pre">		</span> * 获取节点数
<span style="white-space:pre">		</span> * 
<span style="white-space:pre">		</span> * -----------------------------
<span style="white-space:pre">		</span> */


<span style="white-space:pre">		</span>nodeNum = new Integer(paramLine).intValue(); // 获取节点数


<span style="white-space:pre">		</span>int[][] link = new int[nodeNum][nodeNum]; // 邻接矩阵定义


<span style="white-space:pre">		</span>/*
<span style="white-space:pre">		</span> * -----------------------------*
<span style="white-space:pre">		</span> * 
<span style="white-space:pre">		</span> * 获取迭代初值
<span style="white-space:pre">		</span> * 
<span style="white-space:pre">		</span> * -----------------------------
<span style="white-space:pre">		</span> */


<span style="white-space:pre">		</span>float[] tempPR = new float[nodeNum];


<span style="white-space:pre">		</span>String[] strInit = initPR.split(",");


<span style="white-space:pre">		</span>for (int i = 0; i < strInit.length; i++) {


<span style="white-space:pre">			</span>tempPR[i] = new Float(strInit[i]).floatValue();


<span style="white-space:pre">			</span>System.out.print(tempPR[i] + "f, ");


<span style="white-space:pre">		</span>}


<span style="white-space:pre">		</span>System.out.println();


<span style="white-space:pre">		</span>/*
<span style="white-space:pre">		</span> * -----------------------------*
<span style="white-space:pre">		</span> * 
<span style="white-space:pre">		</span> * 构造邻接矩阵
<span style="white-space:pre">		</span> * 
<span style="white-space:pre">		</span> * -----------------------------
<span style="white-space:pre">		</span> */


<span style="white-space:pre">		</span>int tmp = 0;


<span style="white-space:pre">		</span>while (flag) {


<span style="white-space:pre">			</span>String lineText = br.readLine();


<span style="white-space:pre">			</span>if (null == lineText) {


<span style="white-space:pre">				</span>flag = false;


<span style="white-space:pre">				</span>continue;


<span style="white-space:pre">			</span>}


<span style="white-space:pre">			</span>String[] s = lineText.split(",");


<span style="white-space:pre">			</span>for (int j = 0; j < nodeNum; j++) {


<span style="white-space:pre">				</span>link[tmp][j] = new Integer(s[j]).intValue();


<span style="white-space:pre">			</span>}


<span style="white-space:pre">			</span>tmp++;


<span style="white-space:pre">		</span>}


<span style="white-space:pre">		</span>br.close(); // 关闭流


<span style="white-space:pre">		</span>reader.close(); // 关闭文件


<span style="white-space:pre">		</span>/*
<span style="white-space:pre">		</span> * ---------------------------------*
<span style="white-space:pre">		</span> * 
<span style="white-space:pre">		</span> * 邻接矩阵打印模块
<span style="white-space:pre">		</span> * 
<span style="white-space:pre">		</span> * ---------------------------------
<span style="white-space:pre">		</span> */


<span style="white-space:pre">		</span>for (int i = 0; i < nodeNum; i++) {


<span style="white-space:pre">			</span>for (int j = 0; j < nodeNum; j++) {


<span style="white-space:pre">				</span>System.out.print(link[i][j] + ",");


<span style="white-space:pre">			</span>}


<span style="white-space:pre">			</span>System.out.println();


<span style="white-space:pre">		</span>}


<span style="white-space:pre">		</span>/*
<span style="white-space:pre">		</span> * ---------------------------------*
<span style="white-space:pre">		</span> * 
<span style="white-space:pre">		</span> * 统计节点的外链接数
<span style="white-space:pre">		</span> * 
<span style="white-space:pre">		</span> * ---------------------------------
<span style="white-space:pre">		</span> */


<span style="white-space:pre">		</span>for (int i = 0; i < nodeNum; i++) {


<span style="white-space:pre">			</span>int links = 0;


<span style="white-space:pre">			</span>for (int j = 0; j < nodeNum; j++) {


<span style="white-space:pre">				</span>if (link[i][j] != 9) {


<span style="white-space:pre">					</span>links += link[i][j];


<span style="white-space:pre">				</span>}


<span style="white-space:pre">			</span>}


<span style="white-space:pre">			</span>outLink[i] = links; // 节点0到NODENUM的外链数 假设对应为A B C D


<span style="white-space:pre">		</span>}


<span style="white-space:pre">		</span>System.out.println("");


<span style="white-space:pre">		</span>// 计算PR值


<span style="white-space:pre">		</span>/*
<span style="white-space:pre">		</span> * ----------------------------------------------------------------*
<span style="white-space:pre">		</span> * 
<span style="white-space:pre">		</span> * 循环对每个节点的"入链"进行计算,得到该节点的PR值。 所谓入链接点,就是指邻接矩阵
<span style="white-space:pre">		</span> * 
<span style="white-space:pre">		</span> * 的纵向节点,其计算的方向为纵向;
<span style="white-space:pre">		</span> * 
<span style="white-space:pre">		</span> * 
<span style="white-space:pre">		</span> * 
<span style="white-space:pre">		</span> * 对于横向的每个节点,有一个对应的纵向节点的数组。
<span style="white-space:pre">		</span> * 
<span style="white-space:pre">		</span> * 为0表示没有链接,不用计算,
<span style="white-space:pre">		</span> * 
<span style="white-space:pre">		</span> * 为9表示节点自身,不用计算,
<span style="white-space:pre">		</span> * 
<span style="white-space:pre">		</span> * 为1表示有链接,我们在前一个步骤中已经得到了该入链节点的外链接数。
<span style="white-space:pre">		</span> * 
<span style="white-space:pre">		</span> * ----------------------------------------------------------------
<span style="white-space:pre">		</span> */


<span style="white-space:pre">		</span>for (int m = 0; m < TIMES; m++) { // 迭代


<span style="white-space:pre">			</span>/*
<span style="white-space:pre">			</span> * ------------------------------------------------------------*
<span style="white-space:pre">			</span> * 
<span style="white-space:pre">			</span> * 每次迭代完成后,要把各个节点的PR值放到一个数组中,用于下一次迭代
<span style="white-space:pre">			</span> * 
<span style="white-space:pre">			</span> * 假设放到tempPR[]中;
<span style="white-space:pre">			</span> * 
<span style="white-space:pre">			</span> * 同时,还要保留一个计算用PR值的副本,假设为copyPR[]
<span style="white-space:pre">			</span> * 
<span style="white-space:pre">			</span> * ------------------------------------------------------------
<span style="white-space:pre">			</span> */


<span style="white-space:pre">			</span>// 数组拷贝
<span style="white-space:pre">			</span>int t = m+1;
<span style="white-space:pre">			</span>System.out.println("经过" + t + "次迭代计算,PR值为:");
<span style="white-space:pre">			</span>


<span style="white-space:pre">			</span>for (int x = 0; x < tempPR.length; x++) {


<span style="white-space:pre">				</span>copyPR[x] = tempPR[x];


<span style="white-space:pre">			</span>}


<span style="white-space:pre">			</span>float sum = 0f; // PageRank临时求和变量


<span style="white-space:pre">			</span>// float[] fac = {2f,3f,4f,5f};


<span style="white-space:pre">			</span>for (int node = 0; node < nodeNum; node++) {


<span style="white-space:pre">				</span>/*
<span style="white-space:pre">				</span> * --------------------------------------------------------*
<span style="white-space:pre">				</span> * 
<span style="white-space:pre">				</span> * 这个循环是为了得到本轮各个节点计算后的PR值,将得到一个新的PR值数组
<span style="white-space:pre">				</span> * 
<span style="white-space:pre">				</span> * --------------------------------------------------------
<span style="white-space:pre">				</span> */


<span style="white-space:pre">				</span>// 使用copyPR[]进行计算


<span style="white-space:pre">				</span>for (int j = 0; j < nodeNum; j++) {


<span style="white-space:pre">					</span>int var = link[j][node];


<span style="white-space:pre">					</span>/*
<span style="white-space:pre">					</span> * --------------------------------------------------------*
<span style="white-space:pre">					</span> * 
<span style="white-space:pre">					</span> * 比如要计算第0个节点,那么对应的第0列:
<span style="white-space:pre">					</span> * 
<span style="white-space:pre">					</span> * link[0][0],link[1][0],link[2][0],link[3][0]
<span style="white-space:pre">					</span> * 
<span style="white-space:pre">					</span> * 为其对应的纵向节点,
<span style="white-space:pre">					</span> * 
<span style="white-space:pre">					</span> * 其中值为9代表节点本身,为0不参与计算,为1代表与节点有链接
<span style="white-space:pre">					</span> * 
<span style="white-space:pre">					</span> * -------------------------------------------------------
<span style="white-space:pre">					</span> */


<span style="white-space:pre">					</span>if (var == 0 | var == 9) {


<span style="white-space:pre">						</span>continue; // 没有链接就跳过


<span style="white-space:pre">					</span>} else {


<span style="white-space:pre">						</span>rank = rank + copyPR[j] / (outLink[j]); // 计算


<span style="white-space:pre">					</span>}


<span style="white-space:pre">				</span>}


<span style="white-space:pre">				</span>
<span style="white-space:pre">				</span>value =(float) (rank * alpha + (1-alpha)); // 这个得到该节点在本轮迭代的最后值


<span style="white-space:pre">				</span>sum += value;


<span style="white-space:pre">				</span>System.out.println("PR[" + node + "]" + value); // 信息打印


<span style="white-space:pre">				</span>tempPR[node] = value;


<span style="white-space:pre">				</span>rank = 0f; // 本节点计算完成后,中间变量清零


<span style="white-space:pre">			</span>}


<span style="white-space:pre">			</span>System.out.println("AVG OF PR = " + sum / nodeNum);


<span style="white-space:pre">			</span>System.out.println("=====================================");

<span style="white-space:pre">		</span>}

<span style="white-space:pre">	</span>}

}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章