公號:碼農充電站pro
主頁:https://codeshellme.github.io
在網際網路早期,隨著網路上的網頁逐漸增多,如何從海量網頁中檢索出我們想要的頁面,變得非常的重要。
當時著名的雅虎和其它網際網路公司都試圖解決這個問題,但都沒能有一個很好的解決方案。
直到1998 年前後,兩位史丹佛大學的博士生,拉里·佩奇和謝爾蓋·布林一起發明了著名的 PageRank 演算法,才完美的解決了網頁排名的問題。也正是因為這個演算法,誕生了偉大的 Google 公司。
(上圖中:左為布林,右為佩奇。)
1,PageRank 演算法原理
PageRank 演算法的核心原理是:在網際網路中,如果一個網頁被很多其它網頁所連結,說明該網頁非常的重要,那麼它的排名就高。
拉里·佩奇將整個網際網路看成一張大的圖,每個網站就像一個節點,而每個網頁的連結就像一個弧。那麼,網際網路就可以用一個圖或者矩陣來描述。
拉里·佩奇也因該演算法在30 歲時當選為美國工程院院士。
假設目前有4 個網頁,分別是 A,B,C,D,它們的連結關係如下:
我們規定有兩種鏈:
- 出鏈:從自身引出去的鏈。
- 入鏈:從外部引入自身的鏈。
比如圖中的C 網頁,有兩個入鏈,一個出鏈。
PageRank 的思想就是,一個網頁的影響力就等於它的所有入鏈的影響力之和。
用數學公式表示為:
其中(分值代表頁面影響力):
PR(u)
是網頁u
的分值。Bu
是網頁u
的入鏈集合。- 網頁
v
是網頁u
的任意一個入鏈。 PR(v)
是網面v
的分值。L(v)
是網頁v
的出鏈數量。- 網頁
v
帶給網頁u
的分值就是PR(v) / L(v)
。 - 那麼
PR(u)
就等於所有的入鏈分值之和。
在上面的公式中,我們假設從一個頁面v 到達它的所有的出鏈頁面的概率是相等的。
比如上圖來說,頁面A 有三個出鏈分別連結到了 B、C、D 上。那麼當使用者訪問 A 的時候,就有跳轉到 B、C 或者 D 的可能性,跳轉概率均為 1/3。
2,計算網頁的分值
下面來看下如何計算網頁的分值。
我們可以用一個表格,來表示上圖中的網頁的連結關係,及每個頁面到其它頁面的概率:
A | B | C | D | |
---|---|---|---|---|
A | 0 A->A |
1/2 B->A |
1 C->A |
0 D->A |
B | 1/3 A->B |
0 B->B |
0 C->B |
1/2 D->B |
C | 1/3 A->C |
0 B->C |
0 C->C |
1/2 D->C |
D | 1/3 A->D |
1/2 B->D |
0 C->D |
0 D->D |
根據這個表格中的數字,可以將其轉換成一個矩陣M:
假設 A、B、C、D 四個頁面的初始影響力都是相同的,都為 1/4,即:
經過第一次分值轉移之後,可以得到 W1,如下:
同理可以得到W2,W3 一直到 Wn:
- W2 = M * W1
- W3 = M * W2
- Wn = M * Wn-1
那麼什麼時候計算終止呢?
佩奇和布林已經證明,不管網頁的初識值選擇多少(我們這假設都是1/4),最終都能保證網頁的分值能夠收斂到一個真實確定值。
也就是直到 Wn 不再變化為止。
這就是網頁分值的計算過程,還是比較好理解的。
3,PageRank 的兩個問題
我們上文中介紹到的是PageRank 的基本原理,是簡化版本。在實際應用中會出現等級洩露(RankLeak)和等級沉沒(Rank Sink)的問題。
如果一個網頁沒有出鏈,就會吸收其它網頁的分值不釋放,最終會導致其它網頁的分值為0,這種現象叫做等級洩露。如下圖中的網頁C:
相反,如果一個網頁沒有入鏈,最終會導致該網頁的分值為0,這種現象叫做等級沉沒。如下圖中的網頁C:
4,PageRank 的隨機瀏覽模型
為了解決上面的問題,拉里·佩奇提出了隨機瀏覽模型,即使用者並不都是依靠網頁連結來訪問網頁,也有可能用其它方式訪問網址,比如輸入網址。
因此,提出了阻尼因子的概念,這個因子代表使用者按照跳轉連結來上網的概率,而 1-d 則代表使用者通過其它方式訪問網頁的概率。
所以,將上文中的公式改進為:
其中:
- d 為阻尼因子,通常可以取0.85。
- N 為網頁總數。
5,用程式碼計算網頁分值
如何用程式碼來計算網頁的PR 分值呢?(為了方便檢視,我把上圖放在這裡)
我們可以看到,該圖實際上就是資料結構中的有向圖,因此我們可以通過構建有向圖來構建 PageRank 演算法。
NetworkX 是一個Python 工具包,其中整合了常用的圖結構和網路分析演算法。
我們可以用 NetworkX 來構建上圖中的網路結構。
首先引入模組:
import networkx as nx
用 DiGraph 類建立有向圖:
G = nx.DiGraph()
將4 個網頁的連結關係,用陣列表示:
edges = [
("A", "B"), ("A", "C"), ("A", "D"),
("B", "A"), ("B", "D"),
("C", "A"),
("D", "B"), ("D", "C")
]
陣列中的元素作為有向圖的邊,並新增到圖中:
for edge in edges:
G.add_edge(edge[0], edge[1])
使用pagerank
方法計算PR 分值:
# alpha 為阻尼因子
PRs = nx.pagerank(G, alpha=1)
print PRs
輸出每個網頁的PR 值:
{'A': 0.33333396911621094,
'B': 0.22222201029459634,
'C': 0.22222201029459634,
'D': 0.22222201029459634}
最終,我們計算出了每個網頁的PR 值。
6,畫出網路圖
NetworkX 包中還提供了畫出網路圖的方法:
import matplotlib.pyplot as plt
# 畫網路圖
nx.draw_networkx(G)
plt.show()
如下:
我們還可以設定圖的形狀,節點的大小,邊的長度等屬性,具體可以點選這裡檢視。
更多關於 NetworkX 的內容可以參考其官方文件。
7,總結
PageRank 演算法給了我們一個很重要的啟發,權重在很多時候是一個非常重要的指標。
- 比如在人際交往中,個人的影響力不僅取決於你的朋友的數量,而且朋友的質量非常重要,說明了圈子的重要性。
- 比如在自媒體時代,粉絲數並不能真正的代表你的影響力,粉絲的質量也很重要。如果你的粉絲中有很多大V,那麼將大大增加你影響力。
本篇文章主要介紹了:
- PageRank 演算法的原理。
- 簡化版的PageRank 演算法遇到的問題,以及解決方案:
- 等級洩露和等級沉沒。
- 引出隨機瀏覽模型來解決這兩個問題。
- 如何用程式碼模擬PageRank 演算法:
- 使用了 NetworkX 模組。
(本節完。)
推薦閱讀:
歡迎關注作者公眾號,獲取更多技術乾貨。