我有三个以.npy
格式保存到磁盘的NumPy数组,总共大约40 GB(表示来自非常大的文档集的文本计数数据)。这三个数组代表scipy.sparse.csc_matrix
稀疏矩阵的data
,indices
和indptr
属性。
我想在此数据上使用分布式gensim LsiModel,特别是使用gensim.matutils.Scipy2Corpus
函数从底层稀疏矩阵提供语料库迭代器。
但是,我不想在内存中实现整个矩阵。相反,我如何告诉gensim有关底层磁盘数据的信息,并根据需要将gensim流从磁盘传输到csc矩阵以将块分发给工作进程?如果我理解正确,这就是Scipy2Corpus
和distributed LsiModel examples声称要做的事情,但他们需要提前将数组实现为csc矩阵。
我尝试使用mmap_mode='r'
加载每个底层数组,但是构造物化csc矩阵的函数scipy.sparse.csc_matrix
将无论如何都会提取所有数据。
答案 0 :(得分:0)
我做了一个稀疏矩阵:
In [207]: A=sparse.random(100,100,.1,'csr')
In [208]: A
Out[208]:
<100x100 sparse matrix of type '<class 'numpy.float64'>'
with 1000 stored elements in Compressed Sparse Row format>
制作其属性的副本,并保存它们
In [209]: D,I,J = A.data.copy(),A.indptr.copy(),A.indices.copy()
In [236]: np.save('sparse_d',D)
In [237]: np.save('sparse_I',I)
In [238]: np.save('sparse_J',J)
如果我将它们重新加载为mmap
,我可以创建一个新矩阵:
In [240]: D1=np.load('sparse_d.npy', mmap_mode='r')
In [241]: I1=np.load('sparse_I.npy', mmap_mode='r')
In [242]: J1=np.load('sparse_J.npy', mmap_mode='r')
In [243]: Amm=sparse.csr_matrix((D1,J1,I1),A.shape)
但是这个新数组的属性是文件的内存副本:
In [246]: type(D1)
Out[246]: numpy.core.memmap.memmap
In [247]: type(Amm.data)
Out[247]: numpy.ndarray
因此,由mmap
数组组成的稀疏矩阵会加载所有数据(如原始帖子中所述)。
In [252]: A.indptr
Out[252]:
array([ 0, 10, 20, 29, 36, 46, 60, 66, 74, 85, 93,
104, 117, 128, 139, 147, 156, 165, 172, 188, 201, 211, ...
我可以通过
获得A
切片
In [254]: A37=A[3:7,:]
In [255]: A37
Out[255]:
<4x100 sparse matrix of type '<class 'numpy.float64'>'
with 37 stored elements in Compressed Sparse Row format>
这是A
的副本,而不是视图(就像密集阵列一样)。
这些行的相关indptr
值为
In [256]: I1[3:8]
Out[256]: memmap([29, 36, 46, 60, 66])
66-29是37,A37
中非零值的数量。
我可以从mmap
数组的切片中创建一个稀疏矩阵:
In [259]: Amm37=sparse.csr_matrix((D1[29:66],J1[29:66],I1[3:8]-I1[3]), shape=(4, 100))
In [260]: Amm37
Out[260]:
<4x100 sparse matrix of type '<class 'numpy.float64'>'
with 37 stored elements in Compressed Sparse Row format>
In [261]: np.allclose(A37.A, Amm37.A)
Out[261]: True
虽然Amm37
的属性在内存中,但该函数的D1
和J1
输入为mmap
个切片:
In [262]: D1[29:66]
Out[262]:
memmap([ 0.08874032, 0.18952295, 0.43034343, 0.83725733, 0.61073925,
0.9178207 , 0.03644072, 0.32206696, 0.90945298, 0.20585155,
.... 0.43905333])
In [263]: I1[3:8]-I1[3]
Out[263]: array([ 0, 7, 17, 31, 37])
所以是的,我可以从保存的属性中重新创建原始A
的行切片,而无需加载整个mmap数组。我只需要从3个阵列中选择切片。同样,我可以从csc
格式数组中选择列。
但是从csr
属性中提取列而不完全加载它是非常困难的。所需的data
和indices
值将分散到存储的数组中。将csr
属性转换为csc
需要创建完整的csr
矩阵并使用其tocsc()
方法。