【白话机器学习】算法理论+实战之PageRank算法
1. 寫在前面
如果想從事數據挖掘或者機器學習的工作,掌握常用的機器學習算法是非常有必要的,常見的機器學習算法:
監督學習算法:邏輯回歸,線性回歸,決策樹,樸素貝葉斯,K近鄰,支持向量機,集成算法Adaboost等
無監督算法:聚類,降維,關聯規則, PageRank等
已發布:
【白話機器學習】算法理論+實戰之K近鄰算法
【白話機器學習】算法理論+實戰之決策樹
【白話機器學習】算法理論+實戰之樸素貝葉斯
【白話機器學習】算法理論+實戰之支持向量機(SVM)
【白話機器學習】算法理論+實戰之AdaBoost算法
【白話機器學習】算法理論+實戰之K-Means聚類算法
【白話機器學習】算法理論+實戰之PCA降維
【白話機器學習】算法理論+實戰之EM聚類
【白話機器學習】算法理論+實戰之關聯規則
為了詳細的理解這些原理,曾經看過西瓜書,統計學習方法,機器學習實戰等書,也聽過一些機器學習的課程,但總感覺話語里比較深奧,讀起來沒有耐心,并且理論到處有,而實戰最重要, 所以在這里想用最淺顯易懂的語言寫一個白話機器學習算法理論+實戰系列。
個人認為,理解算法背后的idea和使用,要比看懂它的數學推導更加重要。idea會讓你有一個直觀的感受,從而明白算法的合理性,數學推導只是將這種合理性用更加嚴謹的語言表達出來而已,打個比方,一個梨很甜,用數學的語言可以表述為糖分含量90%,但只有親自咬一口,你才能真正感覺到這個梨有多甜,也才能真正理解數學上的90%的糖分究竟是怎么樣的。如果算法是個梨,本文的首要目的就是先帶領大家咬一口。另外還有下面幾個目的:
檢驗自己對算法的理解程度,對算法理論做一個小總結
能開心的學習這些算法的核心思想, 找到學習這些算法的興趣,為深入的學習這些算法打一個基礎。
每一節課的理論都會放一個實戰案例,能夠真正的做到學以致用,既可以鍛煉編程能力,又可以加深算法理論的把握程度。
也想把之前所有的筆記和參考放在一塊,方便以后查看時的方便。
學習算法的過程,獲得的不應該只有算法理論,還應該有樂趣和解決實際問題的能力!
今天是白話機器學習算法理論+實戰的第三篇,PageRank算法,通過今天的學習,快速Get到PageRank的原理,并最后運用PageRank算法實現一個項目:分析希拉里郵件里面的人物關系,在這能看到誰和希拉里交往最為活躍。
大綱如下:
PageRank的簡化模型和計算原理
PageRank的隨機瀏覽模型(解決等級沉沒和等級泄露)
PageRank給我們帶來的啟發很重要 (人脈杠桿)
PageRank實戰 (分析希拉里郵件里面的人物關系,看看誰和希拉里交往最活躍)
Ok, let's go !
2. PageRank?還是從日常生活談起吧
提到PageRank,好多人可能一上來一臉懵逼,不知道這是個什么東西,但是提到一個詞?想必大家一定不陌生,那就是從眾心理。大家一般都有從眾心理,不信的話可以看看下面的場景:
★比如,當你某一家飯店,或者理發店,或者小吃店里面的顧客非常多,每天爆滿的時候,心理一定會想,這家店想必不錯,要不然不可能這么多人,我也進去試試。?或者,在淘寶上買某個商品的時候,肯定是喜歡挑人多的店鋪,好評量高的店鋪買的放心等等吧。?所以當我們在生活中遇到艱難選擇的時候,往往喜歡看看別人是怎么做的,一般都會選大部分人的選擇。這其實就是一種從眾。
”這些店鋪也好,選擇也罷,其實都是通過很多人的投票進而提高了自己的影響力,再比如說,微博上如何去衡量一個人的影響力呢??我們習慣看他的粉絲,如果他的粉絲多,并且里面都是一些大V,明星的話,很可能這個人的影響力會比較強。?再比如說,職場上如何衡量一個人的影響力呢?我們習慣看與他交往的人物, 如果和他交往的都是像馬云,王健林,馬化騰這樣的人物,那么這個人的影響力估計也小不了。再比如說,如何判斷一篇論文好?我們習慣看他的引用次數,或者影響因子,高的論文就比較好等等。
但是你只知道嗎?其實我們的這種方式就在用PageRank算法的思想了,只不過我們沒有發覺罷了,所謂的算法來源于生活,并服務于生活就是這個道理。
好了,通過上面的案例,相信已經對PageRank這個詞有點感覺了吧。那么趁熱打鐵,說說它的來源吧。
3. PageRank是怎么來的?
想必大家上網的時候,都用過搜索引擎,現在已經非常好用了,基本上輸入關鍵詞,都能找到匹配的內容,質量還不錯。但在 1998 年之前,搜索引擎的體驗并不好。早期的搜索引擎,會遇到下面的兩類問題:
返回結果質量不高:搜索結果不考慮網頁的質量,而是通過時間順序進行檢索;
容易被人鉆空子:搜索引擎是基于檢索詞進行檢索的,頁面中檢索詞出現的頻次越高,匹配度越高,這樣就會出現網頁作弊的情況。有些網頁為了增加搜索引擎的排名,故意增加某個檢索詞的頻率。
基于這些缺陷,當時 Google 的創始人拉里·佩奇提出了 PageRank 算法,目的就是要找到優質的網頁,這樣 Google 的排序結果不僅能找到用戶想要的內容,而且還會從眾多網頁中篩選出權重高的呈現給用戶。其靈感就是論文影響力因子的啟發。
4. PageRank的簡化模型
假設一共有 4 個網頁 A、B、C、D。它們之間的鏈接信息如圖所示:首先先知道兩個概念:
★出鏈指的是鏈接出去的鏈接。入鏈指的是鏈接進來的鏈接。比如圖中 A 有 2 個入鏈,3 個出鏈。
”那么我們如何計算一個網頁的影響力或者重要程度呢?
★簡單來說,一個網頁的影響力 = 所有入鏈集合的頁面的加權影響力之和,用公式表示為:u 為待評估的頁面,Bu 為頁面 u 的入鏈集合。針對入鏈集合中的任意頁面 v,它能給 u 帶來的影響力是其自身的影響力 PR(v) 除以 v 頁面的出鏈數量,即頁面 v 把影響力 PR(v) 平均分配給了它的出鏈,這樣統計所有能給 u 帶來鏈接的頁面 v,得到的總和就是網頁 u 的影響力,即為 PR(u)。
”What? 這是在說什么??只需要先明白兩點:
如果一個頁面,入鏈比較多,也就是跳轉過去的概率比較大的時候,這個頁面往往就比較重要,影響力高一些(這就類似于購買商品的人越多,這個商品就貌似越好一樣)
如果某個頁面本身的影響力很大,那么也會相應的增加它出鏈指向的頁面影響力。(這個就類似于你的朋友都是大牛的話,你在別人心目中的印象也會提升)
所以你能看到,出鏈會給被鏈接的頁面賦予影響力,當我們統計了一個網頁鏈出去的數量,也就是統計了這個網頁的跳轉概率。
★在這個例子中,你能看到 A 有三個出鏈分別鏈接到了 B、C、D 上。那么當用戶訪問 A 的時候,就有跳轉到 B、C 或者 D 的可能性,跳轉概率均為 1/3。
B 有兩個出鏈,鏈接到了 A 和 D 上,跳轉概率為 1/2。
這樣,我們可以得到 A、B、C、D 這四個網頁的轉移矩陣 M:這個轉移矩陣,每一行代表了每個節點入鏈上的權重(大家瀏覽別的頁面的時候,有多大的概率能跳到我這來)。每一列代表了每個節點對其他頁面的影響力的賦予程度(也就是大家瀏覽我這,有多大的概率跳到別的頁面上去)。
有了這個轉移矩陣,我們就可以計算每個頁面的影響力是多少了。
★比如上圖A頁面的影響力怎么計算呢?其實我們是通過他的入鏈點B、C的影響力去計算的,也就是我們的那個公式。開始我們假設四個頁面的影響力相同,都是1/4。則A第一次的影響力這么想,B有兩條出鏈,那么會給我傳過它影響力的1/2。C有一條出鏈,那么會把它的影響力全傳給A。
故:PR(A) = 1/4 * 1/2 + 1/4
這是一次迭代。你發現了嗎?這其實就是轉移矩陣M的第一行 * 一個全為1/4的列向量得到的(向量乘法)
所以如果我們利用向量的乘法原理的話,只需要一個向量乘法就可以計算出每個頁面的影響力了。
我們假設 A、B、C、D 四個頁面的初始影響力都是相同的,即:當進行第一次轉移之后,各頁面的影響力 w1 變為:然后我們再用轉移矩陣乘以 w1 得到 w2 結果,直到第 n 次迭代后 wn 影響力不再發生變化,可以收斂到 (0.3333,0.2222,0.2222,0.2222),也就是對應著 A、B、C、D 四個頁面最終平衡狀態下的影響力。
你能看出 A 頁面相比于其他頁面來說權重更大,也就是 PR 值更高。而 B、C、D 頁面的 PR 值相等。
至此,我們模擬了一個簡化的 PageRank 的計算過程,也就是PageRank簡化模型的原理了。
是不是計算起來很簡單啊?那就再回去看看那個公式理解了沒?
但是你發現了嗎?雖然這個模型簡單,但是有問題的,比如萬一我有一個網頁只有入鏈沒有出鏈怎么辦??萬一我有一個網頁只有出鏈,沒有入鏈怎么辦?
上面的兩個問題分別對應著等級泄露和等級沉沒。
等級泄露(Rank Leak):如果一個網頁沒有出鏈,就像是一個黑洞一樣,吸收了其他網頁的影響力而不釋放,最終會導致其他網頁的 PR 值為 0。
等級沉沒(Rank Sink):如果一個網頁只有出鏈,沒有入鏈(如下圖所示),計算的過程迭代下來,會導致這個網頁的 PR 值為 0(也就是不存在公式中的 V)。
這其實就和練功一樣,如果其他所有人把功力傳給一個人,而這個人只接收別人的功力并不傳給其他人,那么這個人必定非常強大,其他人慢慢的就會功力喪失, 武俠小說里面的高手很多是這么煉成的吧(吸星大法這樣的)。
如果一個人只往外傳功力,不接收外來人的功力,比如給人療傷的時候,那么這個人很快也就會功力喪失了。(武俠小說中療傷的時候,某個大俠給人療著療著自己就昏過去了)
上面的兩個例子可以很好的理解這兩個問題。
那么如何有效解決呢?
5. PageRank 的隨機瀏覽模型
為了解決簡化模型中存在的等級泄露和等級沉沒的問題,拉里·佩奇提出了 PageRank 的隨機瀏覽模型。他假設了這樣一個場景:用戶并不都是按照跳轉鏈接的方式來上網,還有一種可能是不論當前處于哪個頁面,都有概率訪問到其他任意的頁面,比如說用戶就是要直接輸入網址訪問其他頁面,雖然這個概率比較小。
所以他定義了阻尼因子 d,這個因子代表了用戶按照跳轉鏈接來上網的概率,通??梢匀∫粋€固定值 0.85,而 1-d=0.15 則代表了用戶不是通過跳轉鏈接的方式來訪問網頁的,比如直接輸入網址。其中 N 為網頁總數,這樣我們又可以重新迭代網頁的權重計算了,因為加入了阻尼因子 d,一定程度上解決了等級泄露和等級沉沒的問題。
通過數學定理(這里不進行講解)也可以證明,最終 PageRank 隨機瀏覽模型是可以收斂的,也就是可以得到一個穩定正常的 PR 值。
6. PageRank給我們帶來的啟發
這個算法有個好處,就是可以通過這個算法,給我們帶來一點生活中的啟示,會是什么啟示呢??啥?不要盲目從眾??這個就有點low了。
PageRank 可以說是 Google 搜索引擎重要的技術之一,在 1998 年幫助 Google 獲得了搜索引擎的領先優勢,現在 PageRank 已經比原來復雜很多,但它的思想依然能帶給我們很多啟發。
比如,如果你想要自己的媒體影響力有所提高,就盡量要混在大 V 圈中;如果想找到高職位的工作,就盡量結識公司高層,或者認識更多的獵頭,因為獵頭和很多高職位的人員都有鏈接關系。?這也就是很重要的理論:加人脈杠桿,搞定一人,撬動千人。(好吧,這個只是逆襲學習理論中的一小小部分,后面打算也會把逆襲學習理論整理出來,大家共勉。)
說了這么多,也知道了PageRank的原理了,那就讓我們實戰吧!
7. PageRank實戰
7.1 如何使用工具實現PageRank算法
PageRank 算法工具在 sklearn 中并不存在,我們需要找到新的工具包。實際上有一個關于圖論和網絡建模的工具叫 NetworkX,它是用 Python 語言開發的工具,內置了常用的圖與網絡分析算法,可以方便我們進行網絡數據分析。
上面舉了一個網頁權重的例子,假設一共有 4 個網頁 A、B、C、D,它們之間的鏈接信息如圖所示:針對這個例子,我們看下用 NetworkX 如何計算 A、B、C、D 四個網頁的 PR 值,具體代碼如下:
import networkx as nx # 創建有向圖 G = nx.DiGraph() # 有向圖之間邊的關系 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_list = nx.pagerank(G, alpha=1) print("pagerank值是:\n", pagerank_list)結果如下:
pagerank值是: {'A': 0.33333396911621094, 'B': 0.22222201029459634, 'C': 0.22222201029459634, 'D': 0.22222201029459634}關鍵代碼就nx.pagerank(G, alpha=1) 這一句話, 這里的alpha就是我們上面說的阻尼因子,代表用戶按照跳轉鏈接的概率。默認是0.85。這里是1,表示我們都是用跳轉鏈接,不直接輸入網址的那種。
好了,運行完這個例子之后,來看下 NetworkX 工具都有哪些常用的操作。
★關于圖的創建圖可以分為無向圖和有向圖,在 NetworkX 中分別采用不同的函數進行創建。無向圖指的是不用節點之間的邊的方向,使用 nx.Graph() 進行創建;有向圖指的是節點之間的邊是有方向的,使用 nx.DiGraph() 來創建。在上面這個例子中,存在 A→D 的邊,但不存在 D→A 的邊。
關于節點的增加、刪除和查詢如果想在網絡中增加節點,可以使用 G.add_node(‘A’) 添加一個節點,也可以使用 G.add_nodes_from([‘B’,‘C’,‘D’,‘E’]) 添加節點集合。如果想要刪除節點,可以使用 G.remove_node(node) 刪除一個指定的節點,也可以使用 G.remove_nodes_from([‘B’,‘C’,‘D’,‘E’]) 刪除集合中的節點。
那么該如何查詢節點呢?如果你想要得到圖中所有的節點,就可以使用 G.nodes(),也可以用 G.number_of_nodes() 得到圖中節點的個數。關于邊的增加、刪除、查詢增加邊與添加節點的方式相同,使用 G.add_edge(“A”, “B”) 添加指定的“從 A 到 B”的邊,也可以使用 add_edges_from 函數從邊集合中添加。我們也可以做一個加權圖,也就是說邊是帶有權重的,使用add_weighted_edges_from 函數從帶有權重的邊的集合中添加。在這個函數的參數中接收的是 1 個或多個三元組[u,v,w]作為參數,u、v、w 分別代表起點、終點和權重。
另外,我們可以使用 remove_edge 函數和 remove_edges_from 函數刪除指定邊和從邊集合中刪除。另外可以使用 edges() 函數訪問圖中所有的邊,使用 number_of_edges() 函數得到圖中邊的個數。
以上是關于圖的基本操作,如果我們創建了一個圖,并且對節點和邊進行了設置,就可以找到其中有影響力的節點,原理就是通過 PageRank 算法,使用 nx.pagerank(G) 這個函數,函數中的參數 G 代表創建好的圖。
7.2 如何用 PageRank 揭秘希拉里郵件中的人物關系
數據集可以再這里下載:https://github.com/cystanford/PageRank先了解下數據集:
★整個數據集由三個文件組成:Aliases.csv,Emails.csv 和 Persons.csv,其中 Emails 文件記錄了所有公開郵件的內容,發送者和接收者的信息。Persons 這個文件統計了郵件中所有人物的姓名及對應的 ID。因為姓名存在別名的情況,為了將郵件中的人物進行統一,我們還需要用 Aliases 文件來查詢別名和人物的對應關系。
整個數據集包括了 9306 封郵件和 513 個人名,數據集還是比較大的。不過這一次我們不需要對郵件的內容進行分析,只需要通過郵件中的發送者和接收者(對應 Emails.csv 文件中的 MetadataFrom 和 MetadataTo 字段)來繪制整個關系網絡。因為涉及到的人物很多,因此我們需要通過 PageRank 算法計算每個人物在郵件關系網絡中的權重,最后篩選出來最有價值的人物來進行關系網絡圖的繪制。
了解了數據集和項目背景之后,我們來設計到執行的流程步驟:
★首先我們需要加載數據源;
在準備階段:我們需要對數據進行探索,在數據清洗過程中,因為郵件中存在別名的情況,因此我們需要統一人物名稱。另外郵件的正文并不在我們考慮的范圍內,只統計郵件中的發送者和接收者,因此我們篩選 MetadataFrom 和 MetadataTo 這兩個字段作為特征。同時,發送者和接收者可能存在多次郵件往來,需要設置權重來統計兩人郵件往來的次數。次數越多代表這個邊(從發送者到接收者的邊)的權重越高;
在挖掘階段:我們主要是對已經設置好的網絡圖進行 PR 值的計算,但郵件中的人物有 500 多人,有些人的權重可能不高,我們需要篩選 PR 值高的人物,繪制出他們之間的往來關系。在可視化的過程中,我們可以通過節點的 PR 值來繪制節點的大小,PR 值越大,節點的繪制尺寸越大。
最終代碼如下:
# -*- coding: utf-8 -*- # 用 PageRank 挖掘希拉里郵件中的重要任務關系 import pandas as pd import networkx as nx import numpy as np from collections import defaultdict import matplotlib.pyplot as plt # 數據加載 emails = pd.read_csv("./input/Emails.csv") # 讀取別名文件 file = pd.read_csv("./input/Aliases.csv") aliases = {} for index, row in file.iterrows():aliases[row['Alias']] = row['PersonId'] # 讀取人名文件 file = pd.read_csv("./input/Persons.csv") persons = {} for index, row in file.iterrows():persons[row['Id']] = row['Name'] # 針對別名進行轉換 def unify_name(name):# 姓名統一小寫name = str(name).lower()# 去掉, 和 @后面的內容name = name.replace(",","").split("@")[0]# 別名轉換if name in aliases.keys():return persons[aliases[name]]return name # 畫網絡圖 def show_graph(graph, layout='spring_layout'):# 使用 Spring Layout 布局,類似中心放射狀if layout == 'circular_layout':positions=nx.circular_layout(graph)else:positions=nx.spring_layout(graph)# 設置網絡圖中的節點大小,大小與 pagerank 值相關,因為 pagerank 值很小所以需要 *20000nodesize = [x['pagerank']*20000 for v,x in graph.nodes(data=True)]# 設置網絡圖中的邊長度edgesize = [np.sqrt(e[2]['weight']) for e in graph.edges(data=True)]# 繪制節點nx.draw_networkx_nodes(graph, positions, node_size=nodesize, alpha=0.4)# 繪制邊nx.draw_networkx_edges(graph, positions, edge_size=edgesize, alpha=0.2)# 繪制節點的 labelnx.draw_networkx_labels(graph, positions, font_size=10)# 輸出希拉里郵件中的所有人物關系圖plt.show() # 將寄件人和收件人的姓名進行規范化 emails.MetadataFrom = emails.MetadataFrom.apply(unify_name) emails.MetadataTo = emails.MetadataTo.apply(unify_name) # 設置遍的權重等于發郵件的次數 edges_weights_temp = defaultdict(list) for row in zip(emails.MetadataFrom, emails.MetadataTo, emails.RawText):temp = (row[0], row[1])if temp not in edges_weights_temp:edges_weights_temp[temp] = 1else:edges_weights_temp[temp] = edges_weights_temp[temp] + 1 # 轉化格式 (from, to), weight => from, to, weight edges_weights = [(key[0], key[1], val) for key, val in edges_weights_temp.items()] # 創建一個有向圖 graph = nx.DiGraph() # 設置有向圖中的路徑及權重 (from, to, weight) graph.add_weighted_edges_from(edges_weights) # 計算每個節點(人)的 PR 值,并作為節點的 pagerank 屬性 pagerank = nx.pagerank(graph) # 將 pagerank 數值作為節點的屬性 nx.set_node_attributes(graph, name = 'pagerank', values=pagerank) # 畫網絡圖 show_graph(graph)# 將完整的圖譜進行精簡 # 設置 PR 值的閾值,篩選大于閾值的重要核心節點 pagerank_threshold = 0.005 # 復制一份計算好的網絡圖 small_graph = graph.copy() # 剪掉 PR 值小于 pagerank_threshold 的節點 for n, p_rank in graph.nodes(data=True):if p_rank['pagerank'] < pagerank_threshold:small_graph.remove_node(n) # 畫網絡圖,采用circular_layout布局讓篩選出來的點組成一個圓 show_graph(small_graph, 'circular_layout')運行結果:針對代碼中的幾個模塊個簡單的說明:
★函數定義人物的名稱需要統一,因此設置了 unify_name 函數,同時設置了 show_graph 函數將網絡圖可視化。NetworkX 提供了多種可視化布局,這里使用 spring_layout 布局,也就是呈中心放射狀。
除了 spring_layout 外,NetworkX 還有另外三種可視化布局,circular_layout(在一個圓環上均勻分布節點),random_layout(隨機分布節點 ),shell_layout(節點都在同心圓上)。
計算邊權重郵件的發送者和接收者的郵件往來可能不止一次,我們需要用兩者之間郵件往來的次數計算這兩者之間邊的權重,所以用 edges_weights_temp 數組存儲權重。而上面介紹過在 NetworkX 中添加權重邊(即使用 add_weighted_edges_from 函數)的時候,接受的是 u、v、w 的三元數組,因此我們還需要對格式進行轉換,具體轉換方式見代碼。3. PR 值計算及篩選使用 nx.pagerank(graph) 計算了節點的 PR 值。由于節點數量很多,我們設置了 PR 值閾值,即 pagerank_threshold=0.005,然后遍歷節點,刪除小于 PR 值閾值的節點,形成新的圖 small_graph,最后對 small_graph 進行可視化(對應運行結果的第二張圖)。
8. 總結
今天用了一天的時間,學習PageRank算法的理論,并且通過理論做了一個實戰,運用了一下,又抓緊記錄,完成了一篇博客,心理還是很高興的。學習知識的過程就是這樣,如果只是單純的輸入,沒有一點輸出的話,那么很快就會忘記,輸出一遍,至少在大腦里面停留了片刻,這里也留下了自己的蹤跡,就像那就話說的:天空中沒有鳥的痕跡,但是我已經飛過。
努力學習,快速感悟,敢于嘗試,這樣我們才能做到永遠年輕,永遠熱淚盈眶。加油!
參考:
http://note.youdao.com/noteshare?id=3568b0c7f636cb21f260cd9f83ea4817&sub=B90987F55A05445B8E07476DDFCB6D62
https://time.geekbang.org/
https://blog.csdn.net/u013007900/article/details/88961913
https://blog.csdn.net/leadai/article/details/81230557
往期精彩回顧適合初學者入門人工智能的路線及資料下載機器學習在線手冊深度學習在線手冊AI基礎下載(pdf更新到25集)本站qq群1003271085,加入微信群請回復“加群”獲取一折本站知識星球優惠券,復制鏈接直接打開:https://t.zsxq.com/yFQV7am喜歡文章,點個在看
總結
以上是生活随笔為你收集整理的【白话机器学习】算法理论+实战之PageRank算法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 目前看的图神经网络(GNN)论文的一些总
- 下一篇: Embedding技术在房产推荐中的应用