当前位置:   article > 正文

图形处理:betweeness中心性– neo4j的密码与graphstream

betweeness中心性

上周, 我写了关于中间性中心性算法以及使用graphstream 理解它的尝试 ,在阅读源代码时,我意识到我可以使用neo4j所有最短路径算法将某些东西放在一起。

概括地说,中间性中心度算法用于确定图中节点的负载和重要性。

在与Jen讨论这一点时,她指出,计算整个图上节点之间的中间性通常是没有意义的。 但是,了解在您感兴趣的较小子图中哪个节点最重要可能很有用。

在这种情况下,我有兴趣在一个非常小的有向图中确定节点的中间性:

betweeness2

让我们简要回顾一下算法:

[中间性中心]等于从所有顶点到经过该节点的所有其他顶点的最短路径数。

这意味着我们排除了直接在两个节点之间而不经过任何其他路径的任何路径,这是我最初没有掌握的。

如果我们手工确定适用的路径,我们将得到以下结果:

  1. A -> B: Direct Path Exists
  2. A -> C: B
  3. A -> D: E
  4. A -> E: Direct Path Exists
  5. B -> A: No Path Exists
  6. B -> C: Direct Path Exists
  7. B -> D: E or C
  8. B -> E: Direct Path Exists
  9. C -> A: No Path Exists
  10. C -> B: No Path Exists
  11. C -> D: Direct Path Exists
  12. C -> E: No Path Exists
  13. D -> A: No Path Exists
  14. D -> B: No Path Exists
  15. D -> C: No Path Exists
  16. D -> E: No Path Exists
  17. E -> A: No Path Exists
  18. E -> B: No Path Exists
  19. E -> C: No Path Exists
  20. E -> D: Direct Path Exists

给出以下中间性中心值:

  1. A: 0
  2. B: 1
  3. C: 0.5
  4. D: 0
  5. E: 1.5

我们可以针对最新版本的graphstream (考虑方向)编写测试,以确认我们的手动算法:

  1. @Test
  2. public void calculateBetweennessCentralityOfMySimpleGraph() {
  3. Graph graph = new SingleGraph("Tutorial 1");
  4. Node A = graph.addNode("A");
  5. Node B = graph.addNode("B");
  6. Node E = graph.addNode("E");
  7. Node C = graph.addNode("C");
  8. Node D = graph.addNode("D");
  9. graph.addEdge("AB", A, B, true);
  10. graph.addEdge("BE", B, E, true);
  11. graph.addEdge("BC", B, C, true);
  12. graph.addEdge("ED", E, D, true);
  13. graph.addEdge("CD", C, D, true);
  14. graph.addEdge("AE", A, E, true);
  15. BetweennessCentrality bcb = new BetweennessCentrality();
  16. bcb.computeEdgeCentrality(false);
  17. bcb.betweennessCentrality(graph);
  18. System.out.println("A="+ A.getAttribute("Cb"));
  19. System.out.println("B="+ B.getAttribute("Cb"));
  20. System.out.println("C="+ C.getAttribute("Cb"));
  21. System.out.println("D="+ D.getAttribute("Cb"));
  22. System.out.println("E="+ E.getAttribute("Cb"));
  23. }

输出是预期的:

  1. A=0.0
  2. B=1.0
  3. C=0.5
  4. D=0.0
  5. E=1.5

我想看看是否可以使用neo4j做同样的事情,所以我使用以下cypher语句在空白数据库中创建了图形:

  1. CREATE (A {name: "A"})
  2. CREATE (B {name: "B"})
  3. CREATE (C {name: "C"})
  4. CREATE (D {name: "D"})
  5. CREATE (E {name: "E"})
  6. CREATE A-[:TO]->E
  7. CREATE A-[:TO]->B
  8. CREATE B-[:TO]->C
  9. CREATE B-[:TO]->E
  10. CREATE C-[:TO]->D
  11. CREATE E-[:TO]->D

然后,我编写了一个查询,该查询找到了图中所有节点集之间的最短路径

  1. MATCH p = allShortestPaths(source-[r:TO*]->destination)
  2. WHERE source <> destination
  3. RETURN NODES(p)

如果运行,它将返回以下内容:

  1. ==> +---------------------------------------------------------+
  2. ==> | NODES(p) |
  3. ==> +---------------------------------------------------------+
  4. ==> | [Node[1]{name:"A"},Node[2]{name:"B"}] |
  5. ==> | [Node[1]{name:"A"},Node[2]{name:"B"},Node[3]{name:"C"}] |
  6. ==> | [Node[1]{name:"A"},Node[5]{name:"E"},Node[4]{name:"D"}] |
  7. ==> | [Node[1]{name:"A"},Node[5]{name:"E"}] |
  8. ==> | [Node[2]{name:"B"},Node[3]{name:"C"}] |
  9. ==> | [Node[2]{name:"B"},Node[3]{name:"C"},Node[4]{name:"D"}] |
  10. ==> | [Node[2]{name:"B"},Node[5]{name:"E"},Node[4]{name:"D"}] |
  11. ==> | [Node[2]{name:"B"},Node[5]{name:"E"}] |
  12. ==> | [Node[3]{name:"C"},Node[4]{name:"D"}] |
  13. ==> | [Node[5]{name:"E"},Node[4]{name:"D"}] |
  14. ==> +---------------------------------------------------------+
  15. ==> 10 rows

我们仍在返回节点之间的直接链接,但是通过基于路径中节点的数量过滤结果可以很容易地纠正这一点:

  1. MATCH p = allShortestPaths(source-[r:TO*]->destination)
  2. WHERE source <> destination AND LENGTH(NODES(p)) > 2
  3. RETURN EXTRACT(n IN NODES(p): n.name)
  1. ==> +--------------------------------+
  2. ==> | EXTRACT(n IN NODES(p): n.name) |
  3. ==> +--------------------------------+
  4. ==> | ["A","B","C"] |
  5. ==> | ["A","E","D"] |
  6. ==> | ["B","C","D"] |
  7. ==> | ["B","E","D"] |
  8. ==> +--------------------------------+
  9. ==> 4 rows

如果我们稍微调整密码查询,我们可以获得每个源/目标的最短路径的集合:

  1. MATCH p = allShortestPaths(source-[r:TO*]->destination)
  2. WHERE source <> destination AND LENGTH(NODES(p)) > 2
  3. WITH EXTRACT(n IN NODES(p): n.name) AS nodes
  4. RETURN HEAD(nodes) AS source,
  5. HEAD(TAIL(TAIL(nodes))) AS destination,
  6. COLLECT(nodes) AS paths
  1. ==> +------------------------------------------------------+
  2. ==> | source | destination | paths |
  3. ==> +------------------------------------------------------+
  4. ==> | "A" | "D" | [["A","E","D"]] |
  5. ==> | "A" | "C" | [["A","B","C"]] |
  6. ==> | "B" | "D" | [["B","C","D"],["B","E","D"]] |
  7. ==> +------------------------------------------------------+
  8. ==> 3 rows

当我们有一种使用cypher来对集合进行切片的方法时,从这里获得节点间的中间性得分并不难,但是现在使用通用的编程语言要容易得多。

在这种情况下,我使用了Ruby并提出了以下代码:

  1. require 'neography'
  2. neo = Neography::Rest.new
  3. query = " MATCH p = allShortestPaths(source-[r:TO*]->destination)"
  4. query << " WHERE source <> destination AND LENGTH(NODES(p)) > 2"
  5. query << " WITH EXTRACT(n IN NODES(p): n.name) AS nodes"
  6. query << " RETURN HEAD(nodes) AS source, HEAD(TAIL(TAIL(nodes))) AS destination, COLLECT(nodes) AS paths"
  7. betweenness_centrality = { "A" => 0, "B" => 0, "C" => 0, "D" => 0, "E" => 0 }
  8. neo.execute_query(query)["data"].map { |row| row[2].map { |path| path[1..-2] } }.each do |potential_central_nodes|
  9. number_of_central_nodes = potential_central_nodes.size
  10. potential_central_nodes.each do |nodes|
  11. nodes.each { |node| betweenness_centrality[node] += (1.0 / number_of_central_nodes) }
  12. end
  13. end
  14. p betweenness_centrality

输出以下内容:

  1. $ bundle exec ruby centrality.rb
  2. {"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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/627199
推荐阅读
相关标签
  

闽ICP备14008679号