我希望使用中间scipy.sparse.dok_matrix
存储格式构建稀疏实矩阵,然后将矩阵转换为scipy.sparse.csc_matrix
存储格式,并使用生成的矩阵执行计算。但是,中间矩阵的大小大大超出了我的估计和可用内存。
$ python3 -V
Python 3.4.2
$ pip freeze | grep -E 'scipy|numpy'
numpy==1.14.2
scipy==1.0.1
numpy
当我按如下方式构建一个20,000×20,000个16位整数的numpy数组时,我估计大小将是20000 ** 2 * 16/8/2 **20≈763M。该进程的驻留集大小(RSS)为815M,由htop
unix工具报告,与我的估算相符。
import numpy as np
n = 20000
M = np.ones((n, n), dtype=np.uint16)
dict
当我使用16位整数作为关键字和值来构建20,000×20,000 scipy.sparse.dok_matrix
时,我估计大小将是20000 ** 2 *(16 * 3)/ 8/2 ** 30 ... 2.24G加上哈希表的一些小开销。但是,该过程的RSS值为66.4G,这表明我的估计值出现了严重错误。
import numpy as np
n = 20000
M = dict()
for i in range(n):
i = np.uint16(i)
for j in range(n):
j = np.uint16(j)
M[(i, j)] = np.uint16(1)
scipy.sparse.dok_matrix
当我使用16位整数作为键和值构建20,000×20,000 scipy.sparse.dok_matrix
时,我估计大小将再次为20000 ** 2 *(16 * 3)/ 8/2 ** 30 ≈2.24G加上哈希表的一些小开销。但是,该过程的RSS为81.3G,与dict
示例相比,我的估计值更远。
from scipy.sparse import dok_matrix
import numpy as np
n = 20000
M = dok_matrix((n, n), dtype=np.uint16)
for i in range(n):
i = np.uint16(i)
for j in range(n):
j = np.uint16(j)
M[i, j] = 1
答案 0 :(得分:2)
虽然您可以控制dtype
的{{1}}值data
,但您无法控制密钥存储空间。
查看dok
类代码:
dok_matrix
因此元素存储为选定def __setitem__(self, index, x):
...
v = np.asarray(x, dtype=self.dtype)
...
dict.__setitem__(self, (int(i), int(j)), v[()])
的numpy'标量'对象:
dtype
我不太了解Python dict存储来估计哈希表所需的内存。我不认为实际的索引元组存储在任何地方,只是它们的哈希值。
最近的另一个问题是尝试使用In [129]: M = sparse.dok_matrix((10,10), dtype=np.uint16)
In [130]: M[0,0] = 1
In [131]: list(M.items())
Out[131]: [((0, 0), 1)]
In [132]: type(_[0][1])
Out[132]: numpy.uint16
来比较数组和列表的内存使用情况。在这个上使用它:
sys.getsizeof
使用列表,In [133]: sys.getsizeof(M) # 1 item
Out[133]: 256
In [134]: for i in range(10):
...: for j in range(10):
...: M[i,j]=1
...:
In [135]: sys.getsizeof(M) # full
Out[135]: 4720
仅捕获对象开销和指针缓冲区。我不知道它用字典捕获了什么。也许只是哈希表。数据值存储在内存的其他位置:
getsizeof
其他稀疏格式的存储更容易估算。 In [136]: sys.getsizeof(Out[131][0][1])
Out[136]: 26
In [137]: M.nnz
Out[137]: 100
In [138]: 26*M.nnz
Out[138]: 2600
和coo
使用3个numpy数组。索引数组存储为csr
或int32
,具体取决于矩阵的维度。
为了粗略估计内存使用情况,我为文件编写了各种格式:
int64
由于In [164]: np.save('Mdense',M.A)
In [165]: sparse.save_npz('Mcsr',M.tocsr())
In [166]: sparse.save_npz('Mcoo',M.tocoo())
In [179]: f = open('Mdok',mode='wb')
In [180]: pickle.Pickler(f).dump(M)
In [181]: f.close()
In [182]: ll M*
-rw-rw-r-- 1 paul 900 Apr 16 11:53 Mcoo.npz
-rw-rw-r-- 1 paul 911 Apr 16 11:53 Mcsr.npz
-rw-rw-r-- 1 paul 328 Apr 16 11:53 Mdense.npy
-rw-rw-r-- 1 paul 3023 Apr 16 11:57 Mdok
已满,因此稀疏M
格式占用密集数组空间的3倍是有意义的。 coo
每个coo
,data
和row
都有一个100个元素数组。 col
尝试压缩csr
数组,但区别并不总是那么重要。
我必须使用row
作为pickle
。 dok
无法处理sparse.save_npz
。