我正试图理解这个问题的解决方案,虽然我可以重用代码,但我更希望在我这样做之前知道发生了什么。
这个问题是关于如何平铺一个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_row
和repeat_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_row
是numpy.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
副本。因此,整个矩阵的加法/减法是(有意)有限的。