在python中生成图形时的高内存消耗

时间:2014-04-30 02:47:35

标签: python graph

我使用python从文件生成图表。 当我运行我的代码时,它使用了大约7 GB的内存! (图表有1,600,00个节点)

输入文件是这样的:

1 2
1 3
1 4
2 4

每行代表一条边。在这个例子中,我们有4个节点和4个边。

这是我的代码:

class Graph(object):

    def __init__(self):
        self.node_list = []
        self.edge = []
        self.neighbors = {}
        with open(infile, "r") as source_file:
            for row in csv.reader(source_file, delimiter='\t'):
                self.node_list.append(int(row[0]))
                self.node_list.append(int(row[1]))
                self.edge.append(row)
        for node in self.edge:
            if node[0] in self.neighbors:
                self.neighbors[node[0]].append(node[1])
            else:
                self.neighbors[node[0]] = [node[1]]
            if node[1] in self.neighbors:
                self.neighbors[node[1]].append(node[0])
            else:
               self.neighbors[node[1]] = [node[0]]
        self.node_list = list(set(self.node_list))

g = Graph()

提前致谢。

3 个答案:

答案 0 :(得分:2)

一旦__init__运行,IMHO self.node_list就没用了。你不应该把它绑在自己身上。 此外,我无法理解为什么你需要self.edge这种格式。你可能根本不需要它。

self.neighbors可能提供了一个足够好的图表descritpion。

答案 1 :(得分:2)

您以错误的方式使用了错误的数据结构。

您的代码在节点列表中创建了大量冗余条目。使用您的示例,节点列表将是:

[1, 2, 1, 3, 1, 4, 2, 4]

当处理1' 600'节点时,将大大增加您的数据需求。然后在self.edge中存储一个从未发布的输入文件的完整副本。

你甚至不需要为你正在做的事情上课:

import collections

graph = collections.defaultdict(list)
with open(infile) as inf:
    for line in inf.read():
        p, q = line.split()
        if p not in graph[q]:
            graph[q].append(p)
        if q not in graph[p]:
            graph[p].append(q)

graph现在包含输入文件的最小表示形式。这是一个运作良好的rather old pattern。如果您想在创建图表后对其执行任何操作,则可能会发现NetworkX这样的包非常有用。

答案 2 :(得分:1)

您可以使用此解决方案或其变体来提高内存使用率。 试一下。

我们的想法是将每个节点与一个整数序号标记相关联 并使用该标记访问包含neighors列表的列表。

import csv 
class Graph(object):
        def __init__(self,infile):
        tags = {} 
        self.neighbors = []
        with open(infile, "r") as source_file:
            for row in csv.reader(source_file, delimiter=' '):
            node1 = int(row[0]) 
            node2 = int(row[1]) 
            if node1 not in tags:
                tags[node1] = len(tags) 
                self.neighbors.append([])
            if node2 not in tags:
                tags[node2] = len(tags) 
                self.neighbors.append([])
            self.neighbors[tags[node1]].append(tags[node2])  
            self.neighbors[tags[node2]].append(tags[node1])  
    def getNodes(self):
        return xrange(len(self.neighbors))
    def getNeighs(self,i):
        return self.neighbors[i]
g = Graph('infile.txt')

print "MyNodes:\n ",
print [i for i in g.getNodes()] 
print 'myNeighs\n ', 
for i in g.getNodes(): 
    print g.getNeighs(i),

让我展示一个可能的变种。请注意,在这两种情况下 字典'标签'可以在之后被垃圾收集(即删除) __init__已经运行,因为没有引用它。你离开了 仅限列表。

import csv 
class Graph2(object):
        def __init__(self,infile):
        tags = {} 
        self.inverseTags = [] 
        self.neighbors = []
        with open(infile, "r") as source_file:
            for row in csv.reader(source_file, delimiter=' '):
            node1 = int(row[0]) 
            node2 = int(row[1]) 
            if node1 not in tags:
                tags[node1] = len(tags) 
                self.neighbors.append([])
                self.inverseTags.append(node1)
            if node2 not in tags:
                tags[node2] = len(tags) 
                self.neighbors.append([])
                self.inverseTags.append(node2)
            self.neighbors[tags[node1]].append(tags[node2])  
            self.neighbors[tags[node2]].append(tags[node1])  
    def getNodes(self):
        return xrange(len(self.neighbors))
    def getNodesOriginalNames(self):
        return (self.inverseTags[i] for i in xrange(len(self.neighbors)))
    def getNeighs(self,i):
        return self.neighbors[i]
    def getNeighsOriginalName(self,i):
        return [self.inverseTags[j] for j in self.neighbors[i]]
g = Graph2('infile.txt')

print "MyNodes:\n ",
print [i for i in g.getNodesOriginalNames()] 
print 'myNeighs\n ', 
for i in g.getNodes(): 
    print g.getNeighsOriginalName(i),

当然,如果在你的csv文件中,节点的名称已经从零开始了 您可以保存__init__所做的所有翻译工作。