Python 将1.2GB边列表转换为稀疏矩阵
我有一个1.2GB的文本文件中图形的边列表。我的ubuntu电脑有8GB内存。输入中的每一行看起来像Python 将1.2GB边列表转换为稀疏矩阵,python,pandas,numpy,optimization,scipy,Python,Pandas,Numpy,Optimization,Scipy,我有一个1.2GB的文本文件中图形的边列表。我的ubuntu电脑有8GB内存。输入中的每一行看起来像 287111206 357850135 我想将其转换为稀疏邻接矩阵,并将其输出到文件中 我的数据的一些统计数据: Number of edges: around 62500000 Number of vertices: around 31250000 我以前也问过同样的问题,得到了很好的回答。问题是我不能让它工作 我第一次尝试在文件中加载np.loadtxt,但速度非常慢,占用了大量内存。因
287111206 357850135
我想将其转换为稀疏邻接矩阵,并将其输出到文件中
我的数据的一些统计数据:
Number of edges: around 62500000
Number of vertices: around 31250000
我以前也问过同样的问题,得到了很好的回答。问题是我不能让它工作
我第一次尝试在文件中加载np.loadtxt,但速度非常慢,占用了大量内存。因此,我转而选择pandas.read_csv,它的速度非常快,但这也导致了它自身的问题。这是我当前的代码:
import pandas
import numpy as np
from scipy import sparse
data = pandas.read_csv("edges.txt", sep=" ", header= None, dtype=np.uint32)
A = data.as_matrix()
print type(A)
k1,k2,k3=np.unique(A,return_inverse=True,return_index=True)
rows,cols=k3.reshape(A.shape).T
M=sparse.coo_matrix((np.ones(rows.shape,int),(rows,cols)))
print type(M)
问题是熊猫数据帧<代码>数据代码>非常庞大,我实际上是在一个低效率的环境中进行复制。然而,随着代码崩溃,情况更加糟糕
<type 'instancemethod'>
Traceback (most recent call last):
File "make-sparse-matrix.py", line 13, in <module>
rows,cols=k3.reshape(A.shape).T
AttributeError: 'function' object has no attribute 'shape'
raph@raph-desktop:~/python$ python make-sparse-matrix.py
<type 'numpy.ndarray'>
Traceback (most recent call last):
File "make-sparse-matrix.py", line 12, in <module>
k1,k2,k3=np.unique(A,return_inverse=True,return_index=True)
File "/usr/local/lib/python2.7/dist-packages/numpy/lib/arraysetops.py", line 209, in unique
iflag = np.cumsum(flag) - 1
File "/usr/local/lib/python2.7/dist-packages/numpy/core/fromnumeric.py", line 2115, in cumsum
return cumsum(axis, dtype, out)
MemoryError
更新
我现在尝试了许多不同的方法,但都失败了。这里是一个总结
g=Graph.Read\u Ncol('edges.txt')
一起使用。这使用了大量的RAM,使我的计算机崩溃G=networkit.graphio.readGraph(“edges.txt”)一起使用,
networkit.Format.EdgeList,分隔符=”,continuous=False)
。这使用了大量的RAM,使我的计算机崩溃g=Graph.Read\u Edgelist(“edges contig.txt”)
。尽管需要4GB的RAM(这比理论上应该的数量要多得多),但现在它仍然可以工作。然而,没有igraph函数可以从图中写出稀疏邻接矩阵。建议的解决方案是。不幸的是,这使用了大量的内存,使我的计算机崩溃G=networkit.readGraph(“edges contig.txt”,networkit.Format.EdgeListSpaceOne)
。这也可以使用少于igraph所需4GB的内存。networkit还提供了一个编写Matlab文件的函数(这是scipy可以读取的稀疏邻接矩阵的一种形式)。然而,networkit.graphio.writeMat(G,“test.mat”)
使用了大量RAM,使我的计算机崩溃- 使用pandas读取数据(而不是numpy:我很惊讶np.loadtxt的性能如此糟糕!)
- 使用外部库实现更高效的内存方法(而不是字典)
- 基本方法是相同的
import random
N = 62500000
for i in xrange(N):
print random.randint(10**8,10**9-1), random.randint(10**8,10**9-1)
代码
第一版
这里有一个非常简单的和非常低效的(关于时间和空间)代码来构建这个稀疏矩阵。我发布这段代码,因为我相信,如果在更大的应用中使用这些核心部分,理解它们是很重要的
让我们看看,这段代码对于您的用例是否足够有效,或者它是否需要工作。从远处很难说,因为我们没有你的数据
用于映射的字典部分可能会破坏您的记忆。但是,在不知道是否需要的情况下对其进行优化是毫无意义的。特别是因为代码的这一部分依赖于图中的顶点数(我对这个基数一无所知)
edges-10.txt的输出:
[[287111206 357850135]
[512616930 441657273]
[530905858 562056765]
[524113870 320749289]
[149911066 964526673]
[169873523 631128793]
[646151040 986572427]
[105290138 382302570]
[194873438 968653053]
[912211115 195436728]]
(10, 2)
[[ 0 10]
[ 1 11]
[ 2 12]
[ 3 13]
[ 4 14]
[ 5 15]
[ 6 16]
[ 7 17]
[ 8 18]
[ 9 19]]
(0, 10) True
(1, 11) True
(2, 12) True
(3, 13) True
(4, 14) True
(5, 15) True
(6, 16) True
(7, 17) True
(8, 18) True
(9, 19) True
您可能想看看这个项目,这是一个C代码的GPL库,它是为这类事情而设计的,并且有一个很好的Python API。我认为在您的例子中,Python代码应该是
from igraph import Graph
g = Graph.Read_Edgelist('edges.txt')
g.write_adjacency('adjacency_matrix.txt')
以下是我的解决方案:
import numpy as np
import pandas as pd
import scipy.sparse as ss
def read_data_file_as_coo_matrix(filename='edges.txt'):
"Read data file and return sparse matrix in coordinate format."
data = pd.read_csv(filename, sep=' ', header=None, dtype=np.uint32)
rows = data[0] # Not a copy, just a reference.
cols = data[1]
ones = np.ones(len(rows), np.uint32)
matrix = ss.coo_matrix((ones, (rows, cols)))
return matrix
熊猫使用read\u csv
完成繁重的解析工作。熊猫已经在以列格式存储数据。数据[0]
和数据[1]
只获取参考,没有副本。然后我把它们输入coo\u矩阵
。本地基准:
In [1]: %timeit -n1 -r5 read_data_file_as_coo_matrix()
1 loop, best of 5: 14.2 s per loop
In [3]: %timeit -n1 -r5 save_csr_matrix('edges.npz', matrix.tocsr())
1 loop, best of 5: 13.4 s per loop
In [4]: %timeit -n1 -r5 load_csr_matrix('edges.npz')
1 loop, best of 5: 881 ms per loop
然后将csr矩阵保存到文件中:
def save_csr_matrix(filename, matrix):
"""Save compressed sparse row (csr) matrix to file.
Based on http://stackoverflow.com/a/8980156/232571
"""
assert filename.endswith('.npz')
attributes = {
'data': matrix.data,
'indices': matrix.indices,
'indptr': matrix.indptr,
'shape': matrix.shape,
}
np.savez(filename, **attributes)
本地基准:
In [1]: %timeit -n1 -r5 read_data_file_as_coo_matrix()
1 loop, best of 5: 14.2 s per loop
In [3]: %timeit -n1 -r5 save_csr_matrix('edges.npz', matrix.tocsr())
1 loop, best of 5: 13.4 s per loop
In [4]: %timeit -n1 -r5 load_csr_matrix('edges.npz')
1 loop, best of 5: 881 ms per loop
然后从文件中重新加载:
def load_csr_matrix(filename):
"""Load compressed sparse row (csr) matrix from file.
Based on http://stackoverflow.com/a/8980156/232571
"""
assert filename.endswith('.npz')
loader = np.load(filename)
args = (loader['data'], loader['indices'], loader['indptr'])
matrix = ss.csr_matrix(args, shape=loader['shape'])
return matrix
本地基准:
In [1]: %timeit -n1 -r5 read_data_file_as_coo_matrix()
1 loop, best of 5: 14.2 s per loop
In [3]: %timeit -n1 -r5 save_csr_matrix('edges.npz', matrix.tocsr())
1 loop, best of 5: 13.4 s per loop
In [4]: %timeit -n1 -r5 load_csr_matrix('edges.npz')
1 loop, best of 5: 881 ms per loop
最后,对其进行全面测试:
def test():
"Test data file parsing and matrix serialization."
coo_matrix = read_data_file_as_coo_matrix()
csr_matrix = coo_matrix.tocsr()
save_csr_matrix('edges.npz', csr_matrix)
loaded_csr_matrix = load_csr_matrix('edges.npz')
# Comparison based on http://stackoverflow.com/a/30685839/232571
assert (csr_matrix != loaded_csr_matrix).nnz == 0
if __name__ == '__main__':
test()
运行test()
时,大约需要30秒:
$ time python so_38688062.py
real 0m30.401s
user 0m27.257s
sys 0m2.759s
内存高水位线约为1.79GB
注意,一旦你在CSR矩阵格式中转换了“边.txt”到“边.npz”,加载它将花费不到一秒钟。
在我的回答中,我考虑节点的ID是由9个字符长字符串给出的,每个字符都来自<代码> [09A-ZA-Z] 。这些节点ID的code>n应映射到值[0,n-1]
(这对于您的应用程序来说可能不是必需的,但仍然具有普遍意义)
我相信大家都知道,为了完整起见,接下来的考虑事项如下:
10^8
个字符串string+int32
值对在字典中的开销约为120
字节,导致文件的内存使用量为12GBint64
:有62个不同的字符->可以用6位编码,字符串中的9个字符->6*9=54 ca。1.2 GB就足够了,但是成本为
from scipy import sparse
def data_as_coo_matrix(filename, EDGE_CNT)
node_cnt, nodes = maps_to_ids(filename, EDGE_CNT)
rows=nodes[::2]#it is only a view, not a copy
cols=nodes[1::2]#it is only a view, not a copy
return sparse.coo_matrix((np.ones(len(rows), dtype=bool), (rows, cols)), shape=(node_cnt, node_cnt))
def toInt64(string):
res=0L
for ch in string:
res*=62
if ch <='9':
res+=ord(ch)-ord('0')
elif ch <='Z':
res+=ord(ch)-ord('A')+10
else:
res+=ord(ch)-ord('a')+36
return res
import numpy as np
import scipy.sparse as sparse
def readEdges():
with open('edges.txt') as f:
data = f.read()
edges = np.fromstring(data, dtype=np.int32, sep=' ')
edges = np.reshape(edges, (edges.shape[0]/2, 2))
ones = np.ones(len(edges), np.uint32)
cooMatrix = sparse.coo_matrix((ones, (edges[:,0], edges[:,1])))
%timeit -n5 readEdges()
5 loops, best of 3: 13.6 s per loop
def readEdgesMmap():
with open('edges.txt') as f:
with contextlib.closing(mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)) as m:
edges = np.fromstring(m, dtype=np.int32, sep=' ')
edges = np.reshape(edges, (edges.shape[0]/2, 2))
ones = np.ones(len(edges), np.uint32)
cooMatrix = sparse.coo_matrix((ones, (edges[:,0], edges[:,1])))
%timeit -n5 readEdgesMmap()
5 loops, best of 3: 12.7 s per loop