我有两个scipy_sparse_csr_matrix'a'和scipy_sparse_csr_matrix(boolean)'mask',我想将'a'的元素设置为零,其中mask的元素为True。
例如
>>>a
<3x3 sparse matrix of type '<type 'numpy.int32'>'
with 4 stored elements in Compressed Sparse Row format>
>>>a.todense()
matrix([[0, 0, 3],
[0, 1, 5],
[7, 0, 0]])
>>>mask
<3x3 sparse matrix of type '<type 'numpy.bool_'>'
with 4 stored elements in Compressed Sparse Row format>
>>>mask.todense()
matrix([[ True, False, True],
[False, False, True],
[False, True, False]], dtype=bool)
然后我想获得以下结果。
>>>result
<3x3 sparse matrix of type '<type 'numpy.int32'>'
with 2 stored elements in Compressed Sparse Row format>
>>>result.todense()
matrix([[0, 0, 0],
[0, 1, 0],
[7, 0, 0]])
我可以通过像
这样的操作来完成result = a - a.multiply(mask)
或
a -= a.multiply(mask) #I don't care either in-place or copy.
但我认为上述操作效率低下。由于'a'和'mask'的实际形状为67,108,864×2,000,000,因此这些操作在高规格服务器(64核Xeon cpu,512GB内存)上需要几秒钟。例如,'a'有大约30,000,000个非零元素,'mask'有大约1,800,000个非零(True)元素,然后上面的操作大约需要2秒。
有更有效的方法吗?
条件如下。
谢谢!
其他方式(尝试过)
a.data*=~np.array(mask[a.astype(np.bool)]).flatten();a.eliminate_zeros() #This takes twice the time longer than above method.
答案 0 :(得分:1)
我最初的印象是这种乘法和减法方法是合理的。通常sparse
代码将操作实现为某种乘法,即使密集等价物使用更直接的方法。行或列上的稀疏和使用矩阵乘法,其中适当的行或列矩阵为1。甚至行或列索引都使用矩阵乘法(至少在csr
格式上)。
有时我们可以直接使用矩阵属性(data
,indices
,indptr
)来改进操作。但这需要更多的思考和实验。
对于密集阵列,我的第一次尝试将是
In [611]: a.A*~(mask.A)
Out[611]:
array([[0, 0, 0],
[0, 1, 0],
[7, 0, 0]], dtype=int32)
但是,没有直接的方法可以对稀疏矩阵进行not
。如果mask
确实稀疏,~mask
就不会。在您的示例中,mask
有4个True术语,5个False,因此密集版本也可以正常运行:
In [612]: nmask=sparse.csr_matrix(~(mask.A))
In [615]: a.multiply(nmask)
Out[615]:
<3x3 sparse matrix of type '<class 'numpy.int32'>'
with 2 stored elements in Compressed Sparse Row format>
CSR scipy matrix does not update after updating its values探讨了将稀疏矩阵的对角线设置为0.可以将data
属性的值设置为0,然后在结尾处设置eliminate_zeros
一次。
另一种密集的方法是
In [618]: a1=a.A
In [619]: a1[mask.A]=0
这也适用于sparse
- 某种
In [622]: a2=a.copy()
In [624]: a2[mask]
Out[624]: matrix([[0, 3, 5, 0]], dtype=int32)
In [625]: a2[mask]=0
/usr/local/lib/python3.5/dist-packages/scipy/sparse/compressed.py:730: SparseEfficiencyWarning: Changing the sparsity structure of a csr_matrix is expensive. lil_matrix is more efficient.
SparseEfficiencyWarning)
In [626]: a2
Out[626]:
<3x3 sparse matrix of type '<class 'numpy.int32'>'
with 6 stored elements in Compressed Sparse Row format>
如前一个问题所述,我们需要消除零:
In [628]: a2.eliminate_zeros()
In [629]: a2
Out[629]:
<3x3 sparse matrix of type '<class 'numpy.int32'>'
with 2 stored elements in Compressed Sparse Row format>
从稀疏性警告中提示,让我们试试lil
格式
In [638]: al=a.tolil()
In [639]: al[mask]
Out[639]:
<1x4 sparse matrix of type '<class 'numpy.int32'>'
with 2 stored elements in LInked List format>
In [640]: al[mask]=0
In [641]: al
Out[641]:
<3x3 sparse matrix of type '<class 'numpy.int32'>'
with 2 stored elements in LInked List format>
有趣的是al[mask]
仍然稀疏,a[mask]
密集。 2种格式使用不同的索引方法。
在稀疏度较低的情况下,可能值得迭代mask
的真(非零)元素,将a
的相应项直接设置为零。
我不会猜测这些方法的相对速度。这需要在现实数据上进行测试。