Python 如何减少scipy.sparse.dok_矩阵的存储大小
我希望使用中间存储格式构建一个稀疏实矩阵,然后将该矩阵转换为存储格式,并使用生成的矩阵执行计算。然而,中间矩阵的大小大大超过了我的估计和可用内存 我的环境 使用Python 如何减少scipy.sparse.dok_矩阵的存储大小,python,python-3.x,numpy,scipy,sparse-matrix,Python,Python 3.x,Numpy,Scipy,Sparse Matrix,我希望使用中间存储格式构建一个稀疏实矩阵,然后将该矩阵转换为存储格式,并使用生成的矩阵执行计算。然而,中间矩阵的大小大大超过了我的估计和可用内存 我的环境 使用numpy 当我构建一个由16位整数组成的20000×20000 numpy数组时,我估计其大小为20000**2*16/8/2**20≈ 763米。根据htopunix工具的报告,该过程的常驻集大小(RSS)为815M,这与我的估计相符 将numpy导入为np n=20000 M=np.one((n,n),dtype=np.uint16
numpy
当我构建一个由16位整数组成的20000×20000 numpy数组时,我估计其大小为20000**2*16/8/2**20≈ 763米。根据htop
unix工具的报告,该过程的常驻集大小(RSS)为815M,这与我的估计相符
将numpy导入为np
n=20000
M=np.one((n,n),dtype=np.uint16)
使用dict
当我使用16位整数作为键和值构建一个20000×20000scipy.sparse.dok_矩阵时,我估计大小为20000**2*(16*3)/8/2**30≈ 2.24G加上哈希表的一些小开销。然而,这个过程的RSS为66.4G,这表明我在估计中犯了一个严重错误
将numpy导入为np
n=20000
M=dict()
对于范围(n)中的i:
i=np.uint16(i)
对于范围(n)内的j:
j=np.uint16(j)
M[(i,j)]=np.uint16(1)
使用scipy.sparse.dok_矩阵
当我构建一个20000×20000scipy.sparse.dok_矩阵时,使用16位整数作为键和值,如下所示,我估计大小将再次为20000**2*(16*3)/8/2**30≈ 2.24G加上哈希表的一些小开销。然而,这个过程的RSS为81.3G,这比我估计的dict例子还要远
从scipy.sparse导入dok_矩阵
将numpy作为np导入
n=20000
M=dok_矩阵((n,n),dtype=np.uint16)
对于范围(n)中的i:
i=np.uint16(i)
对于范围(n)内的j:
j=np.uint16(j)
M[i,j]=1
虽然您可以控制dok
的数据
值的数据类型
,但无法控制密钥存储
查看dok_矩阵
类别代码:
def __setitem__(self, index, x):
...
v = np.asarray(x, dtype=self.dtype)
...
dict.__setitem__(self, (int(i), int(j)), v[()])
因此,元素存储为所选dtype
的numpy“标量”对象:
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
我对Python dict存储了解不够,无法估计哈希表所需的内存。我不认为实际的索引元组存储在任何地方,只是它们的散列
最近的另一个问题试图使用sys.getsizeof
比较数组和列表的内存使用情况。在这个dok上使用它:
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
和csr
使用3个numpy数组。索引数组根据矩阵的维数存储为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
已满,因此稀疏coo
格式将占用密集数组的3倍空间coo
对于数据
、行
和列
中的每一个都有一个100元素的数组csr
试图压缩行
数组,但差异并不总是那么显著
对于dok
,我不得不使用pickle
sparse.save_npz
不处理dok
当您可以控制dok
的数据
值的类型时,您无法控制密钥存储
查看dok_矩阵
类别代码:
def __setitem__(self, index, x):
...
v = np.asarray(x, dtype=self.dtype)
...
dict.__setitem__(self, (int(i), int(j)), v[()])
因此,元素存储为所选dtype
的numpy“标量”对象:
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
我对Python dict存储了解不够,无法估计哈希表所需的内存。我不认为实际的索引元组存储在任何地方,只是它们的散列
最近的另一个问题试图使用sys.getsizeof
比较数组和列表的内存使用情况。在这个dok上使用它:
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
和csr
使用3个numpy数组。索引数组根据矩阵的维数存储为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
已满,因此稀疏coo
格式将占用密集数组的3倍空间coo
对于数据
、行
和列
中的每一个都有一个100元素的数组csr
试图压缩行
数组,但差异并不总是那么显著
对于dok
,我不得不使用pickle
<代码>稀疏。save_npz
不处理dok
解释您的估计值不清楚的地方?请明确说明您的问题。我会说它可能是“我如何使一个dok_矩阵
小于一个常规的非稀疏矩阵,甚至一个dict?”它不可能真的小于一个非稀疏矩阵。但是,我更希望包含相同数据的稀疏矩阵不是100倍大。请解释您的估计值。什么不清楚?请明确说明您的问题。我会说它可能是“我如何使一个dok_矩阵
小于一个常规的非稀疏矩阵,甚至一个dict?”它不可能真的小于一个非稀疏矩阵。但是,我更希望包含相同数据的稀疏矩阵不是100倍大