为什么scipy.sparse.Csr_matrix '广播乘法,但不减法?



我正试图理解这个问题的解决方案,虽然我可以重用代码,但我更希望在我这样做之前知道发生了什么。

这个问题是关于如何平铺一个scipy.sparse.csr_matrix对象,在写作的时候,顶部的答案(@user3357359)显示了如何平铺一个矩阵的单行跨多行:

from scipy.sparse import csr_matrix
sparse_row = csr_matrix([[0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0]])
repeat_number = 3
repeated_row_matrix = csr_matrix(np.ones([repeat_number,1])) * sparse_row

(我已经添加了sparse_rowrepeat_number初始化,以帮助使事情具体化)。

如果我现在将其转换为密集矩阵并打印如下:

print(f"repeated_row_matrix.todense() = {repeated_row_matrix.todense()}")

输出:

repeated_row_matrix.todense() =
[[0 0 0 0 0 1 0 1 1 0 0 0]
[0 0 0 0 0 1 0 1 1 0 0 0]
[0 0 0 0 0 1 0 1 1 0 0 0]]

repeated_row_matrix赋值右侧的操作在我看来似乎是在执行广播。原始sparse_row的形状为(1,12),临时矩阵为1的(3,1)矩阵,结果为(3,12)矩阵。到目前为止,这与您期望的numpy.array的行为相似。但是,如果我用减法操作符做同样的事情:

sparse_row = csr_matrix([[0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0]])
repeat_number = 3
repeated_row_matrix = csr_matrix(np.ones([repeat_number,1])) - sparse_row
print(f"repeated_row_matrix.todense() =n{repeated_row_matrix.todense()}")

第三行出现错误:

3 repeated_row_matrix = csr_matrix(np.ones([repeat_number,1])) - sparse_row
...
ValueError: inconsistent shapes

这是预期的行为吗?如果是,为什么?

我猜想,两个分别为n1和n2非零的稀疏k向量之间的乘法,总是小于或等于min(n1,n2)非零。在最坏的情况下,减法会使n1+n2非零,但这真的解释了为什么允许一种行为而不允许一种行为吗?

我希望从矩阵中执行单行向量的减法(对于我正在玩的k - medioids的稀疏实现)。为了执行减法,我创建了一个临时的稀疏数组,它通过使用广播和乘法来平铺原始行,然后我可以从另一个数组中减去一个数组。我相信应该有更好的办法,但是我看不出来。

同时,@" C.J.Jackson"在评论中回复说,构造平铺的更好方法是:

sparse_row[np.zeros(repeat_number),:]

这工作,但我不知道为什么或什么功能被使用。谁能给我指一下文件?如果sparse_rownumpy.array,那么这不会导致平铺。

提前感谢。

对于密集数组,广播乘法和矩阵乘法可以在特殊情况下做同样的事情。例如对于2个1d数组

In [3]: x = np.arange(3); y = np.arange(5)

播放:

In [4]: x[:,None]*y   # (3,1)*(5,) => (3,1)*(1,5) => (3,5)
Out[4]: 
array([[0, 0, 0, 0, 0],
[0, 1, 2, 3, 4],
[0, 2, 4, 6, 8]])

a(3,1)和(1,5)的点/矩阵乘法。这不是广播。它在共享大小为1的维度上做积和:

In [5]: x[:,None]@y[None,:]
Out[5]: 
array([[0, 0, 0, 0, 0],
[0, 1, 2, 3, 4],
[0, 2, 4, 6, 8]])

生成稀疏矩阵:

In [6]: Mx = sparse.csr_matrix(x);My = sparse.csr_matrix(y)    
In [11]: Mx
Out[11]: 
<1x3 sparse matrix of type '<class 'numpy.intc'>'
with 2 stored elements in Compressed Sparse Row format>    
In [12]: My
Out[12]: 
<1x5 sparse matrix of type '<class 'numpy.intc'>'
with 4 stored elements in Compressed Sparse Row format>

注意形状(1,3)和(1,5)。要做矩阵乘法,第一个需要转置为(3,1):

In [13]: Mx.T@My
Out[13]: 
<3x5 sparse matrix of type '<class 'numpy.intc'>'
with 8 stored elements in Compressed Sparse Column format>
In [14]: _.A
Out[14]: 
array([[0, 0, 0, 0, 0],
[0, 1, 2, 3, 4],
[0, 2, 4, 6, 8]], dtype=int32)

Mx.T*My工作方式相同,因为sparse是在np.matrix(和MATLAB)上建模的,其中*是矩阵乘法。

元素乘法的工作方式与dense相同:

In [20]: Mx.T.multiply(My)
Out[20]: 
<3x5 sparse matrix of type '<class 'numpy.intc'>'
with 8 stored elements in Compressed Sparse Column format>

我有点惊讶,它看起来有点像broadcasting,虽然它不涉及任何自动None维度(稀疏总是2d)。有趣的是,我找不到密集矩阵的逐元素乘法。

但是你发现Mx.T-My会引发inconsistent shapes错误。稀疏开发人员选择不实现这种减法(或加法)。一般来说,稀疏矩阵的加法或减法是一个问题。它可以很容易地得到一个密集的矩阵,如果你给所有的元素加上一些东西,包括"隐含的"。0 .

In [41]: Mx+1
---------------------------------------------------------------------------
NotImplementedError                       Traceback (most recent call last)
Input In [41], in <cell line: 1>()
----> 1 Mx+1
File ~anaconda3libsite-packagesscipysparsebase.py:410, in spmatrix.__add__(self, other)
408         return self.copy()
409     # Now we would add this scalar to every element.
--> 410     raise NotImplementedError('adding a nonzero scalar to a '
411                               'sparse matrix is not supported')
412 elif isspmatrix(other):
413     if other.shape != self.shape:
NotImplementedError: adding a nonzero scalar to a sparse matrix is not supported

复制广播的减法:

In [54]: x[:,None]-y
Out[54]: 
array([[ 0, -1, -2, -3, -4],
[ 1,  0, -1, -2, -3],
[ 2,  1,  0, -1, -2]])

我们必须"平铺"矩阵。你的链接显示了一些选项(包括我的答案)。另一种选择是vstack矩阵的几个实例。sparse.vstack实际上创建了一个新的矩阵,使用coo矩阵格式:

In [55]: Mxx = sparse.vstack([Mx]*5);Myy = sparse.vstack([My,My,My])    
In [56]: Mxx,Myy
Out[56]: 
(<5x3 sparse matrix of type '<class 'numpy.intc'>'
with 10 stored elements in Compressed Sparse Row format>,
<3x5 sparse matrix of type '<class 'numpy.intc'>'
with 12 stored elements in Compressed Sparse Row format>)

现在两个(3,5)矩阵可以加减:

In [57]: Mxx.T-Myy
Out[57]: 
<3x5 sparse matrix of type '<class 'numpy.intc'>'
with 12 stored elements in Compressed Sparse Column format>
In [58]: _.A
Out[58]: 
array([[ 0, -1, -2, -3, -4],
[ 1,  0, -1, -2, -3],
[ 2,  1,  0, -1, -2]], dtype=int32)

在稀疏数学发展的线性代数领域(特别是有限差分和有限单元),矩阵乘法很重要。其他只处理非零元素的数学运算相当简单。但是改变稀疏性的操作是(相对)昂贵的。新值和子矩阵最好添加到coo输入。转换为csr时添加coo副本。因此,整个矩阵的加法/减法是(有意)有限的。

最新更新