图形处理:betweeness中心性– neo4j的密码与graphstream
上周, 我寫了關于中間性中心性算法以及使用graphstream 理解它的嘗試 ,在閱讀源代碼時,我意識到我可以使用neo4j的所有最短路徑算法將某些東西放在一起。
概括地說,中間性中心度算法用于確定圖中節點的負載和重要性。
在與Jen討論這一點時,她指出,計算整個圖上節點之間的中間性通常是沒有意義的。 但是,了解在您感興趣的較小子圖中哪個節點最重要可能很有用。
在這種情況下,我有興趣在一個非常小的有向圖中確定節點的中間性:
讓我們簡要回顧一下算法:
[中間性中心]等于從所有頂點到經過該節點的所有其他頂點的最短路徑數。這意味著我們排除了直接在兩個節點之間而不經過任何其他路徑的任何路徑,這是我最初沒有掌握的。
如果我們手工確定適用的路徑,我們將得到以下結果:
A -> B: Direct Path Exists A -> C: B A -> D: E A -> E: Direct Path Exists B -> A: No Path Exists B -> C: Direct Path Exists B -> D: E or C B -> E: Direct Path Exists C -> A: No Path Exists C -> B: No Path Exists C -> D: Direct Path Exists C -> E: No Path Exists D -> A: No Path Exists D -> B: No Path Exists D -> C: No Path Exists D -> E: No Path Exists E -> A: No Path Exists E -> B: No Path Exists E -> C: No Path Exists E -> D: Direct Path Exists給出以下中間性中心值:
A: 0 B: 1 C: 0.5 D: 0 E: 1.5我們可以針對最新版本的graphstream (考慮方向)編寫測試,以確認我們的手動算法:
@Testpublic void calculateBetweennessCentralityOfMySimpleGraph() {Graph graph = new SingleGraph("Tutorial 1");Node A = graph.addNode("A");Node B = graph.addNode("B");Node E = graph.addNode("E");Node C = graph.addNode("C");Node D = graph.addNode("D");graph.addEdge("AB", A, B, true);graph.addEdge("BE", B, E, true);graph.addEdge("BC", B, C, true);graph.addEdge("ED", E, D, true);graph.addEdge("CD", C, D, true);graph.addEdge("AE", A, E, true);BetweennessCentrality bcb = new BetweennessCentrality();bcb.computeEdgeCentrality(false);bcb.betweennessCentrality(graph);System.out.println("A="+ A.getAttribute("Cb"));System.out.println("B="+ B.getAttribute("Cb"));System.out.println("C="+ C.getAttribute("Cb"));System.out.println("D="+ D.getAttribute("Cb"));System.out.println("E="+ E.getAttribute("Cb"));}輸出是預期的:
A=0.0 B=1.0 C=0.5 D=0.0 E=1.5我想看看是否可以使用neo4j做同樣的事情,所以我使用以下cypher語句在空白數據庫中創建了圖形:
CREATE (A {name: "A"}) CREATE (B {name: "B"}) CREATE (C {name: "C"}) CREATE (D {name: "D"}) CREATE (E {name: "E"})CREATE A-[:TO]->E CREATE A-[:TO]->B CREATE B-[:TO]->C CREATE B-[:TO]->E CREATE C-[:TO]->D CREATE E-[:TO]->D然后,我編寫了一個查詢,該查詢找到了圖中所有節點集之間的最短路徑:
MATCH p = allShortestPaths(source-[r:TO*]->destination) WHERE source <> destination RETURN NODES(p)如果運行,它將返回以下內容:
==> +---------------------------------------------------------+ ==> | NODES(p) | ==> +---------------------------------------------------------+ ==> | [Node[1]{name:"A"},Node[2]{name:"B"}] | ==> | [Node[1]{name:"A"},Node[2]{name:"B"},Node[3]{name:"C"}] | ==> | [Node[1]{name:"A"},Node[5]{name:"E"},Node[4]{name:"D"}] | ==> | [Node[1]{name:"A"},Node[5]{name:"E"}] | ==> | [Node[2]{name:"B"},Node[3]{name:"C"}] | ==> | [Node[2]{name:"B"},Node[3]{name:"C"},Node[4]{name:"D"}] | ==> | [Node[2]{name:"B"},Node[5]{name:"E"},Node[4]{name:"D"}] | ==> | [Node[2]{name:"B"},Node[5]{name:"E"}] | ==> | [Node[3]{name:"C"},Node[4]{name:"D"}] | ==> | [Node[5]{name:"E"},Node[4]{name:"D"}] | ==> +---------------------------------------------------------+ ==> 10 rows我們仍在返回節點之間的直接鏈接,但是通過基于路徑中節點的數量過濾結果可以很容易地糾正這一點:
MATCH p = allShortestPaths(source-[r:TO*]->destination) WHERE source <> destination AND LENGTH(NODES(p)) > 2 RETURN EXTRACT(n IN NODES(p): n.name)==> +--------------------------------+ ==> | EXTRACT(n IN NODES(p): n.name) | ==> +--------------------------------+ ==> | ["A","B","C"] | ==> | ["A","E","D"] | ==> | ["B","C","D"] | ==> | ["B","E","D"] | ==> +--------------------------------+ ==> 4 rows如果我們稍微調整密碼查詢,我們可以獲得每個源/目標的最短路徑的集合:
MATCH p = allShortestPaths(source-[r:TO*]->destination) WHERE source <> destination AND LENGTH(NODES(p)) > 2 WITH EXTRACT(n IN NODES(p): n.name) AS nodes RETURN HEAD(nodes) AS source, HEAD(TAIL(TAIL(nodes))) AS destination, COLLECT(nodes) AS paths==> +------------------------------------------------------+ ==> | source | destination | paths | ==> +------------------------------------------------------+ ==> | "A" | "D" | [["A","E","D"]] | ==> | "A" | "C" | [["A","B","C"]] | ==> | "B" | "D" | [["B","C","D"],["B","E","D"]] | ==> +------------------------------------------------------+ ==> 3 rows當我們有一種使用cypher來對集合進行切片的方法時,從這里獲得節點間的中間性得分并不難,但是現在使用通用的編程語言要容易得多。
在這種情況下,我使用了Ruby并提出了以下代碼:
require 'neography' neo = Neography::Rest.newquery = " MATCH p = allShortestPaths(source-[r:TO*]->destination)" query << " WHERE source <> destination AND LENGTH(NODES(p)) > 2" query << " WITH EXTRACT(n IN NODES(p): n.name) AS nodes" query << " RETURN HEAD(nodes) AS source, HEAD(TAIL(TAIL(nodes))) AS destination, COLLECT(nodes) AS paths"betweenness_centrality = { "A" => 0, "B" => 0, "C" => 0, "D" => 0, "E" => 0 }neo.execute_query(query)["data"].map { |row| row[2].map { |path| path[1..-2] } }.each do |potential_central_nodes| number_of_central_nodes = potential_central_nodes.sizepotential_central_nodes.each do |nodes|nodes.each { |node| betweenness_centrality[node] += (1.0 / number_of_central_nodes) }end endp betweenness_centrality輸出以下內容:
$ bundle exec ruby centrality.rb {"A"=>0, "B"=>1.0, "C"=>0.5, "D"=>0, "E"=>1.5}它似乎可以完成任務,但是我敢肯定,在某些情況下,它無法處理成熟的庫需要處理的問題。 作為一個實驗,看看有什么可能,我認為還算不錯!
該圖位于neo4j控制臺上 ,以防有人感興趣。
翻譯自: https://www.javacodegeeks.com/2013/08/graph-processing-betweeness-centrality-neo4js-cypher-vs-graphstream.html
總結
以上是生活随笔為你收集整理的图形处理:betweeness中心性– neo4j的密码与graphstream的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 爱的希望爱的回味是什么歌 爱的希望爱的回
- 下一篇: 稀硫酸除铁锈的化学方程式 稀硫酸除铁锈的