参考资料:http://blog.csdn.net/hguisu/article/details/7996185
更多数据挖掘算法https://github.com/linyiqun/DataMiningAlgorithm

链接分析

在链接分析中有2个经典的算法,1个是PageRank算法,还有1个是HITS算法,说白了,都是做链接分析的。具体是怎么做呢,继续往下看。

PageRank算法

要说到PageRank算法的作用,得先从搜索引擎开始讲起,PageRank算法的由来正式与此相关。

搜索引擎

最早时期的搜索引擎的结构,无外乎2个核心步骤,step1:建立庞大的资料库,step2:建立索引库,用于指向具体的资料。然后就是用户的查找操作了,那怎么查呢,一个很让人会联想到的方法就是通过关键字匹配的方法,例如我想输入张三这个关键词,那我就会在资源中查包含有张三这个词语的文章,按照关键词匹配方法,只要一篇文章中张三出现的次数越多,就越是要查询的目标。(但是更公正的方法应是次数/文章总次数,一个比值的形式显然更公平)。仔细这么想也没错。好继续往下。

Term Spam攻击

既然我已经知道了搜索的核心原理,如果我想要让我的网页能够出现在搜索的结果更靠前的位置,只要在页面中加入更多对应的关键词不就OK了,比如在html的div中写入10000个张三,让后使其隐藏此标签,使得前端页面不受影响,那我的目的岂不是达到了,这就是Term Spam攻击。

PageRank算法原理

既然关键词匹配算法容易遭到攻击,那有什么好的办法呢,这是候就出现了著名的PageRank算法,作为新的网页排名/重要性算法,最早是由Google的创始人所写的算法,PageRank算法彻底摒弃了什么关键词不关键词的,每个网页都有自己的PageRank值,意味一个网页的重要程度,PR值越高,最后呈现的位置更靠前。那怎么衡量每个网页的重要程度呢,答案是别的页面对他的链接。一句话,越多的网页在其内容上存在指向你的链接,说明你的网页越有名。具体PR值的计算全是通过别的网页的PR值做计算的,简单计算过程如下:

假设一个由只有4个页面组成的集合:A,B,C和D。如果所有页面都链向A,那么A的PR(PageRank)值将是B,C及D的和。

链接挖掘算法之PageRank算法和HITS算法

继续假设B也有链接到C,并且D也有链接到包括A的3个页面。一个页面不能投票2次。所以B给每个页面半票。以同样的逻辑,D投出的票只有三分之一算到了A的PageRank上。

链接挖掘算法之PageRank算法和HITS算法

换句话说,根据链出总数平分一个页面的PR值。

链接挖掘算法之PageRank算法和HITS算法

所示的例子来说明PageRank的具体计算过程。

链接挖掘算法之PageRank算法和HITS算法

以上是网页内部有链接的时候,因为还可能在1个网页中没有任何链接的情况,而这个时候,跳到任何网页的概率都是可能的。因此最后的计算公式就变成了这个样子:

链接挖掘算法之PageRank算法和HITS算法

q称为阻尼系数。

PageRank的计算过程

PageRank的计算过程实际并不复杂,他的计算数学表达式如下:

链接挖掘算法之PageRank算法和HITS算法

就是1-q变成了1-q/n了,算法的过程其实是利用了幂法的原理,等最后计算达到收敛了,也就结束了。

按照上面的计算公式假设矩阵A =q× P + ( 1 一 q) *链接挖掘算法之PageRank算法和HITS算法/N,e为全为1的单位向量,P是一个链接概率矩阵,将链接的关系通过概率矩阵表现,A[i][j]表示网页i存在到网页j的链接,转化如下:

链接挖掘算法之PageRank算法和HITS算法链接挖掘算法之PageRank算法和HITS算法链接挖掘算法之PageRank算法和HITS算法
图2 网页链接矩阵: 图3 网页链接概率矩阵:
链接挖掘算法之PageRank算法和HITS算法链接挖掘算法之PageRank算法和HITS算法

图4 P’ 的转置矩阵

这里为什么要把矩阵做转置操作呢,原本a[i][j]代表i到j链接,现在就变为了j到i的链接的概率了,好,关键记住这点就够了。最后A就计算出来了,你可以把他理解为网页链接概率矩阵,最后只需要乘上对应的网页PR值就可以了。

此时初始化向量R[1, 1, 1];代表最初的网页的PR值,与此A概率矩阵相乘,第一个PR值R[0]'=A[0][0]*R[0] + A[0][1]*R[1]+ A[0][2]*R[2],又因为A[i][j]此时的意思正是j到i网页的链接概率,这样的表达式恰恰就是上文我们所说的核心原理。然后将计算新得的R向量值域概率矩阵迭代计算直到收敛。

PageRank小结

PageRank的计算过程巧妙的被转移到了矩阵的计算中了,使得过程非常的精简。

Link Spam攻击

魔高一尺道高一丈,我也已经知道了PageRank算法的原理无非就是靠链接数升排名嘛,那我想让我自己的网页排名靠前,只要搞出很多网页,把链接指向我,不就行了,学术上这叫Link Spam攻击。但是这里有个问题,PR值是相对的,自己的网页PR值的高低还是要取决于指向者的PR值,这些指向者 的PR值如果不高,目标页也不会高到哪去,所以这时候,如果你想自己造成一堆的僵尸网页,统统指向我的目标网页,PR也不见的会高,所以我们看到的更常见的手段是在门户网站上放链接,各大论坛或者类似于新浪,网页新闻中心的评论中方链接,另类的实现链接指向了。目前针对这种手法的直接的比较好的解决办法是没有,但是更多采用的是TrustRank,意味信任排名检测,首先挑出一堆信任网页做参照,然后计算你的网页的PR值,如果你网页本身很一般,但是PR值特别高,那么很有可能你的网页就是有问题的。

HITS

HITS算法同样作为一个链接分析算法,与PageRank算法在某些方面还是比较像的,将这2种算法放在一起做比较,再好不过的了,一个明显的不同点是HITS处理的网页量是小规模的集合,而且他是与查询相关的,首先输入一个查询q,假设检索系统返回n个页面,HITS算法取其中的200个(假设值),作为分析的样本数据,返回里面更有价值的页面。

HITS算法原理

HITS衡量1个页面用A[i]和H[i]值表示,A代表Authority权威值,H代表Hub枢纽值。

大意可理解为我指出的网页的权威值越高,我的Hub值越大。指向我的网页的Hub值越大,我的权威值越高。二者的变量相互权衡。下面一张图直接明了:

链接挖掘算法之PageRank算法和HITS算法

图3 Hub与Authority权值计算

如果理解了PageRank算法的原理,理解HITS应该很容易,最后结果的输出是根据页面的Authority权威值从高到低。

HITS算法描述

链接挖掘算法之PageRank算法和HITS算法

具体可以对照后面我写的程序。

HITS小结

从链接反的角度来思考,HITS更容易遭受到Link Spam的攻击,因为你想啊,网页数量少啊,出错的几率就显得会大了。

PageRank算法和HITS算法实现

最后奉上本人亲自实现的2个算法,输入数据是同一个文(每条记录代表网页i到网页j存在链接):

  1. 12
  2. 13
  3. 23
  4. 31
算法都不是太难:

  1. packageDataMining_PageRank;
  2. importjava.io.BufferedReader;
  3. importjava.io.File;
  4. importjava.io.FileReader;
  5. importjava.io.IOException;
  6. importjava.lang.reflect.Array;
  7. importjava.text.MessageFormat;
  8. importjava.util.ArrayList;
  9. /**
  10. *PageRank网页排名算法工具类
  11. *
  12. *@authorlyq
  13. *
  14. */
  15. publicclassPageRankTool{
  16. //测试输入数据
  17. privateStringfilePath;
  18. //网页总数量
  19. privateintpageNum;
  20. //链接关系矩阵
  21. privatedouble[][]linkMatrix;
  22. //每个页面pageRank值初始向量
  23. privatedouble[]pageRankVecor;
  24. //网页数量分类
  25. ArrayList<String>pageClass;
  26. publicPageRankTool(StringfilePath){
  27. this.filePath=filePath;
  28. readDataFile();
  29. }
  30. /**
  31. *从文件中读取数据
  32. */
  33. privatevoidreadDataFile(){
  34. Filefile=newFile(filePath);
  35. ArrayList<String[]>dataArray=newArrayList<String[]>();
  36. try{
  37. BufferedReaderin=newBufferedReader(newFileReader(file));
  38. Stringstr;
  39. String[]tempArray;
  40. while((str=in.readLine())!=null){
  41. tempArray=str.split("");
  42. dataArray.add(tempArray);
  43. }
  44. in.close();
  45. }catch(IOExceptione){
  46. e.getStackTrace();
  47. }
  48. pageClass=newArrayList<>();
  49. //统计网页类型种数
  50. for(String[]array:dataArray){
  51. for(Strings:array){
  52. if(!pageClass.contains(s)){
  53. pageClass.add(s);
  54. }
  55. }
  56. }
  57. inti=0;
  58. intj=0;
  59. pageNum=pageClass.size();
  60. linkMatrix=newdouble[pageNum][pageNum];
  61. pageRankVecor=newdouble[pageNum];
  62. for(intk=0;k<pageNum;k++){
  63. //初始每个页面的pageRank值为1
  64. pageRankVecor[k]=1.0;
  65. }
  66. for(String[]array:dataArray){
  67. i=Integer.parseInt(array[0]);
  68. j=Integer.parseInt(array[1]);
  69. //设置linkMatrix[i][j]为1代表i网页包含指向j网页的链接
  70. linkMatrix[i-1][j-1]=1;
  71. }
  72. }
  73. /**
  74. *将矩阵转置
  75. */
  76. privatevoidtransferMatrix(){
  77. intcount=0;
  78. for(double[]array:linkMatrix){
  79. //计算页面链接个数
  80. count=0;
  81. for(doubled:array){
  82. if(d==1){
  83. count++;
  84. }
  85. }
  86. //按概率均分
  87. for(inti=0;i<array.length;i++){
  88. if(array[i]==1){
  89. array[i]/=count;
  90. }
  91. }
  92. }
  93. doublet=0;
  94. //将矩阵转置换,作为概率转移矩阵
  95. for(inti=0;i<linkMatrix.length;i++){
  96. for(intj=i+1;j<linkMatrix[0].length;j++){
  97. t=linkMatrix[i][j];
  98. linkMatrix[i][j]=linkMatrix[j][i];
  99. linkMatrix[j][i]=t;
  100. }
  101. }
  102. }
  103. /**
  104. *利用幂法计算pageRank值
  105. */
  106. publicvoidprintPageRankValue(){
  107. transferMatrix();
  108. //阻尼系数
  109. doubledamp=0.5;
  110. //链接概率矩阵
  111. double[][]A=newdouble[pageNum][pageNum];
  112. double[][]e=newdouble[pageNum][pageNum];
  113. //调用公式A=d*q+(1-d)*e/m,m为网页总个数,d就是damp
  114. doubletemp=(1-damp)/pageNum;
  115. for(inti=0;i<e.length;i++){
  116. for(intj=0;j<e[0].length;j++){
  117. e[i][j]=temp;
  118. }
  119. }
  120. for(inti=0;i<pageNum;i++){
  121. for(intj=0;j<pageNum;j++){
  122. temp=damp*linkMatrix[i][j]+e[i][j];
  123. A[i][j]=temp;
  124. }
  125. }
  126. //误差值,作为判断收敛标准
  127. doubleerrorValue=Integer.MAX_VALUE;
  128. double[]newPRVector=newdouble[pageNum];
  129. //当平均每个PR值误差小于0.001时就算达到收敛
  130. while(errorValue>0.001*pageNum){
  131. System.out.println("**********");
  132. for(inti=0;i<pageNum;i++){
  133. temp=0;
  134. //将A*pageRankVector,利用幂法求解,直到pageRankVector值收敛
  135. for(intj=0;j<pageNum;j++){
  136. //temp就是每个网页到i页面的pageRank值
  137. temp+=A[i][j]*pageRankVecor[j];
  138. }
  139. //最后的temp就是i网页的总PageRank值
  140. newPRVector[i]=temp;
  141. System.out.println(temp);
  142. }
  143. errorValue=0;
  144. for(inti=0;i<pageNum;i++){
  145. errorValue+=Math.abs(pageRankVecor[i]-newPRVector[i]);
  146. //新的向量代替旧的向量
  147. pageRankVecor[i]=newPRVector[i];
  148. }
  149. }
  150. Stringname=null;
  151. temp=0;
  152. System.out.println("--------------------");
  153. for(inti=0;i<pageNum;i++){
  154. System.out.println(MessageFormat.format("网页{0}的pageRank值:{1}",
  155. pageClass.get(i),pageRankVecor[i]));
  156. if(pageRankVecor[i]>temp){
  157. temp=pageRankVecor[i];
  158. name=pageClass.get(i);
  159. }
  160. }
  161. System.out.println(MessageFormat.format("等级最高的网页为:{0}",name));
  162. }
  163. }
下面是HITS算法的实现:

  1. packageDataMining_HITS;
  2. importjava.io.BufferedReader;
  3. importjava.io.File;
  4. importjava.io.FileReader;
  5. importjava.io.IOException;
  6. importjava.util.ArrayList;
  7. /**
  8. *HITS链接分析算法工具类
  9. *@authorlyq
  10. *
  11. */
  12. publicclassHITSTool{
  13. //输入数据文件地址
  14. privateStringfilePath;
  15. //网页个数
  16. privateintpageNum;
  17. //网页Authority权威值
  18. privatedouble[]authority;
  19. //网页hub中心值
  20. privatedouble[]hub;
  21. //链接矩阵关系
  22. privateint[][]linkMatrix;
  23. //网页种类
  24. privateArrayList<String>pageClass;
  25. publicHITSTool(StringfilePath){
  26. this.filePath=filePath;
  27. readDataFile();
  28. }
  29. /**
  30. *从文件中读取数据
  31. */
  32. privatevoidreadDataFile(){
  33. Filefile=newFile(filePath);
  34. ArrayList<String[]>dataArray=newArrayList<String[]>();
  35. try{
  36. BufferedReaderin=newBufferedReader(newFileReader(file));
  37. Stringstr;
  38. String[]tempArray;
  39. while((str=in.readLine())!=null){
  40. tempArray=str.split("");
  41. dataArray.add(tempArray);
  42. }
  43. in.close();
  44. }catch(IOExceptione){
  45. e.getStackTrace();
  46. }
  47. pageClass=newArrayList<>();
  48. //统计网页类型种数
  49. for(String[]array:dataArray){
  50. for(Strings:array){
  51. if(!pageClass.contains(s)){
  52. pageClass.add(s);
  53. }
  54. }
  55. }
  56. inti=0;
  57. intj=0;
  58. pageNum=pageClass.size();
  59. linkMatrix=newint[pageNum][pageNum];
  60. authority=newdouble[pageNum];
  61. hub=newdouble[pageNum];
  62. for(intk=0;k<pageNum;k++){
  63. //初始时默认权威值和中心值都为1
  64. authority[k]=1;
  65. hub[k]=1;
  66. }
  67. for(String[]array:dataArray){
  68. i=Integer.parseInt(array[0]);
  69. j=Integer.parseInt(array[1]);
  70. //设置linkMatrix[i][j]为1代表i网页包含指向j网页的链接
  71. linkMatrix[i-1][j-1]=1;
  72. }
  73. }
  74. /**
  75. *输出结果页面,也就是authority权威值最高的页面
  76. */
  77. publicvoidprintResultPage(){
  78. //最大Hub和Authority值,用于后面的归一化计算
  79. doublemaxHub=0;
  80. doublemaxAuthority=0;
  81. intmaxAuthorityIndex=0;
  82. //误差值,用于收敛判断
  83. doubleerror=Integer.MAX_VALUE;
  84. double[]newHub=newdouble[pageNum];
  85. double[]newAuthority=newdouble[pageNum];
  86. while(error>0.01*pageNum){
  87. for(intk=0;k<pageNum;k++){
  88. newHub[k]=0;
  89. newAuthority[k]=0;
  90. }
  91. //hub和authority值的更新计算
  92. for(inti=0;i<pageNum;i++){
  93. for(intj=0;j<pageNum;j++){
  94. if(linkMatrix[i][j]==1){
  95. newHub[i]+=authority[j];
  96. newAuthority[j]+=hub[i];
  97. }
  98. }
  99. }
  100. maxHub=0;
  101. maxAuthority=0;
  102. for(intk=0;k<pageNum;k++){
  103. if(newHub[k]>maxHub){
  104. maxHub=newHub[k];
  105. }
  106. if(newAuthority[k]>maxAuthority){
  107. maxAuthority=newAuthority[k];
  108. maxAuthorityIndex=k;
  109. }
  110. }
  111. error=0;
  112. //归一化处理
  113. for(intk=0;k<pageNum;k++){
  114. newHub[k]/=maxHub;
  115. newAuthority[k]/=maxAuthority;
  116. error+=Math.abs(newHub[k]-hub[k]);
  117. System.out.println(newAuthority[k]+":"+newHub[k]);
  118. hub[k]=newHub[k];
  119. authority[k]=newAuthority[k];
  120. }
  121. System.out.println("---------");
  122. }
  123. System.out.println("****最终收敛的网页的权威值和中心值****");
  124. for(intk=0;k<pageNum;k++){
  125. System.out.println("网页"+pageClass.get(k)+":"+authority[k]+":"+hub[k]);
  126. }
  127. System.out.println("权威值最高的网页为:网页"+pageClass.get(maxAuthorityIndex));
  128. }
  129. }
2个结果的输出如下:

PageRank算法;

  1. **********
  2. 1.0
  3. 0.7499999999999999
  4. 1.25
  5. **********
  6. 1.125
  7. 0.75
  8. 1.1249999999999998
  9. **********
  10. 1.0624999999999998
  11. 0.78125
  12. 1.15625
  13. **********
  14. 1.078125
  15. 0.7656249999999998
  16. 1.1562499999999998
  17. **********
  18. 1.0781249999999998
  19. 0.7695312499999998
  20. 1.1523437499999998
  21. **********
  22. 1.0761718749999998
  23. 0.7695312499999998
  24. 1.1542968749999996
  25. **********
  26. 1.0771484374999996
  27. 0.7690429687499997
  28. 1.1538085937499996
  29. --------------------
  30. 网页1的pageRank值:1.077
  31. 网页2的pageRank值:0.769
  32. 网页3的pageRank值:1.154
  33. 等级最高的网页为:3
HITS算法:

  1. 0.5:1.0
  2. 0.5:0.5
  3. 1.0:0.5
  4. ---------
  5. 0.3333333333333333:1.0
  6. 0.6666666666666666:0.6666666666666666
  7. 1.0:0.3333333333333333
  8. ---------
  9. 0.2:1.0
  10. 0.6000000000000001:0.6000000000000001
  11. 1.0:0.2
  12. ---------
  13. 0.125:1.0
  14. 0.625:0.625
  15. 1.0:0.125
  16. ---------
  17. 0.07692307692307693:1.0
  18. 0.6153846153846154:0.6153846153846154
  19. 1.0:0.07692307692307693
  20. ---------
  21. 0.04761904761904762:1.0
  22. 0.6190476190476191:0.6190476190476191
  23. 1.0:0.04761904761904762
  24. ---------
  25. 0.029411764705882356:1.0
  26. 0.6176470588235294:0.6176470588235294
  27. 1.0:0.029411764705882356
  28. ---------
  29. ****最终收敛的网页的权威值和中心值****
  30. 网页1:0.029411764705882356:1.0
  31. 网页2:0.6176470588235294:0.6176470588235294
  32. 网页3:1.0:0.029411764705882356
  33. 权威值最高的网页为:网页3
结果都是网页3排名最高。

相关文章: