1. 程式人生 > >基於MapReduce的PageRank演算法實現

基於MapReduce的PageRank演算法實現

  PageRank對網頁排名的演算法,曾是Google發家致富的法寶。以前雖然有實驗過,但理解還是不透徹,這幾天又看了一下,這裡總結一下PageRank演算法的基本原理。

1.什麼是pagerank

  PageRank的Page可是認為是網頁,表示網頁排名,也可以認為是Larry Page(google 產品經理),因為他是這個演算法的發明者之一,還是google CEO(^_^)。PageRank演算法計算每一個網頁的PageRank值,然後根據這個值的大小對網頁的重要性進行排序。它的思想是模擬一個悠閒的上網者,上網者首先隨機選擇一個網頁開啟,然後在這個網頁上呆了幾分鐘後,跳轉到該網頁所指向的連結,這樣無所事事、漫無目的地在網頁上跳來跳去,PageRank就是估計這個悠閒的上網者分佈在各個網頁上的概率。

2.最簡單pagerank模型

  網際網路中的網頁可以看出是一個有向圖,其中網頁是結點,如果網頁A有連結到網頁B,則存在一條有向邊A->B,下面是一個簡單的示例:

  這個例子中只有四個網頁,如果當前在A網頁,那麼悠閒的上網者將會各以1/3的概率跳轉到B、C、D,這裡的3表示A有3條出鏈,如果一個網頁有k條出鏈,那麼跳轉任意一個出鏈上的概率是1/k,同理D到B、C的概率各為1/2,而B到C的概率為0。一般用轉移矩陣表示上網者的跳轉概率,如果用n表示網頁的數目,則轉移矩陣M是一個n*n的方陣;如果網頁j有k個出鏈,那麼對每一個出鏈指向的網頁i,有M[i][j]=1/k,而其他網頁的M[i][j]=0;上面示例圖對應的轉移矩陣如下:

  初試時,假設上網者在每一個網頁的概率都是相等的,即1/n,於是初試的概率分佈就是一個所有值都為1/n的n維列向量V0,用V0去右乘轉移矩陣M,就得到了第一步之後上網者的概率分佈向量MV0,(nXn)*(nX1)依然得到一個nX1的矩陣。下面是V1的計算過程:

  注意矩陣M中M[i][j]不為0表示用一個連結從j指向i,M的第一行乘以V0,表示累加所有網頁到網頁A的概率即得到9/24。得到了V1後,再用V1去右乘M得到V2,一直下去,最終V會收斂,即Vn=MV(n-1),上面的圖示例,不斷的迭代,最終V=[3/9,2/9,2/9,2/9]’:

3.終止點問題

  上述上網者的行為是一個馬爾科夫過程的例項,要滿足收斂性,需要具備一個條件:

  圖是強連通的,即從任意網頁可以到達其他任意網頁

  網際網路上的網頁不滿足強連通的特性,因為有一些網頁不指向任何網頁,如果按照上面的計算,上網者到達這樣的網頁後便走投無路、四顧茫然,導致前面累計得到的轉移概率被清零,這樣下去,最終的得到的概率分佈向量所有元素幾乎都為0。假設我們把上面圖中C到A的連結丟掉,C變成了一個終止點,得到下面這個圖:

  對應的轉移矩陣為:

  連續迭代下去,最終所有元素都為0: 

4.陷阱問題

  另外一個問題就是陷阱問題,即有些網頁不存在指向其他網頁的連結,但存在指向自己的連結。比如下面這個圖:

  上網者跑到C網頁後,就像跳進了陷阱,陷入了漩渦,再也不能從C中出來,將最終導致概率分佈值全部轉移到C上來,這使得其他網頁的概率分佈值為0,從而整個網頁排名就失去了意義。如果按照上面圖對應的轉移矩陣為: 

  不斷的迭代下去,就變成了這樣:

5.解決終止點問題和陷阱問題

  上面過程,我們忽略了一個問題,那就是上網者是一個悠閒的上網者,而不是一個愚蠢的上網者,我們的上網者是聰明而悠閒,他悠閒,漫無目的,總是隨機的選擇網頁,他聰明,在走到一個終結網頁或者一個陷阱網頁(比如兩個示例中的C),不會傻傻的乾著急,他會在瀏覽器的地址隨機輸入一個地址,當然這個地址可能又是原來的網頁,但這裡給了他一個逃離的機會,讓他離開這萬丈深淵。模擬聰明而又悠閒的上網者,對演算法進行改進,每一步,上網者可能都不想看當前網頁了,不看當前網頁也就不會點選上面的連線,而上悄悄地在位址列輸入另外一個地址,而在位址列輸入而跳轉到各個網頁的概率是1/n。假設上網者每一步檢視當前網頁的概率為a,那麼他從瀏覽器位址列跳轉的概率為(1-a),於是原來的迭代公式轉化為:

  現在我們來計算帶陷阱的網頁圖的概率分佈:

  重複迭代下去,得到:

  可以看到C雖然佔了很大一部分pagerank值,但其他網頁頁獲得的一些值,因此C的連結結構,它的權重確實應該會大些。

6.用Map-reduce計算Page Rank

  上面的演算過程,採用矩陣相乘,不斷迭代,直到迭代前後概率分佈向量的值變化不大,一般迭代到30次以上就收斂了。真的的web結構的轉移矩陣非常大,目前的網頁數量已經超過100億,轉移矩陣是100億*100億的矩陣,直接按矩陣乘法的計算方法不可行,需要藉助Map-Reduce的計算方式來解決。實際上,google發明Map-Reduce最初就是為了分散式計算大規模網頁的pagerank,Map-Reduce的pagerank有很多實現方式,我這裡計算一種簡單的。

  考慮轉移矩陣是一個很多的稀疏矩陣,我們可以用稀疏矩陣的形式表示,我們把web圖中的每一個網頁及其鏈出的網頁作為一行,這樣第四節中的web圖結構用如下方式表示:

1 A    B    C    D
2 B    A    D
3 C    C
4 D    B    C

  A有三條出鏈,分別指向B、C、D,實際上,我們爬取的網頁結構資料就是這樣的。

  1、Map階段

  Map操作的每一行,對所有出鏈發射當前網頁概率值的1/k,k是當前網頁的出鏈數,比如對第一行輸出:

<B,1/3*1/4>,<C,1/3*1/4>,<D,1/3*1/4>

  2、Reduce階段

  Reduce操作收集網頁id相同的值,累加並按權重計算,pj=a*(p1+p2+…Pm)+(1-a)*1/n,其中m是指向網頁j的網頁j數,n所有網頁數。

  思路就是這麼簡單,但是實踐的時候,怎樣在Map階段知道當前行網頁的概率值,需要一個單獨的檔案專門儲存上一輪的概率分佈值,先進行一次排序,讓出鏈行與概率值按網頁id出現在同一Mapper裡面,整個流程如下:
  
原文中第二次map輸出的結果表有點問題(部門缺失),讀者可以自行計算,最終的結果是沒有問題的。

  這樣進行一次迭代相當於需要兩次MapReduce,但第一次的MapReduce只是簡單的排序,不需要任何操作,用python呼叫Hadoop的Streaming.

  SortMappert.py程式碼如下:

1 #!/bin/python
2 '''Mapper for sort'''
3 import sys
4 for line in sys.stdin:
5      print line.strip()

  SortReducer.py也是一樣

1 #!/bin/python
2 '''Reducer for sort'''
3 import sys
4 for line in sys.stdin:
5       print line.strip()

  PageRankMapper.py程式碼:

 1 ''' mapper of pangerank algorithm'''
 2 import sys
 3 id1 = id2 = None
 4 heros = value = None
 5 count1 = count2 = 0
 6 
 7 for line in sys.stdin:
 8     data = line.strip().split('\t')
 9     if len(data) == 3 and data[1] == 'a':# This is the pangerank value
10         count1 += 1
11         if count1 >= 2:
12             print '%s\t%s' % (id1,0.0)
13             
14         id1 = data[0]
15         value = float(data[2]) 
16     else:#This the link relation
17         id2 = data[0]
18         heros = data[1:]
19     if id1 == id2 and id1:
20         v = value / len(heros)
21         for hero in heros:
22             print '%s\t%s' % (hero,v)
23         print '%s\t%s' % (id1,0.0)
24         id1 = id2 = None
25         count1 = 0

  PageRankReducer.py程式碼:

 1 ''' reducer of pagerank algorithm'''
 2 import sys
 3 last = None
 4 values = 0.0
 5 alpha = 0.8
 6 N = 4# Size of the web pages
 7 for line in sys.stdin:
 8     data = line.strip().split('\t')
 9     hero,value = data[0],float(data[1])
10     if data[0] != last:
11         if last:
12             values = alpha * values + (1 - alpha) / N
13             print '%s\ta\t%s' % (last,values)
14         last = data[0]
15         values = value
16     else:
17         values += value #accumulate the page rank value
18 if last:
19     values = alpha * values + (1 - alpha) / N
20     print '%s\ta\t%s' % (last,values)

  在linux下模仿Map-Reduce的過程(多輪迭代):

 1 #!/bin/bash
 2 PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
 3 export PATH
 4 max=10
 5 for i in `seq 1 $max`
 6 do
 7     echo "$i"
 8     cat links.txt pangerank.value > tmp.txt 
 9     cat tmp.txt |sort|python PageRankMapper.py |sort|python PageRankReducer.py >pangerank.value
10 done

  這個程式碼不用改動就可以直接在hadoop上跑起來。呼叫hadoop命令:

 1 #!/bin/bash
 2 
 3 #sort
 4 mapper=SortMapper.py
 5 reducer=SortReducer.py
 6 input="yours HDFS dir"/links.txt
 7 input="yours HDFS dir"/pagerank.value
 8 output="yours HDFS dir"/tmp.txt
 9 
10 hadoop jar contrib/streaming/hadoop-*streaming*.jar \
11     -mapper /home/hduser/mapper.py \
12     -reducer /home/hduser/reducer.py -file *.py\
13     -input $input \
14     -output $output
15     
16     
17 #Caculator PageRank
18 mapper=PageRankMapper.py
19 reducer=PageRankReducer.py
20 input="yours HDFS dir"/tmp.txt
21 output="yours HDFS dir"/pagerank.value
22 
23 hadoop jar contrib/streaming/hadoop-*streaming*.jar \
24     -mapper /home/hduser/mapper.py \
25     -reducer /home/hduser/reducer.py -file *.py\
26     -input $input \
27     -output $output

  關於使用python操作hadoop可以檢視參考文獻。python程式碼寫得濃濃的C味,望海涵!

  第四步中帶環的陷阱圖,迭代40次,權值a取0.8,計算結果如下:
 

 1 A            B                C                D
 2 0.15    0.216666666667    0.416666666667    0.216666666667    
 3 0.136666666666    0.176666666666    0.51    0.176666666666    
 4 0.120666666666    0.157111111111    0.565111111111    0.157111111111    
 5 0.112844444444    0.145022222222    0.597111111111    0.145022222222    
 6 0.108008888889    0.138100740741    0.615789629629    0.138100740741    
 7 0.105240296296    0.134042666667    0.62667437037    0.134042666667    
 8 0.103617066667    0.131681145679    0.633020641975    0.131681145679    
 9 0.102672458272    0.130303676049    0.636720189629    0.130303676049    
10 0.10212147042    0.129500792625    0.638876944329    0.129500792625    
11 0.10180031705    0.129032709162    0.640134264625    0.129032709162    
12 0.101613083665    0.128759834878    0.640867246578    0.128759834878    
13 0.101503933951    0.128600756262    0.641294553524    0.128600756262    
14 0.101440302505    0.128508018225    0.641543661044    0.128508018225    
15 0.10140320729    0.128453954625    0.64168888346    0.128453954625    
16 0.10138158185    0.128422437127    0.641773543895    0.128422437127    
17 0.101368974851    0.128404063344    0.64182289846    0.128404063344    
18 0.101361625338    0.128393351965    0.641851670733    0.128393351965    
19 0.101357340786    0.128387107543    0.641868444129    0.128387107543    
20 0.101354843017    0.128383467227    0.64187822253    0.128383467227    
21 0.101353386891    0.128381345029    0.641883923053    0.128381345029    
22 0.101352538012    0.128380107849    0.641887246292    0.128380107849    
23 0.10135204314    0.128379386609    0.641889183643    0.128379386609    
24 0.101351754644    0.128378966148    0.641890313062    0.128378966148    
25 0.101351586459    0.128378721031    0.641890971481    0.128378721031    
26 0.101351488412    0.128378578135    0.64189135532    0.128378578135    
27 0.101351431254    0.128378494831    0.641891579087    0.128378494831    
28 0.101351397932    0.128378446267    0.641891709536    0.128378446267    
29 0.101351378507    0.128378417955    0.641891785584    0.128378417955    
30 0.101351367182    0.128378401451    0.641891829918    0.128378401451    
31 0.10135136058    0.128378391829    0.641891855763    0.128378391829    
32 0.101351356732    0.12837838622    0.64189187083    0.12837838622    
33 0.101351354488    0.12837838295    0.641891879614    0.12837838295    
34 0.10135135318    0.128378381043    0.641891884735    0.128378381043    
35 0.101351352417    0.128378379932    0.64189188772    0.128378379932    
36 0.101351351973    0.128378379284    0.64189188946    0.128378379284    
37 0.101351351714    0.128378378906    0.641891890474    0.128378378906    
38 0.101351351562    0.128378378686    0.641891891065    0.128378378686    
39 0.101351351474    0.128378378558    0.64189189141    0.128378378558    
40 0.101351351423    0.128378378483    0.641891891611    0.128378378483    
41 0.101351351393    0.128378378439    0.641891891728    0.128378378439 

  可以看到pagerank值已經基本趨於穩定,並與第四步的分數表示一致。

參考文獻
1.《Mining of Massive Datasets》
2.《An introduction to information retrival》
3.使用python操作Hadoop

相關推薦

Python基於Kmeans演算法實現文字聚類的簡單練習

接觸機器學習時間不長,也一直有興趣研究這方面的演算法。最近在學習Kmeans演算法,但由於工作的原因無法接觸到相關的專案實戰。為了理清思路、熟悉程式碼,在參照了幾篇機器學習大神的博文後,做了一個簡單的Kmeans演算法的簡單練習。作為一枚機器學習的門外漢,對於文中的一些錯誤和

基於KNN演算法實現的單個圖片數字識別

Test.csv中第1434行,圖片數字值為”0“,最終歸類為0,正確。 Test.csv中第14686行,圖片數字值為”8“,最終歸類為8,正確。 4原始碼 最後附上本次基於KNN思想實現單個數字圖片識別的全部原始碼。 /** * @Title: DigitClassification.java

R語言基於KNN演算法實現蘑菇毒性識別

R語言:基於KNN演算法實現蘑菇毒性識別 平臺:Ubuntu16.04LTS   RStudio 資料集介紹: trainData.txt  訓練資料集。包含4339個樣本(行),每個樣本共6個特徵(列),其中前5列為蘑菇樣本的特徵值,第6列為蘑菇的毒性屬性,0表示無毒,1

基於snowflake演算法實現發號器

(2)snowflake的結構如下(每部分用-分開): 0 - 0000000000 0000000000 0000000000 0000000000 000 - 000 - 00000 - 000000000000 一共加起來剛好64位,為一個Long型。(轉換成字串長度為18) snowflak

Hadoop偽分佈安裝詳解+MapReduce執行原理+基於MapReduce的KNN演算法實現

本篇部落格將圍繞Hadoop偽分佈安裝+MapReduce執行原理+基於MapReduce的KNN演算法實現這三個方面進行敘述。 (一)Hadoop偽分佈安裝 1、簡述Hadoop的安裝模式中–偽分佈模式與叢集模式的區別與聯絡. Hadoop的安裝方式有三種:本地模式,偽分佈模式

基於使用者的協同過濾演算法實現的商品推薦系統

基於使用者的協同過濾演算法實現的商品推薦系統   專案介紹 商品推薦是針對使用者面對海量的商品資訊而不知從何下手的一種解決方案,它可以根據使用者的喜好,年齡,點選量,購買量以及各種購買行為來為使用者推薦合適的商品。在本專案中採用的是基於使用者的協同過濾的推薦演算法來實現

DL之RNN:人工智慧為你寫歌詞(林夕寫給陳奕迅)——基於TF利用RNN演算法實現【機器為你作詞】、訓練&測試過程全記錄

DL之RNN:人工智慧為你寫歌詞(林夕寫給陳奕迅)——基於TF利用RNN演算法實現【機器為你作詞】、訓練&測試過程全記錄 輸出結果 1、test01 你的揹包 一個人過我 誰不屬了 不甘心 不能回頭 我的揹包載管這個 誰讓我們是要不可 但求跟你過一生 你把我灌醉 即使嘴角

DL之RNN:人工智慧為你寫周董歌詞——基於TF利用RNN演算法實現【機器為你作詞】、訓練&測試過程全記錄

DL之RNN:人工智慧為你寫周董歌詞——基於TF利用RNN演算法實現~機器為你作詞~、訓練&測試過程全記錄 輸出結果 1、test01 夕海 而我在等待之光 在月前被畫面 而我心碎 你的個世紀 你的時間 我在趕過去 我的不是你不會感覺媽媽 我說不要不要說 我會愛你 我不要你不

【機器學習演算法實現】主成分分析 PCA ——基於python+numpy

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

基於System Generator的CORDIC演算法實現

基於System Generator的CORDIC演算法實現 文章目錄 基於System Generator的CORDIC演算法實現 一、CORDIC演算法實現 1、簡介 2、CORDIC演算法模式 2、搭建CORDIC模組系統

【機器學習演算法實現】logistic迴歸 基於Python和Numpy函式庫

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

【機器學習演算法實現】kNN演算法 手寫識別——基於Python和NumPy函式庫

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

Python基於K-均值、RLS演算法實現RBF神經網路(神經網路與機器學習 第五章 計算機實驗)

1、生成資料集 class moon_data_class(object): def __init__(self,N,d,r,w): self.N=N self.w=w self.d=d self.r=r

基於sciket-learn實現線性迴歸演算法

線性迴歸演算法主要用來解決迴歸問題,是許多強大的非線性模型的基礎,無論是簡單線性迴歸,還是多元線性迴歸,思想都是一樣的,假設我們找到了最佳擬合方程(對於簡單線性迴歸,多元線性迴歸對應多個特徵作為一組向量)y=ax+b,則對於每一個樣本點xi,根據我們的直線方程,預測值為y^i = axi + b,真

基於scikit-learn實現k近鄰演算法(kNN)與超引數的除錯

前一篇關於kNN的部落格介紹了演算法的底層實現,這片部落格讓我們一起看一看基於scikit-learn如何快速的實現kNN演算法。 scikit-learn內建了很多資料集,就不用我們自己編造假資料了,下面我們分別選用鳶尾花和手寫數字識別的資料集。 首先匯入需要的庫 from sklea

TF之NN:基於TF利用NN演算法實現根據三個自變數預測一個因變數的迴歸問題

TF之NN:基於TF利用NN演算法實現根據三個自變數預測一個因變數的迴歸問題   實驗資料 說明:利用前四年的資料建立迴歸模型,並對第五年進行預測。   輸出結果 loss is: 913.6623 loss is: 781206160000.0

[文件和原始碼分享]C++實現基於α-β剪枝演算法的井字棋遊戲

“井字棋”遊戲(又叫“三子棋”),是一款十分經典的益智小遊戲,操作簡單,娛樂性強。兩個玩家,一個打圈(O),一個打叉(X),輪流在3乘3的格上打自己的符號,最先以橫、直、斜連成一線則為勝。 如果雙方都下得正確無誤,將得和局。這種遊戲實際上是由第一位玩家所控制,第一位玩家是攻,第二位玩家是守。 這種遊戲的變

常見排序演算法記錄(基於java語言實現)

桶排序 public class TongPaiXu1 { public static void main(String[] args) { // 桶排序 int[] m = {1, 3, 6, 3, 4,

非對稱加密過程詳解(基於RSA非對稱加密演算法實現

1、非對稱加密過程:         假如現實世界中存在A和B進行通訊,為了實現在非安全的通訊通道上實現資訊的保密性、完整性、可用性(即資訊保安的三個性質),A和B約定使用非對稱加密通道進行通訊,具體過程如下:   說明:         國內目前使用雙證書體系,即

基於LVD、貝葉斯模型演算法實現的電商行業商品評論與情感分析案例

一、 專案需求 現在大家進行網購,在購物之前呢,肯定會看下相關商品的評論,看下好評和差評,然後再綜合衡量,最後才會決定是否購買相關的商品。對一個指定商品,生產商,賣家,買家認同該商品的哪些優點/不認同