`

浅析PageRank(公式篇2)

 
阅读更多

      上公式~~~PageRank最开始一个版本的公式:

     

      最基本的概念这里不再赘述,对公示稍加解释:页面A的PR是由页面B、C、D一起贡献的,每个页面贡献给A的大小由各自链出数目决定,如果B有五个链出,PR(B)=10,那么就有2的值给A。q是阻尼因子,指代浏览者沿着当前链接继续阅读的可能性,每个页面都有一个最小值1-q,PR中q=0.85。

      接下来,用实例说明:(为了使计算简单明了,实例中的页面无外部的链入和链出,实际PR算法的设计也是依据将互联网看做一个整体,只有内部成员间的连接,无外部链接)

      自己随意画了一个关系图,箭头代表A、B、C页面间的联系(为使矩阵运算简单可观,这里只列出三个页面)。


              

      由图可以看出,它们之间的关联以及构造的矩阵如下(不懂怎么构造矩阵的去看公式篇1,不再解释~~):
                     

      (赤果果的word图,好难看啊~)然后我们沿着之前说过的思路,将矩阵进行转置和概率化,结果如下:
                          

      对如图概率化后的矩阵求解特征值和相对应的特征向量,解得最大特征值所对应特征向量中的原素即为各页面的PR值。这里我们从数学思想与PR公式两个角度进行计算,以验证结果的有效性。

      1、数学实现

      通过公式Ax=kx(详细求解过程与思路1中都已经介绍,这里给出大体思路和结果),其中k为特征值,x为特征向量。求解特征值时,根据(A-kE)x=0,E为与A同型的单位矩阵,即求|A-kE|=0,经计算可得 -k3+1/4k=0,因为数学中的前提是 k0,所以k=1/2,解得特征向量为p=(1,1,2)T,可以得所有的mp( m0)均为特征值1/2的特征向量。

      2、公式

      由公式PR(A)=(PR(B)/L(B)+PR(C)/L(C))*0.85+0.15,假设A、B、C的初始PR均为1,那么通过代入公式,进行第一次求值可得PR(A)=0.575,PR(B)=0.394375,PR(C)=0.7119844(注:在这里计算的时候取的精度为float,与以下代码中使用的相同,也就是精确到小数点后7位)。再将第一次得出的值代入公式进行第二次计算,可得PR(A)=0.31760937,PR(B)=0.284984,PR(C)=0.5561022,重复代入的步骤进行计算,这里不列出全值,但是通过观察结果可以看出,一直到第11次开始,A、B、C三者的PR值保持了一致,不再随计算的重复性变动,当然这里的精确度达到了小数点后的7位,如果对精确度的要求更低,运算的次数会大大减少,比如对精度的要求是小数点后2位,那么计算到第4次便达到了要求。最终的稳定结果是PR(A)=0.26086956,PR(B)=0.26086956,PR(C)=0.5217391。

 

      将公式计算的结果与数学方法所求的值相比可以看出,数学实现的结果中存在的关联关系PR(A)=PR(B)=1/2*PR(C)与通过公式计算的结果PR(A)=0.26086956,PR(B)=0.26086956,PR(C)=0.5217391有着高度的一致性,因此,这两种方法在思路上是统一的。

 

      由这个例子,我们可以再回过头来分析阻尼因子q的作用。Sample中出现了一个比较特殊的情况,C页面只有链入没有链出,也就是说迭代时A,B的值不断传入C,C却不为PR的传播做任何贡献,这必然会导致有限次计算后全网的PR趋于0。加入阻尼因子后,我们看到,计算的结果并未受这一情况的影响,网页间实际PR的计算依然与模型一致,这就是概念篇中提到过的消除值沉淀问题。

 

      这里还有一个很重要的问题要说明:Brin与Page的设计中,证明无论如何取初值,计算结果都会收敛到一个固定的值,之前的计算中取得初值全为1,此时我们验证一下这个说法的正确性。令PR(A)=1,PR(B)=2,PR(C)=3,运算后在第12次、float精度下趋于稳定;令PR(A)=60,PR(B)=70,PR(C)=80,运算在第14次、float精度下趋于稳定;令PR(A)=100,PR(B)=500,PR(C)=1000,运算在第15次、float精度下趋于稳定…………从例子中可以看出,不论初值如何取,最终的计算结果都会趋于一个稳定值,当然这些稳定值也是相等的,区别则是当选取了一个合理的初始值,会使得计算的次数减少,这里只是一个三维矩阵的计算,差距可能不够明显,实际操作中面对几十亿的网页数量这种操作的时间差是不可忽视的。从这些计算值中,可以看出运算次数在随着初始值的增加而增加,个人猜测这或许也是Google将网页排名定为0~10的一个原因,如果将几十的初始值放入十亿单位的网页操作,计算量应该相当的惊人。

 

      本来想进行一下随着维度增加,运算时间变化的分析,但实现过程中发现这个运算时间的影响因素太多,比如电脑运算的即时性、录入矩阵的复杂度等,使得运算之变化幅度很大,维度之间差距也不够明显,尤其是矩阵内部链接复杂度对运算影响非常大,一个简单的四维矩阵可以比上文例举的三维矩阵算短一半时间,复杂的四维花费又变成了一倍,因此这里不列出数据进行对比,感兴趣的话可以自行研究~但是可以确定的是,这个时间量的增加并不是线性的,当维度增加n,行的遍历增加n,列的遍历也增加了n,额外增加的数据其实是n2个,三位矩阵的耗时为28毫秒(取大致的平均值),那么可以假设同等复杂度的维度是1亿的矩阵为28/9*1016毫秒,这还不考虑多耗费的用于创建临时变量以及数组的时间。同时我们可以估算出来,此时初始值有108个,400MB的数据是可以接受的,但矩阵里面的数据有108*108个元素,每个float型占4Byte,也就是需要4*108*108B,等同于40000TB……这需要多么庞大的存储空间啊……

 

      讨论过了理论,我用java的方法模拟一下PR值的计算过程,具体的描述代码中都写出来了,使用的思路和上述Sample一样,只不过代码中是直接从选定的文件中读入初始PR值以及矩阵元素(文件中的书写顺序是:第一行为各个初始的PR值,接下来是矩阵,每行的元素之间通过,分隔,行与行之间无分隔符),然后进行转置、概率化、公式重复求解(这份新代码修改了一个计算上的失误,也增加了随机生成一个矩阵的方法,节省了手工录入矩阵的时间。其中矩阵维度就是矩阵的大小,初始值为初始的PR值,复杂度指代连接中有百分之多少多少为1,当然,这里的复杂度只是取最简单情况,实际中计算复杂程度取决于更为详细的链接情况,比如全部都是50%的复杂度,全单向链接和存在双向链接的计算时间与收敛次数必然不会相同)

package cn.wx.PageRank;

import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;

/**
 * 求取PageRank值的代码
 * @author 艾儿
 */
public class newPageRank {
	
	static JTextField jtf;//显示文件路径的框
	static JTextArea jta;//显示计算结果的框
	static JFrame jf;//显示的窗体
	static JFrame jf1;//显示输入矩阵的窗体
	static float[] data;//存数输入数据的数组
	static int time=20;//指定的运行次数
	
	public static void main(String [] args){
		newPageRank mine = new newPageRank();
		mine.showUI();
	}
	
	/**
	 * 展示计算结果的界面
	 */
	public void showUI(){
		//初始化界面以及按钮、输入框等
		jf = new JFrame();
		jf.setTitle("PR值计算~~");
		jf.setSize(500, 500);
		jf.setDefaultCloseOperation(3);
		jf.setResizable(false);
		jf.setLayout(null);
		jf.setLocationRelativeTo(null);
		
		JButton btn = new JButton("打开");
		btn.setActionCommand("Open");
		btn.setBounds(20, 20, 80, 30);
		
		JButton btn1 = new JButton("随机");
		btn1.setActionCommand("Input");
		btn1.setBounds(110, 20, 80, 30);
		
		jtf = new JTextField();
		jtf.setBounds(200, 20, 260, 30);
		jtf.setEditable(true);
		jtf.setActionCommand("Over");
		
		jta = new JTextArea();
		jta.setEditable(false);
		jta.setLineWrap(true);
		jta.setAutoscrolls(true);
		
		JScrollPane jsp = new JScrollPane(jta);//创建滚动条
		jsp.setBounds(20, 70, 460, 380);
		
		
		//添加监听器
		ActionListener al = new ActionListener(){
			public void actionPerformed(ActionEvent e) {
				if(e.getActionCommand().equals("Open")){
					//弹出选择框
					jta.setText("");//每次重新选择之前清空输入框
					JFileChooser fc = new JFileChooser();
					int value = fc.showOpenDialog(null);
					fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
					if(value == JFileChooser.CANCEL_OPTION){
						return;
					}
					File file = fc.getSelectedFile();
					jtf.setText(file.getAbsolutePath());
					readFile(file);
				}
				if(e.getActionCommand().equals("Input")){
					init();//初始化窗体,获取值
				}
				if(e.getActionCommand().equals("Over")){
					jta.setText("");
					//输入路径结束,执行以下操作
					File file = new File(jtf.getText());
					readFile(file);
				}
			}
			
		};
		
		jf.add(btn);
		jf.add(btn1);
		jf.add(jtf);
		jf.add(jsp);
		btn.addActionListener(al);
		btn1.addActionListener(al);
		jtf.addActionListener(al);
		
		jf.setVisible(true);
	}
	
	/**
	 * 读取相应路径文件的方法
	 * 定义文件中第一行是节点对应的初始化PR值,接下来是N*N的矩阵
	 * 同行数据之间均通过,分隔,不同行无需分隔符
	 * @param file:文件
	 */
	public static void readFile(File file){
		try {
			//创建读文件的流
			FileReader fr = new FileReader(file);
			BufferedReader br = new BufferedReader(fr);
			
			String PR = br.readLine();
			String[] sPR = PR.split(",");//将第一行PR值存入对应数组
			//将读取的PR值从String转为float
			float[] initPR = new float[sPR.length];
			for(int i=0;i<sPR.length;i++){
				initPR[i] = Float.parseFloat(sPR[i]);
			}
			jta.append("各页面的初始PR值………………………………………………………………"+"\n");
			for(int i=0;i<initPR.length;i++){
				jta.append(initPR[i]+"\t");//打印出PR值
			}
			jta.append("\n");
			
			//读取并创建N*N矩阵,在这里使用float,精度为小数点后7位
			float[][] array = new float[initPR.length][initPR.length];
			int count = 0;//用计数器控制行的变化
			//当行数小于指定数N时进行读取
			while(count<initPR.length){
				String value = br.readLine();//读取一行的值
				String[] rowV = value.split(",");
				//对第count行第i列赋值
				for(int i=0;i<initPR.length;i++){
					array[count][i] = Float.parseFloat(rowV[i]);
				}
				count++;
			}
			jta.append("原始矩阵为………………………………………………………"+"\n");
			print(array);//打印出矩阵
			//读取完成后,调用计算的函数对矩阵进行计算
			long start = System.currentTimeMillis();
			calculate(initPR,array);
			long end = System.currentTimeMillis();
			jta.append("total time is:"+(end-start));
		} catch (FileNotFoundException e) {
			javax.swing.JOptionPane.showMessageDialog(jf,"文件未找到,请重试!");
		} catch (IOException e) {
			javax.swing.JOptionPane.showMessageDialog(jf,"文件读取有误,请重试!");
		}
	}
	
	/**
	 * 打印矩阵的方法
	 * @param s
	 */
	static void print(float[][] f){
		for(int i=0;i<f.length;i++){
			for(int j=0;j<f.length;j++){
				jta.append(f[i][j]+"\t");
			}
			jta.append("\n");
		}
	}

	/**
	 * 计算矩阵特征值以及特征向量的方法
	 * @param initPR:存储初始的PR值的float数组
	 * @param array:存储初始矩阵的float二维数组
	 */
	static void calculate(float[] initPR,float[][] array){
		array = changeRC(array);//倒置矩阵
		jta.append("转置后的矩阵…………………………………………………………");
		jta.append("\n");
		print(array);
		array = randomization(array);//概率化矩阵
		jta.append("\n");
		jta.append("概率化后的矩阵………………………………………………………………");
		jta.append("\n");
		print(array);
		for(int i=1;i<=time;i++){
			initPR = formular(initPR,array);
			jta.append("\n");
			jta.append("经过"+i+"次计算,PR值为………………………………………………");
			jta.append("\n");
			for(int j=0;j<initPR.length;j++){
				jta.append("PR["+j+"]的值为:"+initPR[j]);
				jta.append("\n");
			}
		}
		jta.repaint();
	}
	
	/**
	 * 转置矩阵的方法
	 * @param array:需要转置的矩阵
	 * @return:将转置后的矩阵返回
	 */
	static float[][] changeRC(float[][] array){
		float temp = 0;//临时变量,用于交换
		for(int i=0;i<array.length;i++){
			for(int j=0;j<array.length;j++){
				//对矩阵的每一行、列遍历,如果下标i<j就倒换
				if(i<j){
					temp = array[i][j];
					array[i][j] = array[j][i];
					array[j][i] = temp;
				}
			}
		}
		return array;
	}
	
	/**
	 * 概率化矩阵的方法
	 * @param array:需要概率化的矩阵
	 * @return:返回已经概率化的矩阵
	 */
	static float[][] randomization(float[][] array){
		int count = 0;//控制列变化的计数器
		int size = 0;//计量列中连接为1的元素数量的计数器
		while(count<array.length){
			size = 0;//每次计数之前要清零
			for(int i=0;i<array.length;i++){
				if(array[i][count]==1){
					size++;//先统计出数量为多少
				}
			}
			jta.append("the size of "+count+" is:"+size+"    ");
			for(int i=0;i<array.length;i++){
				if(array[i][count]==1){
					array[i][count]=(float)1/size;
				}
			}
			count++;
		}
		return array;
	}
	
	/**
	 * 通过公式计算PR值
	 * @param initPR:初始PR值
	 * @param array:经处理的矩阵
	 * @return:返回计算后的PR值
	 */
	static float[] formular(float[] initPR,float[][] array){
		for(int i=0;i<initPR.length;i++){
			initPR[i] = 0;//重算一个PR之前,将其清零
			int count =0;//计量每一行0元素个数
			for(int j=0;j<initPR.length;j++){
				if(i!=j && array[i][j]!=0){
					initPR[i] = (float) (initPR[i]+((initPR[j]*array[i][j])*0.85+0.15));
				}else
					count++;
			}
			if(count==initPR.length){
				initPR[i] = (float) 0.15;
			}
		}
		return initPR;
	} 
	
	
	static void input(float[] data){
		float size = data[0];
		float complex = data[1];
		float[] initPR = new float[data.length-2];
		for(int i=0;i<initPR.length;i++){
			initPR[i] = data[i+2];
		}
		float[][] array = new float[(int) size][(int) size];//创建输入大小的矩阵
		//初始化矩阵元素为0
		for(int i=0;i<array.length;i++){
			for(int j=0;j<array.length;j++){
				array[i][j]=0;
			}
		}
		int num = (int) (complex/100*array.length*array.length);//需要被赋为1的元素个数
		//为矩阵按照复杂程度赋值
		while(num>0){
			int row = (int) (Math.random()*(array.length));
			int column = (int) (Math.random()*(array.length));//随机生成行列数
			if(row!=column && array[row][column]!=1){
				array[row][column]=1;
				num--;
			}
		}
		//打印随机生成的PR和矩阵
		jta.append("各页面的初始PR值………………………………………………………………"+"\n");
		for(int i=0;i<initPR.length;i++){
			jta.append(initPR[i]+"\t");//打印出PR值
		}
		jta.append("\n");
		jta.append("生成的矩阵…………………………………………………………………………"+"\n");
		print(array);
		//将计算好的初始PR数组和矩阵传入计算
		long start = System.currentTimeMillis();
		calculate(initPR,array);
		long end = System.currentTimeMillis();
		jta.append("total time is:"+(end-start));
	}
	
	/**
	 * 初始化一个输入值的窗体
	 */
	static void init(){
		jf1 = new JFrame("生成随机矩阵");
		jf1.setSize(300, 160);
		jf1.setResizable(false);
		jf1.setDefaultCloseOperation(2);
		jf1.setLocationRelativeTo(null);
		jf1.setLayout(new FlowLayout());
		
		JLabel lb = new JLabel("矩阵维度:");
		final JTextField jtf = new JTextField(15);
		JLabel lb1 = new JLabel("初始PR值:");
		final JTextField jtf1 = new JTextField(15);
		JLabel lb2 = new JLabel("    复杂度:  ");
		final JTextField jtf2 = new JTextField(15);
		jtf2.setActionCommand("sure");
		JLabel lb3 = new JLabel("% ");
		JButton btn = new JButton("确认");
		btn.setActionCommand("sure");
		JButton btn1 = new JButton("取消");
		btn1.setActionCommand("cancle");
		
		ActionListener al = new ActionListener(){
			public void actionPerformed(ActionEvent e) {
				if(e.getActionCommand().equals("sure")){
					//点击确认后,存储输入值
					float size = Integer.parseInt(jtf.getText());//取值
					String[] s = jtf1.getText().split(",");
					float complex = Integer.parseInt(jtf2.getText());
					
					//初始化数组,将输入框中的值存入数组
					data = new float[s.length+2];
					//先存入矩阵维度,再放入复杂度,最后存入各个初始值
					data[0] = size;
					data[1] = complex;
					for(int i=0;i<s.length;i++){
						data[2+i] = Float.parseFloat(s[i]);
					}
					jf1.dispose();
					input(data);
				}
				if(e.getActionCommand().equals("cancle")){
					jf1.dispose();
				}
			}
			
		};
		
		jf1.add(lb);
		jf1.add(jtf);
		jf1.add(lb1);
		jf1.add(jtf1);
		jf1.add(lb2);
		jf1.add(jtf2);
		jf1.add(lb3);
		jf1.add(btn);
		jf1.add(btn1);
		
		jtf2.addActionListener(al);
		btn.addActionListener(al);
		btn1.addActionListener(al);
		
		jf1.setVisible(true);
	}
	
}

 

 

 

     关于公式再提一下,Google后来调整时使用了1-q/N,公式的其他部分未作任何变动,这里的N是互联网中全部的网页数量,网上的参考资料说这样做使得网页级别变为了被随机访问的期望值(不理解)……做一下比较,对于0.15/N这个公式,从逻辑上看也可以认为是加速了值收敛,通过代码计算验证发现,对于同样维度为10的矩阵,初始值全为1,复杂度为50%,原公式经过20次运算后,有9个PR值收敛到了小数点后2位,一个收敛到了小数点后1位,而改进后的公式,有8个PR值收敛到了小数点后3位,2个收敛到小数点后2位。可以看出,仅仅是10维矩阵就几乎存在一位的精度差,如果应用到上亿的网页运算中,计算时间一定会大大的缩减~但是这种情况下的计算比较复杂,而且两种计算的原理近似,这里不再额外讨论。

 

 

 

 

 

 

  • 大小: 11.3 KB
  • 大小: 6.1 KB
  • 大小: 17.8 KB
  • 大小: 22.5 KB
  • 大小: 16.2 KB
  • 大小: 22.7 KB
分享到:
评论
1 楼 luliangy 2012-01-31  

相关推荐

    matlab编程实现pagerank公式

    用matlab编程实现的pagerank算法 与你们分享

    pagerank_大数据pagerank算法代码_pageRank_

    2. **初始化PageRank**:所有网页初始PageRank值平均分配。 3. **迭代更新**:按照PageRank公式进行迭代更新,直到收敛或达到预设的最大迭代次数。 4. **处理悬挂链**:悬挂链是指没有出链的网页,它们的PageRank...

    PageRank_pageRank_python_

    2. 计算转移:每个网页的PageRank值按以下公式分配给链接的目标网页:PR(A) = (1-d) + d * Σ(PR(Ti)/L(Ti)),其中PR(A)是网页A的PageRank值,d为阻尼因子(通常设置为0.85),PR(Ti)是链接到A的第i个网页的PageRank...

    pageRank-详细解析(具体例子).docx

    为了解决这个问题,引入了公式(2),其中N(j)表示网页j的超链接数,每个链接的重要性被平均分配。为了使PageRank值具有可比性,进一步引入了一个常数C,得到公式(3): \[ R(x) = \frac{C}{N_j} \sum_{B(x)} R(j) \] ...

    pagerank算法

    2. **PageRank算法公式**: PageRank的计算公式是:PR(A) = (1-d) + d (PR(T1)/C(T1) + ... + PR(Tn)/C(Tn)),其中PR(A)表示页面A的PageRank值,PR(Ti)是链接到页面A的页面Ti的PageRank值,C(Ti)是页面Ti的出链数量...

    Go-pagerank-加权PageRank算法Go实现

    3. **迭代更新**:按照PageRank公式进行迭代计算,每一轮迭代中,每个网页的PageRank值是所有入链网页的PageRank值乘以相应的权重之和,再加上阻尼因子乘以所有网页PageRank的平均值。 4. **判断收敛**:在每次迭代...

    基础PageRank 算法 C++实现

    2. **PageRank的迭代过程** - 初始化:所有网页的PageRank值设为1/N,N为网页总数。 - 计算:按照上述公式,迭代计算每个网页的PageRank值,直到满足收敛条件(如连续两次计算的PageRank值变化小于某个阈值)或...

    pagerank_BSU_大数据课程大作业一_南开大学_pagerank算法_pageRank_

    PageRank的更新公式为:`PR(i) = (1-d) + d * Σ(PR(j)/L(j))`,其中PR(i)是网页i的新PageRank,PR(j)是链接到i的网页j的PageRank,L(j)是j的出链数量。 5. **处理悬空链接**:有些网页没有出链,称为悬空节点。...

    PageRank博文

    PageRank矩阵的迭代公式如下: \[ P = (1-d)TP + \frac{d}{N}E \] 其中,P是PageRank向量,T是转移矩阵,d是阻尼因子,N是网页总数,E是一个所有元素均为1/N的矩阵,表示随机跳转到任何页面的概率。 在实际计算中,...

    pagerank数据集.rar

    2. **迭代计算**: 在每次迭代中,每个节点的PageRank值由其链接的所有节点的PageRank值按比例分配。分配的比例是链接节点的PageRank除以链接总数。公式大致为:PR(A) = (1-d) + d * Σ(PR(B)/L(B)),其中A是目标节点...

    python实现PageRank算法

    2. **迭代计算**:根据网页间的链接关系,按照一定的规则进行PageRank值的传递。每个网页的PageRank值等于所有链接至该网页的网页PageRank值之和乘以转移概率(通常是0.85,剩余的0.15随机分散到所有网页)。 3. **...

    无向图pagerank算法(Java)

    2. **迭代计算**:在每次迭代中,每个网页的PageRank值由其所有入链网页的PageRank值加权平均得出,加权因子为链接到该网页的网页数的倒数。如果存在死链(没有出链的网页),需要添加“阻尼因子”(通常为0.85),...

    有关pagerank算法论文

    此公式体现了PageRank算法的迭代特性,即网页的PageRank值会随着整个网络中所有网页的PageRank值的更新而不断调整。 ### PageRank算法的应用与影响 PageRank算法自推出以来,迅速改变了搜索引擎行业的格局。Google...

    pagerank算法模拟实现

    2. 计算新PageRank:对于每个网页i,其新的PageRank值PR(i)由以下公式计算: PR(i) = (1-d) + d * Σ(PR(j)/L(j)),其中d是阻尼因子,j是链接到i的所有网页,L(j)是网页j的出链数量。这意味着网页的PageRank值一...

    PageRank.zip_PageRank下载_packrank_pagerank dataset_pagerank 数据_pa

    - **迭代计算**:按照PageRank公式,计算每个网页的新PageRank值,公式为`PR(p) = (1-d)/N + d * Σ PR(q)/L(q)`,其中`d`是阻尼因子(通常取0.85),`N`是网页总数,`PR(q)`是链接到网页`p`的网页`q`的PageRank值...

    pageRank算法实例加代码

    2. **投票页面的PageRank**:高PageRank的页面投出的票更具有价值,因此,来自高PageRank页面的链接对目标页面的影响更大。 3. **阻尼因子**:为了防止无限循环的链接投票,PageRank引入了阻尼因子(通常为0.85),...

    pagerank-java实现查询

    这篇博士论文文档详细阐述了PageRank的理论基础和实现原理,由Google的创始人Larry Page和Sergey Brin提出。Java实现的PageRank查询代码则为我们提供了实际操作这一算法的实例。 PageRank的基本思想是,一个网页的...

    Google的PageRank算法学习

    - 初始时,每个网页的PageRank值设置为相同的数值,然后根据上述公式进行多轮迭代,直到PageRank值收敛为止。 - 实际应用中,通常需要进行数十次甚至上百次迭代才能获得满意的PageRank值。 2. **PageRank值的特性...

Global site tag (gtag.js) - Google Analytics