如何在Python中对图形进行集群?

如何在Python中对图形进行集群?,python,sorting,matrix,cluster-analysis,graph-theory,Python,Sorting,Matrix,Cluster Analysis,Graph Theory,设G是一个图。所以G是一组节点和一组链接。我需要找到一种快速的方法来划分图形。我现在正在处理的图只有120*160个节点,但我可能很快就会处理一个同等的问题,在另一个环境中(不是医学,而是网站开发),有数百万个节点 因此,我所做的是将所有链接存储到一个图形矩阵中: M=numpy.mat(numpy.zeros((len(data.keys()),len(data.keys())))) 如果节点s连接到节点t,那么M在位置s,t中保持1。我确保M是对称的M[s,t]=M[t,s],并且每个节点

设G是一个图。所以G是一组节点和一组链接。我需要找到一种快速的方法来划分图形。我现在正在处理的图只有120*160个节点,但我可能很快就会处理一个同等的问题,在另一个环境中(不是医学,而是网站开发),有数百万个节点

因此,我所做的是将所有链接存储到一个图形矩阵中:

M=numpy.mat(numpy.zeros((len(data.keys()),len(data.keys()))))
如果节点s连接到节点t,那么M在位置s,t中保持1。我确保M是对称的M[s,t]=M[t,s],并且每个节点都链接到自己的M[s,s]=1

如果我记得很清楚,如果我用M乘以M,结果是一个矩阵,表示通过两个步骤连接顶点的图形

所以我继续对它本身进行多重叠加,直到矩阵中的零的数量不再减少。现在我有了连接组件的列表。 现在我需要对这个矩阵进行聚类

到目前为止,我对算法相当满意。我认为它简单、优雅,而且相当快。这部分我有问题

本质上,我需要将这个图拆分为它的连接组件

我可以浏览所有节点,看看它们连接到什么

但是对矩阵进行排序,对行进行重新排序呢。但我不知道是否有可能做到这一点

以下是迄今为止的代码:

def findzeros(M):
    nZeros=0
    for t in M.flat:
        if not t:
            nZeros+=1
    return nZeros

M=numpy.mat(numpy.zeros((len(data.keys()),len(data.keys()))))    
for s in data.keys():
    MatrixCells[s,s]=1
    for t in data.keys():
        if t<s:
            if (scipy.corrcoef(data[t],data[s])[0,1])>threashold:
                M[s,t]=1
                M[t,s]=1

nZeros=findzeros(M)
M2=M*M
nZeros2=findzeros(M2)

while (nZeros-nZeros2):
    nZeros=nZeros2
    M=M2
    M2=M*M
    nZeros2=findzeros(M2)
这里基本上有4个集群:(0)、(1,3)、(2)、(4) 但我仍然不知道svn在这方面有什么帮助。

在SciPy中,您可以使用。还要注意的是,有更有效的方法将矩阵本身相乘。无论如何,你要做的事情可以通过SVD分解来完成


为什么不使用真正的图形库,比如?它有一个示例(尽管没有提供示例)。我可以想象,一个专用的库将比您编写的任何特殊图形代码都要快


编辑:看起来它可能是比python图形更好的选择;当然是这样。

看起来有一个库,它将根据链接列表为您划分图形。通过将链接节点的原始列表(而不是矩阵乘以导出的列表)传递给图,从图中提取链接列表应该相当容易

重复执行M'=MM对于M的大阶而言是无效的。对于N阶矩阵的全矩阵乘法将花费N次乘法和N-1次加法,其中有N2次,即O(N3)次运算。如果要将其扩展到“数百万个节点”,则每个矩阵乘法将执行O(1018)个操作,其中您需要执行几个操作


简而言之,你不想这样做。来自瓦特克的援助将是那里唯一合适的选择。最好的选择是只使用PyMetis,而不是尝试重新创建图形分区

这里有一些简单的实现,它使用我不久前写过的代码查找连接的组件。虽然它非常简单,但它可以很好地扩展到上万个顶点和边


import sys
from operator import gt, lt

class Graph(object):
    def __init__(self):
        self.nodes = set()
        self.edges = {}
        self.cluster_lookup = {}
        self.no_link = {}

    def add_edge(self, n1, n2, w):
        self.nodes.add(n1)
        self.nodes.add(n2)
        self.edges.setdefault(n1, {}).update({n2: w})
        self.edges.setdefault(n2, {}).update({n1: w})

    def connected_components(self, threshold=0.9, op=lt):
        nodes = set(self.nodes)
        components, visited = [], set()
        while len(nodes) > 0:
            connected, visited = self.dfs(nodes.pop(), visited, threshold, op)
            connected = set(connected)
            for node in connected:
                if node in nodes:
                    nodes.remove(node)

            subgraph = Graph()
            subgraph.nodes = connected
            subgraph.no_link = self.no_link
            for s in subgraph.nodes:
                for k, v in self.edges.get(s, {}).iteritems():
                    if k in subgraph.nodes:
                        subgraph.edges.setdefault(s, {}).update({k: v})
                if s in self.cluster_lookup:
                    subgraph.cluster_lookup[s] = self.cluster_lookup[s]

            components.append(subgraph)
        return components

    def dfs(self, v, visited, threshold, op=lt, first=None):
        aux = [v]
        visited.add(v)
        if first is None:
            first = v
        for i in (n for n, w in self.edges.get(v, {}).iteritems()
                  if op(w, threshold) and n not in visited):
            x, y = self.dfs(i, visited, threshold, op, first)
            aux.extend(x)
            visited = visited.union(y)
        return aux, visited

def main(args):
    graph = Graph()
    # first component
    graph.add_edge(0, 1, 1.0)
    graph.add_edge(1, 2, 1.0)
    graph.add_edge(2, 0, 1.0)

    # second component
    graph.add_edge(3, 4, 1.0)
    graph.add_edge(4, 5, 1.0)
    graph.add_edge(5, 3, 1.0)

    first, second = graph.connected_components(op=gt)
    print first.nodes
    print second.nodes

if __name__ == '__main__':
    main(sys.argv)

SVD算法在这里不适用,但在其他方面Phil H是正确的

正如其他人所指出的,没有必要重新发明轮子。人们对最优聚类技术进行了大量的研究。是一个著名的聚类程序。

找到一个最优的图划分是一个NP难问题,因此无论采用何种算法,它都将是一个近似或启发式问题。毫不奇怪,不同的聚类算法会产生(大范围)不同的结果

纽曼模块化算法的Python实现:

另外:,

还有和,它们对连接的组件具有有效的例程,并且都有效地存储网络。如果要处理数百万个节点,networkx可能不够(它是纯python afaik)。这两种工具都是用C++编写的,因此可以处理合理运行时间的大型图形分析。
正如Phil指出的,对于大型图,您的方法的计算时间将非常长(我们谈论的是天、周、月……),而对于一百万个节点的图,您的表示将需要大约一百万GB的内存

多谢各位。我查阅了资源,但我真的不知道它有什么帮助。我用一个简单的例子更新了这个问题,以及SVN des似乎无法解决这个问题。也许我用错了?那怎么办呢?无论如何谢谢:)这就是SVD(单值分解)。基本上,对于数百万个节点这样大的对象,需要近似算法,而不是精确算法(图聚类是NP完全的)。文章得到了解释这些算法的文章的链接。你是想重新创造PageRank或点击率吗?不是真的。现在只需对属于哪个生物细胞的数据进行排序。在未来,我有一个类似的问题,最终将生成一个搜索引擎。但不是在书页上。不使用链接。(在这个阶段不能再多说了:))。无论如何,祝贺你!好的,哈哈。那么潜在的语义分析呢?;-)好吧,我不会扯你的舌头。请记住,小规模可能发生的事情在大规模时变得非常复杂。大多数图算法都有很高的多项式复杂度,所以在1mln节点上使用它是非常困难的。你能澄清一下你的问题吗。我发现了一个“可能吗”(答案总是肯定的,所以这不是你真正的问题)和一个“我不知道SVD能帮上什么忙”,这不是一个真正的问题。你的问题是什么?你好,谢谢你花时间回答我的问题。问题是,明确的是:“我应该如何确定连接的成分?”我以为你理解它,以及在哪里有一些天真的乐趣。“Pietro Speroni:考虑重写你的问题,使它更简单,更集中和更清楚。”长时间的讨论很难跟上。简短的代码示例和一个非常明显的问题更好。您提供了一些代码,所以问“我应该如何确定…”似乎是不对的。谢谢您,但既然我确实收到了答案,我是l

import sys
from operator import gt, lt

class Graph(object):
    def __init__(self):
        self.nodes = set()
        self.edges = {}
        self.cluster_lookup = {}
        self.no_link = {}

    def add_edge(self, n1, n2, w):
        self.nodes.add(n1)
        self.nodes.add(n2)
        self.edges.setdefault(n1, {}).update({n2: w})
        self.edges.setdefault(n2, {}).update({n1: w})

    def connected_components(self, threshold=0.9, op=lt):
        nodes = set(self.nodes)
        components, visited = [], set()
        while len(nodes) > 0:
            connected, visited = self.dfs(nodes.pop(), visited, threshold, op)
            connected = set(connected)
            for node in connected:
                if node in nodes:
                    nodes.remove(node)

            subgraph = Graph()
            subgraph.nodes = connected
            subgraph.no_link = self.no_link
            for s in subgraph.nodes:
                for k, v in self.edges.get(s, {}).iteritems():
                    if k in subgraph.nodes:
                        subgraph.edges.setdefault(s, {}).update({k: v})
                if s in self.cluster_lookup:
                    subgraph.cluster_lookup[s] = self.cluster_lookup[s]

            components.append(subgraph)
        return components

    def dfs(self, v, visited, threshold, op=lt, first=None):
        aux = [v]
        visited.add(v)
        if first is None:
            first = v
        for i in (n for n, w in self.edges.get(v, {}).iteritems()
                  if op(w, threshold) and n not in visited):
            x, y = self.dfs(i, visited, threshold, op, first)
            aux.extend(x)
            visited = visited.union(y)
        return aux, visited

def main(args):
    graph = Graph()
    # first component
    graph.add_edge(0, 1, 1.0)
    graph.add_edge(1, 2, 1.0)
    graph.add_edge(2, 0, 1.0)

    # second component
    graph.add_edge(3, 4, 1.0)
    graph.add_edge(4, 5, 1.0)
    graph.add_edge(5, 3, 1.0)

    first, second = graph.connected_components(op=gt)
    print first.nodes
    print second.nodes

if __name__ == '__main__':
    main(sys.argv)