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