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