【Neo4j】第 9 章:预测关系
?🔎大家好,我是Sonhhxg_柒,希望你看完之后,能對你有所幫助,不足請指正!共同學習交流🔎
📝個人主頁-Sonhhxg_柒的博客_CSDN博客?📃
🎁歡迎各位→點贊👍 + 收藏?? + 留言📝?
📣系列專欄 - 機器學習【ML】?自然語言處理【NLP】? 深度學習【DL】
??
?🖍foreword
?說明?本人講解主要包括Python、機器學習(ML)、深度學習(DL)、自然語言處理(NLP)等內容。
如果你對這個系列感興趣的話,可以關注訂閱喲👋
文章目錄
技術要求
為什么要使用鏈接預測?
動態圖
應用
恢復丟失的數據
提出建議
使用鏈接預測算法進行推薦
使用 Neo4j 創建鏈接預測指標
基于社區的指標
路徑相關指標
節點之間的距離
卡茨指數(The Katz index)
使用當地鄰里信息
共同鄰居
亞當-阿達爾
鄰居總數
優先附加
其他指標
使用 ROC 曲線構建鏈路預測模型
將數據導入 Neo4j
分割圖并計算每條邊的分數
測量二元分類模型的性能
了解 ROC 曲線
提取特征和標簽
繪制 ROC 曲線
確定最佳截止和計算性能
使用 scikit-learn 構建更復雜的模型
將鏈接預測結果保存到 Neo4j
預測二分圖中的關系
概括
問題
進一步閱讀
圖是數據表示的一種特定形式。在前面的章節中,我們學習了如何以無監督或半監督的方式從圖中提取信息。我們探索了如何將這些信息用作經典機器學習模型的特征,其中節點是觀察值。在本章中,我們將處理一種只有圖才有可能解決的全新類型的問題:鏈接預測。在準確了解鏈接預測問題是什么以及如何將其應用于不同的案例之后,我們將了解 Graph Data Science 庫中實現的功能,這可以幫助我們找到問題的解決方案。最后,我們將使用 Python 及其數據科學工具箱研究一個真實的示例應用程序問題。
本章將涵蓋以下主題:
- 為什么要使用鏈接預測?
- 使用 Neo4j 創建鏈接預測指標
- 使用 ROC 曲線構建鏈路預測模型
技術要求
本章將使用以下工具:
- 我們依賴 Neo4j 圖數據庫,版本 ≥ 3.5,以及以下插件:
- 圖數據科學庫(版本 ≥ 1.0)
- 代碼示例將使用 Python (≥ 3.6) 給出,我們將使用以下包進行數據建模和數據可視化:
- 要存儲數據并創建 DataFrame,我們將依賴.?pandas
- 為了構建模型,我們將使用.?scikit-learn
- 數據可視化將使用.?matplotlib
- 本章的代碼可以在 GitHub 上的以下鏈接中找到:
https ://github.com/PacktPublishing/Hands-On-Graph-Analytics-with-Neo4j/ch9
如果您使用的是Neo4j < 4.0,那么GDS插件的最后一個兼容版本是1.1,而如果您使用的是Neo4j ≥ 4.0,那么GDS插件的第一個兼容版本是1.2。
為什么要使用鏈接預測?
鏈接預測包括猜測圖中現有節點之間的哪些未知連接現在或將來更有可能是真實的。通過適當的表述,這可以轉化為機器學習問題。但在嘗試建立鏈接預測模型之前,對于任何數據科學任務,我們必須從對問題的深刻理解開始。這將是我們在本節中的目標。首先,通過使用動態圖的上下文,我們將定義鏈接預測背后究竟隱藏了什么。我們還將審查一些應用程序,從營銷到科學。
動態圖
到目前為止,在本書中,我們以靜態的方式研究了圖。換句話說,我們從外部數據源導入圖表,并且圖表內容(節點或關系)從未改變。以這種方式研究圖結構可以為我們提供一些關于它所代表的數據的信息。然而,在現實生活場景中,無論您的圖模型是道路網絡還是電子商務網站,它都會隨著時間而改變。在動態圖中,圖的所有部分都可以改變。以下是圖表可以更改的方式的一些示例:
- 節點添加:訂閱服務的新用戶、添加到目錄的新產品或創建的新交叉點。?
- 節點移除:產品不再生產或客戶離開。
- 鏈接添加:現有客戶購買另一種產品,或在兩個路口之間添加一條道路。
- 鏈接刪除:一條封閉的道路或客戶取消訂閱某些服務,但保持訂閱其他產品。
預測所有這些變化可能非常具有挑戰性。因此,我們將專注于本章中的鏈接,假設節點沒有變化。有了這個假設,圖G在時間t?2的狀態由以下公式給出:
G(t?1?) + added_links - removed_links = G(t?2?)
下圖是對上述公式的說明:
由于我們只關注鏈接添加,我們的目標是預測我們圖中兩個現有但未連接的節點將來是否可能連接。為此可以考慮許多不同類型的應用程序。
應用
預測未來的鏈接是鏈接預測的目標之一。但是可以找到其他應用程序,尤其是在我們掌握的信息不完整的情況下。
恢復丟失的數據
有時我們的圖表數據并不能代表全貌。我們的知識將是不完整的,并且圖中實體之間的某些鏈接可能會丟失。至少有兩種情況經常發生這種情況。
打擊犯罪
在犯罪行為方面,警方并不了解犯罪組織內部和之間的所有節點或關系。鏈接預測方法已被用于推斷丟失的鏈接,并找到未來最有可能合作犯罪的犯罪分子。
研究
研究,就其本質而言,總是在發展和變化。當一個圖用于對某個主題的知識進行建模時,這些知識通常是部分的,因為研究正在進行中,我們還沒有完全理解圖的所有元素之間的相互作用。
鏈接預測技術在生物學中已經被大量使用,例如,試圖根據當前有關遺傳疾病的知識來識別與某些疾病有關的基因。
提出建議
在日常生活中,鏈接預測可用于在社交網絡和電子商務環境中向用戶推薦。
社交鏈接(Facebook 好友、LinkedIn 聯系人...)
Facebook、Twitter 和 LinkedIn 等網站都可以使用連接圖表示:
- Facebook 是一種無向圖建模友誼。
- LinkedIn 也是一個代表專業聯系人的無向圖。
- Twitter 是一個有向圖(您可能會關注不關注您的人,反之亦然)。
所有這些社交媒體網站都包含類似“您可能認識的人”部分的內容。這些建議可以基于不同的因素。例如,他們可以使用以下事實:
- 你們參加了同一所大學的講座,所以即使這種關系沒有在社交媒體上正式公布,你們也可能認識對方。
- 你們有共同的朋友,所以你們很可能彼此認識,或者在未來的聚會、婚禮或其他涉及共同朋友的活動中被介紹。
除了連接推薦,鏈接預測也可以用于產品推薦。
產品推薦
想象一個類似于這個的圖形模式:
用戶鏈接到他們購買的產品。因此,為每個用戶推薦產品是一個鏈接預測問題,我們試圖預測用戶和產品之間的新鏈接。
但是,這種鏈接預測與社交網絡中使用的鏈接預測之間存在根本區別。這種差異來自圖表的性質;在社交網絡中,該圖被稱為monopartite,而 user-product 圖是bipartite。區別如下圖所示:
?在二分圖中,圖由兩組節點 N 和 M 組成,邊必然連接節點 N 和節點 M。在前面顯示用戶和產品的圖模式中,關系僅連接用戶和產品;我們從來沒有看到用戶-用戶或產品-產品的關系。這就是使圖表具有二分性的原因——一側是用戶,另一側是產品。
我們將在本章中學習的技術主要是為單部圖設計的。我們將在本章的最后一節看到它們如何適應二分圖。
使用鏈接預測算法進行推薦
在第 8 章,在機器學習中使用基于圖的特征中,我們研究了一個包含以下列的數據集:
如果您閱讀了第 2 章,Cypher 查詢語言,您可能已經注意到該數據集與我們在本章中研究的圖之間的相似性。它基于 GitHub 公共 API 構建,包含與 GitHub 上的 Neo4j 組織相關的數據:
- 它的貢獻者
- 這些貢獻者貢獻的存儲庫
- 這些新存儲庫的貢獻者
圖模式如下:
Language并且Document是通過對存儲庫的自述文件進行基于 NLP 的分析添加的一些特殊節點。我們將在這里重點關注User和Repository標簽。
從該圖中,我們可以使用以下 Cypher 查詢構建上一章中使用的數據:
MATCH (u:User) OPTIONAL MATCH (u)-[:CONTRIBUTED_TO]->(r:Repository)<-[:OWNS]-(:User {login: "neo4j"}) WITH u, COLLECT(r) as rs RETURN id(u) as user_id, u.followers as followers, u.publicRepos as publicRepos, size(rs) > 0 as contributed_to_neo4j ORDER BY user_id該OPTIONAL MATCH語句允許我們檢索所有用戶,包括那些沒有為 Neo4j 做出貢獻的用戶。使用COLLECT語句是必要的,這樣我們就不會計算兩次為 Neo4j 擁有的多個存儲庫做出貢獻的用戶。
但是,再次查看圖模式,我們可以看到我們在前一章中試圖回答的問題,“該用戶是否對 Neo4j 擁有的存儲庫做出了貢獻?”。也可以轉化為鏈接預測問題:
用戶和 Neo4j 擁有的存儲庫之間是否存在鏈接?
多年來已經開發了幾種技術來找到解決這個問題的方法。在下一節中,我們將探討 GDS 插件中已實現的主要算法。
使用 Neo4j 創建鏈接預測指標
有許多指標可用于鏈接預測問題。我們已經在本書中研究了其中的一些,但我們將在本節中以鏈接預測為新焦點來回顧它們。已經引入了一些其他指標,特別是針對此類應用程序,它們linkprediction位于 GDS 的命名空間下。
鏈接預測算法的想法是能夠創建一個矩陣N×N,其中N是圖中的節點數。矩陣的每個ij元素必須指示節點i和j之間存在鏈接的概率。
可以使用不同類型的指標來實現這一目標。其中之一是節點相似度度量,例如我們在第 7 章社區檢測和相似度度量中研究的 Jaccard 相似度。在這種方法中,通過比較節點鄰居的集合,我們可以了解節點的相似性以及它們未來連接的可能性。
相似性是可以在鏈接預測上下文中使用的度量的一個示例,但已經開發了更多。以下段落介紹其中最著名的。
基于社區的指標
社區指標包含有關圖結構的信息。第 7 章,社區檢測和相似性度量中介紹了不同類型的此類算法。其中包括用于發現孤立節點組的強連接和弱連接組件以及用于更微妙社區識別的標簽傳播和 Louvain 算法。
在許多情況下,我們可以安全地假設同一社區中的兩個節點更有可能被連接。下圖說明了這個概念:
接下來更有可能創建B和C之間的鏈接,因為B和C位于同一個社區中,與節點B和D不同。在這種情況下,評分函數如下:
如果 u 和 v 在同一個社區中,則 score(u, v) = 1,否則為 0
在這些情況下,我們可以使用sameCommunityGDS 插件的功能。這將簡單地檢查兩個節點是否在同一個社區中,假設社區存儲為每個節點的節點屬性:
MATCH (u:User {user_id: 32}) MATCH (v:User {user_id: 12464}) RETURN gds.alpha.linkprediction.sameCommunity(u, v, "louvain") as sameCommunity這完全等同于使用以下內容:
MATCH (u:User {user_id: 32}) MATCH (v:User {user_id: 12464}) RETURN u.louvain = v.louvain as sameCommunity路徑相關指標
兩個節點之間的距離可以是它們接近程度和未來可能連接的另一個指標。
節點之間的距離
讓我們再看一下下圖:
在上圖中,我們可以看到B和C之間的關系比D和F之間的關系更可能為真,因為B和C之間的最短路徑只有 2(未加權圖),而 B 和 C 之間的最短路徑D和F為 3。
所以我們可以設想一個評分函數如下:
score(u, v) = 1/d(u, v),
其中d(u, v)是節點u和v之間的最短路徑
在第 4 章,圖數據科學庫和路徑查找中,我們研究了所有對的最短路徑算法,如果基于距離的鏈接預測指標與您的問題相關,則該算法在這里很有用。請記住,該算法可以graph使用以下查詢在先前創建的名為投影圖 上運行:
CALL gds.alpha.allShortestPaths.stream("projected_graph", {}) YIELD sourceNodeId, targetNodeId, distance WITH gds.util.asNode(sourceNodeId) as startNode,gds.util.asNode(targetNodeId) as endNode,distance RETURN startNode.name as start,endNode.name as end,distance為了將此距離轉換為鏈接預測分數,我們將取距離的倒數,并根據這個新指標將結果按升序排序。這會導致最近的節點首先出現。如果我們只想顯示不存在的鏈接,我們必須添加一個額外的過濾器來刪除已經通過直接鏈接相互連接的節點對。這兩個操作都在以下 Cypher 查詢中執行:
CALL gds.alpha.allShortestPaths.stream("projected_graph", {}) YIELD sourceNodeId, targetNodeId, distance WITH gds.util.asNode(sourceNodeId) as startNode,gds.util.asNode(targetNodeId) as endNode,1.0 / distance as score WHERE NOT ((startNode)-[:LINKED_TO]->(endNode)) RETURN startNode.name, endNode.name, score LIMIT 10未加權圖中的最高可能分數為 0.5,因為斷開連接的節點彼此相距至少兩跳。創建兩個節點B和C之間的邊,得分為 0.5,包括閉合由三個節點B、C及其公共鄰居A組成的三角形。下圖說明了這個概念;節點C和B彼此相距兩跳,因為它們之間的最短路徑通過節點A。連接它們將閉合頂點為A、B和C 的三角形:
然而,在一個大圖上,我們可能有很多節點,在這種情況下,關閉所有三角形幾乎是不可行的。幸運的是,基于當地社區,存在更精細的技術。
卡茨指數(The Katz index)
計算節點之間的最短距離是一種非常基本的方法,它沒有考慮節點之間可能的連接。一個詳細的版本,稱為Katz 索引,包括對兩個節點之間的所有路徑求和,長度增加。它使用以下公式計算:
分數(u, v) = ∑?l?β?l?p(u, v; l)
讓我們詳細看看每個組件:
- l是路徑長度,從 1 到 ∞。
- p(u, v; l)是節點u和v之間長度為l的路徑數。
- β是一個權重參數,其值在 0 和 1 之間選擇,以便為最短距離賦予更多權重。
在實踐中,鄰接矩陣用于計算這個分數,因為可以證明u和v之間長度為l的路徑的數量等于鄰接矩陣的uv元素的冪l:
score(u, v) = ∑l?βl?A(u, v)l
Katz 索引已被證明是性能最佳的基于路徑的鏈接預測算法之一。例如,請看進一步閱讀部分中題為“復雜網絡中的鏈接預測:一項調查”的論文。
使用當地鄰里信息
為了理解以下公式背后的數學原理,我們首先介紹一些符號,類似于第 7 章,社區檢測和相似性度量中使用的符號:
- u、v和i是圖的節點。
- N(u)表示節點u的鄰居集合。
- |N(u)|?是集合的大小,表示節點u的鄰居數。
共同鄰居
公共鄰居方法支持以下假設:
兩個有共同朋友的人比沒有共同朋友的人更有可能被介紹。
共同鄰居度量度量u和v之間的共同朋友集的大小:
score(u, v) = | N(u) ∩ N(v) |
在 GDS 插件中,鏈接預測指標是函數,可以使用以下方法計算:
MATCH (u) MATCH (v) RETURN id(u), id(v), gds.alpha.linkprediction.commonNeighbors(u, v)亞當-阿達爾
Adamic-Adar得分是對共同鄰居方法的改進。Adamic-Adar 假設稀有連接比普通連接提供更多信息。在 Adamic-Adar 公式中,與鄰居的每個關系都根據以下公式通過鄰居度的倒數加權:
score(u, v) = Σ?i?1/log|N(i)|, i ∈ N(u) ∩ N(v)
下圖說明了這個想法。
而節點u和v在兩側通過x連接,由于x在左圖中的度數較低,它與u和v的關系更重要,u和v之間的邊更可能:
鄰居總數
當以下假設合理時,必須使用總鄰居度量:
一個節點連接得越多,它的社交性越強,接收新鏈接的可能性就越大。
在量化節點u和v連接的可能性時,我們可以使用屬于兩個節點的相鄰集的節點數:
score(u, v) = | N(u) ∪ N(v) |
讓我們通過考慮以下兩個圖表來理解這個公式:
下圖左側的節點u和v與右側的節點u和v相比有很多連接。因此,左側的節點u和v更有可能接受新連接:
優先附加
在某些情況下,假設以下是合理的:
更受歡迎的人更有可能與其他受歡迎的人聯系起來。
在這些情況下,必須使用優先連接方法。節點u和v的優先附著分數等于節點u和v的度數的乘積:
score(u, v) = | N(u) | × | N(v)?|
這個分數也在gds.alpha.preferentialAttachment函數下的GDS插件中實現:
MATCH (u), MATCH (v) RETURN id(u), id(v), gds.alpha.linkprediction.preferentialAttachment(u, v, {relationshipType: "REL", direction: "BOTH" })請注意,我們可以選擇指定用于查找鄰域的關系的類型和方向。我們將在下一節中查看一個示例應用程序。
其他指標
并非所有上述指標都可以同時使用。在哪種情況下最好使用哪一個取決于控制圖增長的底層過程,并且在許多情況下,有必要測試幾個指標以找到最合適的一個。我們甚至可以想象更多的指標,例如:
- 互惠性:鏈接的存在使得在相反方向上添加鏈接的可能性更大,而刪除互惠鏈接的可能性更小。
- 新的弱點:新形成的鏈接比舊鏈接不太可能持續存在,因此權重較小。
- 不穩定性:如果連接到節點u和v的屬性或鏈接經常變化,則u和v之間的邊也更有可能無法生存并且權重較小。
在這篇關于鏈接預測評分方法的回顧之后,我們現在將使用 Neo4j 和scikit-learn.
使用 ROC 曲線構建鏈路預測模型
在我們迄今為止研究的所有圖分析問題中,我們的觀察都是圖的節點。然而,現在我們正在轉向一個不同的概念,其中觀察是邊緣。數據集的每一行都應包含有關圖形一條邊的信息。由于我們的目標是預測鏈接是否會在未來出現或從我們當前的知識中丟失,我們可以將問題轉化為二分類問題,即邊緣可以具有:
- 類True,鏈接存在或可能被創建,或者
- 類False,鏈接不太可能出現。
由于我們即將建立一個分類模型,我們的數據集必須包括現有和不存在的邊(二元分類器的兩個類)。
將數據導入 Neo4j
我們將在本章其余部分使用的數據是隨機生成的幾何圖。這種圖有許多有趣的特征,其中之一是它能夠重現一些現實生活中的圖的行為,例如社交圖。
下載數據并將其放入import我們圖的文件夾后,我們可以使用以下 Cypher 語句將其導入到 Neo4j 中:
LOAD CSV FROM "file:///graph_T2.edgelist" AS row FIELDTERMINATOR " " MERGE (u:Node {id: toInteger(row[0])}) MERGE (v:Node {id: toInteger(row[1])}) MERGE (u)-[:KNOWS_T2]->(v) 該圖僅包含 500 個節點和3,565個關系,這就是我們可以忽略Eager前面查詢中有關運算符的警告的原因。訓練集包含在時間t?2時已經存在于圖中的邊。因此,我們還要在之前的時間t?1導入圖形。此時,節點與已經存在的節點相同,因此我們可以使用MATCH子句代替MERGE:
LOAD CSV FROM "file:///graph_T1.edgelist" AS row FIELDTERMINATOR " " MATCH (u:Node {id: toInteger(row[0])}) MATCH (v:Node {id: toInteger(row[1])}) MERGE (u)-[:KNOWS_T1]->(v)所以我們現在有一個包含兩種關系的圖表:
- KNOWS_T1如果兩個節點在時間t1相互認識,則鏈接它們。
- KNOWS_T2如果兩個節點在時間t2相互認識,則鏈接它們。類型關系集是類型關系KNOWS_T1集的子集,因為在時間t1KNOWS_T2相互認識的兩個節點在時間t2仍然相互認識。
我們現在將學習如何計算該圖的鏈接預測分數。
分割圖并計算每條邊的分數
為了使用鏈接預測分數進行預測,我們需要遵循以下步驟:
在這個例子中,圖在 t?1的狀態已經通過KNOWS_T1關系提供了。
我們現在可以計算圖中每對節點的鏈接預測分數,使用新創建的關系僅考慮時間t?1的知識。在這里,我們選擇使用 Adamic-Adar 分數:
MATCH (u) MATCH (v) WHERE u <> v RETURN u.id as u_id, v.id as v_id, gds.alpha.linkprediction.adamicAdar(u, v, {relationshipQuery: "KNOWS_T1",direction: "BOTH"}) as score LIMIT 10前面查詢中最重要的部分在這里突出顯示:
- 鏈接預測函數將僅使用一種類型的關系KNOWS_T1,忽略我們試圖預測的有關后驗關系的信息。
- 該圖被認為是無向的;如果 A 知道 B(在任何時候),那么我們認為 B 知道 A。
Adamic-Adar 算法識別的一些最可能的節點對如下:
╒══════╤══════╤═══════╕ │"u_id"│"v_id"│"score"│ ╞══════╪══════╪═══════╡ │41 │33 │7.3 │ ├──────┼──────┼───────┤ │33 │41 │7.3 │ ├──────┼──────┼───────┤ │171 │42 │7.1 │ ├──────┼──────┼───────┤ │162 │178 │6.9 │ ├──────┼──────┼───────┤ │3 │124 │6.7 │ ├──────┼──────┼───────┤ │75 │16 │6.6 │ └──────┴──────┴───────┘要在模型中使用這個分數,我們需要量化它的辨別能力,這可以通過接收器操作特征(?ROC?) 曲線來實現。我們還需要為分數找到一個最佳截止值,以決定將來是否會出現鏈接;例如,我們應該停止在 score=5、score=4.5 還是更低?我們現在將討論這兩個主題。
測量二元分類模型的性能
這個問題是一個二元分類任務。我們的觀察是鏈接,我們必須決定它們屬于以下兩個類別中的哪一個:
- 鏈接將在時間t?1和t?2之間創建。
- 在時間t?1和t?2之間不會創建鏈接。
為了衡量給定模型的性能,我們可以使用 ROC 曲線。
了解 ROC 曲線
到目前為止,我們有什么信息?對于測試樣本,我們在時間 t?2的圖,我們知道每對節點的以下內容:
- 在時間t?2時它們之間是否確實存在聯系(基本事實)
- 從鏈接預測指標計算的分數
從這些信息中,我們可以得出每個標簽的分數分布。讓我們考慮以下情節:
最左邊的曲線表示具有標簽的所有觀察的分數分布False,而最右邊的曲線對應于具有標簽的所有觀察的分數分布True。為了評估指標的質量,我們可以使用 ROC 曲線。
為了根據這些信息做出預測,我們需要定義一個分數閾值。要定義分數閾值,我們需要設置一條垂直線,以便將這條線左側的所有觀測值分類為False,而將右側的所有觀測值(即分數高于閾值的觀測值)分類為歸類為True。下圖說明了兩種可能的閾值選擇;頂行有一個閾值T=11,而底行的兩個圖有一個閾值T=7:
從這些曲線中,我們可以定義一些變量:
- 真陽性(?TP?):正確分類為陽性的觀察次數。這對應于綠色曲線下方和所選閾值右側的綠色區域。
- 假陰性(?FN?):這是 TP 的對應物,對應于被分類為陰性的陽性觀察的比例。在圖上,這是綠色曲線下的紅色區域。
- 真陰性(?TN?):正確分類為陰性的陰性觀察次數。這是左側紅色曲線下方的綠色區域。
- 假陽性(?FP?):被錯誤歸類為陽性的負面觀察的數量。這對應于紅色曲線下的紅色區域。
這四個變量組合起來定義真陽性率(?TPR?) 和假陽性率(?FPR?):
TPR = TP / (TP + FN)
FPR = FP / (FP + TN)
TPR衡量正確分類的True觀察值與整個正面觀察值的比例。FPR量化了錯誤分類的負面觀察的比例。這兩個量之間的權衡由 ROC 曲線表示:
?每個點對應一個給定的閾值。T=10處的點接近最優分區,即 FPR 和 TPR 之間折衷最佳的分區。
下圖說明了一些配置,以幫助我們更好地了解 ROC 在不同場景下的樣子:
?讓我們來看看這些配置中的每一個:
- False在配置 1 中, (最左邊的曲線)和(最右邊的曲線)標簽的分數分布True很好地分開。您可以輕松猜測應該使用哪個閾值來創建一個模型,該模型將成功地將觀察結果分配給正確的類。在這種情況下,AUC 接近1,這是一個幾乎完美模型的標志。
- 在配置 2 中,兩個分布更接近,但仍然可以區分。AUC 較低,約為 0.8,但我們仍然可以獲得良好的性能。
- 在配置 3 中,兩個分布幾乎相同,模型幾乎不比隨機選擇好。
- 最后,在配置 4 中,模型似乎顛倒了這兩個類別,因為False標簽現在由最右邊的曲線表示,因此得分高于True標簽。如果我們堅持將較高分數歸類為正數的預期規則,那么性能會比隨機模型差。
現在讓我們回到我們最初的鏈路預測問題并繪制 ROC 曲線。
提取特征和標簽
為了為鏈接預測任務創建數據集,我們需要執行以下操作:
以下查詢執行這三個操作:
MATCH (u) MATCH (v) // take only one link from undirected graph WHERE u.id < v.id // exclude u = v // exclude edges that were already there at T1: AND NOT ( (u)-[:KNOWS_T1]-(v) ) // compute score WITH u, v, gds.alpha.linkprediction.adamicAdar(u, v, {relationshipQuery: "KNOWS_T1", direction: "BOTH"}) as score RETURN u.id as u_id, v.id as v_id, score, // get the label: does the edge exist at time t2?EXISTS( (u)-[:KNOWS_T2]-(v) ) as label 注意:鏈接預測算法仍處于 GDS 插件的 alpha 層(從 ??1.2.0 版開始)。這意味著它們尚未優化,之前的查詢可能會很長!從此查詢創建的數據集也可在文件中找到adamic_adar_scores_labelled.csv。
繪制 ROC 曲線
在使用 Neo4j 計算基于圖的信息之后,讓我們使用一些更經典的數據科學工具來量化分數的質量。我們將使用pandas和中實現的功能scikit-learn。
創建數據框
首先,讓我們使用 Neo4j Python 驅動程序將 Neo4j 中的數據導出到 pandas DataFrame(類似于第 8 章,在機器學習中使用基于圖的特征中使用的方法):
import pandas as pd from neo4j import GraphDatabasedriver = GraphDatabase.driver("bolt://localhost:7687", auth=("neo4j", "<YOUR_PASSWORD>"))cypher = """ MATCH (u) MATCH (v) WHERE u.id < v.id // exclude u = v AND NOT ( (u)-[:KNOWS_T2]-(v) ) WITH u, v, gds.alpha.linkprediction.adamicAdar(u, v, {relationshipQuery: "KNOWS_T1",direction: "BOTH"}) as score RETURN u.id as u_id, v.id as v_id, score, EXISTS( (u)-[:KNOWS_T1]-(v) ) as label """with driver.session() as session:rec = session.run(cypher)df = pd.DataFrame.from_records(rec.data()) 請記住更新前面的代碼以使用您自己的憑據連接到 Neo4j。我們可以檢查 DataFrame 中的類重新分區:
False 105555 True 3839我們的非現有鏈接大約是現有鏈接的 30 倍。我們的數據集是不平衡的。對于這一階段的分析,只要我們使用不受這種不平衡影響的指標,這將不是問題。
每個班級的歸一化分數分布在下圖中再現:
正如您從圖中看到的那樣, Adamic-Adar 分數似乎是推斷未來鏈接的一個很好的指標。現在讓我們使用 ROC 曲線對此進行量化。
繪制 ROC 曲線
首先,我們應該將數據集拆分為訓練和測試樣本,同時尊重兩個樣本中的類重新分區:
from sklearn.model_selection import train_test_splitX = df[["score"]] y = df.label X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2,random_state=42, # make sure both the train and test samples are representative# of the whole dataset in terms of class unbalancestratify=y )正如我們之前注意到的,我們的數據集是不平衡的。我們可以使用一些采樣技術來恢復訓練集中的類平衡:
from imblearn.under_sampling import RandomUnderSamplerrus = RandomUnderSampler(random_state=SEED) X_train, y_train = rus.fit_resample(X_train, y_train)為了計算不同閾值的 FPR 和 TPR,我們將使用一個scikit-learn函數來為我們這樣做:
from sklearn.metrics import roc_curvefpr, tpr, thresholds = roc_curve(y_train, X_train.score)要使用 繪制 ROC 曲線matplotlib,請使用以下代碼:
import matplotlib.pyplot as pltplt.plot(fpr, tpr, color='blue', linewidth=2)結果如下圖所示:
從上圖中可以看出,我們的模型表現得非常好,并且有一些閾值我們可以在 TPR 和 FPR 中實現良好的性能。我們只需要選擇這個閾值來完成我們的第一個鏈接預測模型的構建。
確定最佳截止和計算性能
選擇用于分類的閾值取決于許多參數。在這里,我們將使用一個閾值來實現精確度和召回率之間的最佳權衡:
precisions, recalls, thresholds = precision_recall_curve(y_train, X_train.score) plt.plot(thresholds, recalls[:-1], label="Recall") plt.plot(thresholds, precisions[:-1], label="Precision") plt.legend() plt.grid() plt.xlabel("Threshold") plt.show()生成的圖在這里重現,其中下降曲線表示召回率,上升曲線表示精度:
選擇閾值 5 會導致以下混淆矩陣:
在時間t?2(第一行)的所有現有邊中,97% 被我們的算法正確標記為True 。同樣,對于不存在的邊緣,93% 被正確分類為False。
使用 scikit-learn 構建更復雜的模型
第一個模型僅使用 Adamic-Adar 分數進行預測,已經運行良好,但是,它只使用了一個特征。在下一節中,我們將從圖中提取更多特征,就像我們之前在第 8 章中所做的那樣,在機器學習中使用基于圖的特征。一旦將數據提取到 DataFrame 中并且我們正確設置了標簽,我們就可以想象使用任何二進制分類器,無論是它scikit-learn還是其他包。
將鏈接預測結果保存到 Neo4j
一旦我們的模型準備好并產生預測,我們可以將它們保存回 Neo4j 以供將來使用(參見第 11 章,在 Web 應用程序中使用 Neo4j)。關于鏈接預測問題,我們將保存一個新的關系類型,FUTURE_LINK對于我們識別為未來更有可能連接的每一對節點。
讓我們從編寫將執行此操作的參數化 Cypher 查詢開始:
cypher = """ MATCH (u:Node {id: $u_id}) MATCH (v:Node {id: $v_id}) CREATE (u)-[:FUTURE_LINK {score: $score}]->(v) """我們將所有需要的信息合并到一個 DataFrame 中:
df_test = df.loc[X_test.index] df_test["score"] = pred然后我們可以遍歷這些數據并為每行創建一個關系label=True:
with driver.session() as session:for t in df_test.itertuples():if t.label:session.run(cypher, parameters={"u_id": t.u_id,"v_id": t.v_id,"score": t.score})循環現在關閉;從 Neo4j 中提取數據以執行我們的分析后,此分析的結果現在返回到數據庫中。它們現在可以由后端或前端應用程序獲取,例如,向用戶顯示連接建議。
在結束這個話題之前,讓我們回到二分圖的話題,例如,它對于進行產品推薦特別有用。
預測二分圖中的關系
在二分圖的情況下,以前的方法效果不佳。實際上,包含閉合三角形的算法是不合適的。
例如,考慮下圖:
????????????????????????????????????????
可以使用以下 Cypher 創建此圖:
CREATE (u1:User {name: "u1"}) CREATE (u2:User {name: "u2"}) CREATE (u3:User {name: "u3"}) CREATE (u4:User {name: "u4"})CREATE (p1:Product {name: "p1"}) CREATE (p2:Product {name: "p2"}) CREATE (p3:Product {name: "p3"})CREATE (u1)-[:BOUGHT]->(p1) CREATE (u1)-[:BOUGHT]->(p2) CREATE (u2)-[:BOUGHT]->(p1) CREATE (u2)-[:BOUGHT]->(p3) CREATE (u3)-[:BOUGHT]->(p2) CREATE (u3)-[:BOUGHT]->(p3) CREATE (u4)-[:BOUGHT]->(p2)用戶u1都u2購買了產品p1。u1,?u2,p1因此是可能三角形的三個角。然而,通過在u1和之間添加一條邊來閉合這個三角形u2是不可能的,因為我們不能在u1和之間建立關系u2。
解決這個問題的方法要么是改變我們尋找鄰居的方式,要么是創建一些虛假的關系,以便將二分圖轉換為單分圖。在前面的圖表示例中,我們可以通過考慮購買相同產品的用戶可以以某種方式連接來創建用戶之間的虛假關系。
可以使用以下查詢創建新關系:
MATCH (u1:User)-[:BOUGHT]->(:Product)<-[:BOUGHT]-(u2:User) CREATE (u1)-[:LINKED_TO]->(u2)由User節點和LINKED_TO關系組成的結果圖如下圖所示:
這種新LINKED_TO關系可以用作鏈接預測函數中的參數:
MATCH (u:User) MATCH (v:User) WHERE id(u) < id(v) RETURN gds.alpha.linkprediction.commonNeighbors(u, v, {relationshipQuery: "LINKED_TO",direction: "BOTH" })知道兩個用戶可能會通過這種虛假關系聯系起來,這將使我們對他們未來可能購買的產品有所了解。但是,它還不是用戶和產品之間的鏈接預測問題。
為此,我們需要在產品和用戶之間創建一種新的關系,這正好與這種BOUGHT關系相反:
MATCH (p:Product)<-[:BOUGHT]-(u:User) CREATE (p)-[:LINKED_TO]->(u)有了這些新關系,我們的圖表如下所示:
我們現在可以使用以下查詢來獲取用戶和產品之間鏈接的預測分數:
MATCH (u:User) MATCH (p:Product) WHERE NOT EXISTS ( (u)-[:BOUGHT]->(p) ) WITH u.name as user, p.name as product, gds.alpha.linkprediction.commonNeighbors(u, p, {relationshipQuery: "LINKED_TO",direction: "BOTH" }) as score RETURN user, product, score ORDER BY score DESC結果在下表中重現:
╒══════╤═════════╤═══════╕ │"user"│"product"│"score"│ ╞══════╪═════════╪═══════╡ │"u3" │"p1" │2.0 │ ├──────┼─────────┼───────┤ │"u2" │"p2" │2.0 │ ├──────┼─────────┼───────┤ │"u1" │"p3" │2.0 │ ├──────┼─────────┼───────┤ │"u4" │"p1" │1.0 │ ├──────┼─────────┼───────┤ │"u4" │"p3" │1.0 │ └──────┴─────────┴───────┘我們來分析一下這個結果:
- u3連接到u2和u1,他們都購買了產品p1,所以u3和之間的共同鄰居數p1為 2。
- u4并且p1有一個共同的鄰居,u1,因為另一個鄰居p1是u2并且u2不連接到,所以和p1之間的關系得分為 1。u4p1
我們在commonNeighbors這里使用了該算法,因為它更容易分析結果,但是我們在本章中看到的任何其他鏈接預測函數都可以實現同樣的效果。
概括
閱讀本章后,您應該對鏈接預測的含義以及如何使用它來解決許多與圖相關的問題有了更清晰的理解。您還應該知道可以使用哪種指標來預測鏈接將來在兩個節點之間出現的可能性。最后,您從頭構建了一個鏈接預測問題,了解它與經典數據科學問題的不同之處,并學習了如何成功構建預測模型以預測圖中的新關系。
到目前為止,我們已經學會了如何根據我們的數據形成圖形結構這一事實來構建特征。了解圖結構和這些特征的預測能力是重要的一步。然而,現代機器學習技術傾向于避免算法自動學習特征的特征工程步驟,稱為嵌入。將這種技術應用于圖形是我們將在下一章中介紹的主題。
問題
- 嘗試 GDS 插件中的其他鏈接預測算法
進一步閱讀
- 復雜網絡中的鏈接預測:調查:https ://arxiv.org/abs/1010.0725
- 關于生物學和基因-疾病關系的鏈接預測的論文:
https ://bigdata.oden.utexas.edu/publication/prediction-and-validation-of-gene-disease-associations-using-methods-inspired-by-social?-網絡分析/ - 犯罪背景下的鏈接預測:
https ://www.ncbi.nlm.nih.gov/pmc/articles/PMC4841537/ - 推特上的鏈接預測:WTF:推特上的關注者服務:
https ://dl.acm.org/doi/10.1145/2488388.2488433 - Katz 指數計算(2019 年的論文):
https ://arxiv.org/abs/1912.06525
總結
以上是生活随笔為你收集整理的【Neo4j】第 9 章:预测关系的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【2019-08-14】慢慢来,才叫快
- 下一篇: 在自己的app中打开淘宝