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>} }