【问题标题】:multiplying `csr` sparse matrices of different sizes python乘以不同大小python的`csr`稀疏矩阵
【发布时间】:2016-05-17 15:46:10
【问题描述】:

我需要将两个不同大小的稀疏矩阵(按元素)相乘。以下是矩阵:

matrix1 = (1, 2)    30.0
(2, 3)  20.0
(4, 5)  10.0
(6, 7)  80

matrix2 = (1, 2)    2.0
(2, 3)  1.0
(4, 5)  5.0

如您所见,matrix1 大于 matrix2。我需要将它们相乘以使matrix2 中不存在的元素(在这种情况下元素(6, 7) 保持不变。我需要的输出如下:

final_matrix = (1, 2)   60.0
(2, 3)  20.0
(4, 5)  50.0
(6, 7)  80

对于我正在使用的矩阵的真实数据非常大。如果您需要任何进一步的说明,请告诉我。

谢谢!

【问题讨论】:

  • 矩阵不必按照您定义问题的方式具有不同的大小......只需在第二个矩阵中没有匹配条目的任何地方放置一个1。为了按元素相乘,备用矩阵的维度必须相同。
  • 太好了,您如何建议我在没有匹配条目的任何地方放置1?请记住,我的矩阵非常大 - 迭代它们需要很长时间。
  • 我很想将此称为您关于添加不同形状矩阵的其他问题的副本。同样的问题和潜在的解决方案也适用:stackoverflow.com/questions/37231163/…
  • 我实际上已经使用该问题中的方法自行开发了一个解决方案。很快就会发布答案,只是测试以确保。基于此,您是否建议将其标记为重复?

标签: python matrix scipy sparse-matrix


【解决方案1】:

对于密集数组,执行这种乘法相对容易。而且速度很快,因为切片速度很快

In [453]: x=np.arange(24).reshape(4,6)
In [454]: y=np.arange(10,22).reshape(3,4)

In [457]: x[:3,:4] *= y

In [458]: x
Out[458]: 
array([[  0,  11,  24,  39,   4,   5],
       [ 84, 105, 128, 153,  10,  11],
       [216, 247, 280, 315,  16,  17],
       [ 18,  19,  20,  21,  22,  23]])

使用稀疏等价物

In [460]: xM=sparse.csr_matrix(x)
In [462]: yM=sparse.csr_matrix(y)

切片乘法:

In [468]: z= xM[:3,:4].multiply(yM)   # z.A matches the dense block

但是当我们尝试将该值分配回 xM 时,我们会收到警告

In [469]: xM[:3,:4] = xM[:3,:4].multiply(yM)
/usr/lib/python3/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 [471]: xL=sparse.lil_matrix(x)
In [472]: yL=sparse.lil_matrix(y)
In [475]: xL[:3,:4]=xL[:3,:4].multiply(yL)

xL.multiply代码其实是:return self.tocsr().multiply(other)

我不知道哪种格式组合最有效。

[我们可以通过认识到xM[:3,:4].multiply(yM) 将包含更少而不是更多的非零元素来绕过 csr 稀疏警告。所以至少暂时我们可以将xM.data 的一些值设置为0,而无需更改其他属性。稍后我们可以使用eliminate_zeros 进行清理。]


切片赋值的替代方法是将y 扩展为x 的大小,然后执行完全乘法。在这种情况下,我们需要用 1 填充 y

密集版本是:

In [478]: z=np.ones_like(x)
In [479]: z[:3,:4]=y
In [480]: x*z

对于稀疏矩阵,我们必须查看所需的填充。如果yM 只是比xM 小几行和/或几列,我怀疑我们可以有效地使用sparse.vstackhstack。如果有很多填充,结果将有很多非零值,所以我们不妨制作密集的z

In [503]: zM = sparse.vstack((yM,np.ones((1,4),int)))
In [504]: zM = sparse.hstack((zM,np.ones((4,2),int)))

In [505]: zM.shape
Out[505]: (4, 6)

In [507]: zM.A
Out[507]: 
array([[10, 11, 12, 13,  1,  1],
       [14, 15, 16, 17,  1,  1],
       [18, 19, 20, 21,  1,  1],
       [ 1,  1,  1,  1,  1,  1]], dtype=int32)

In [511]: xM.multiply(zM).A
Out[511]: 
array([[  0,  11,  24,  39,   4,   5],
       [ 84, 105, 128, 153,  10,  11],
       [216, 247, 280, 315,  16,  17],
       [ 18,  19,  20,  21,  22,  23]], dtype=int32)

另一种构建此扩展yM 的方法是使用sparse.bmat,它从块中创建一个新矩阵。 bmat 的工作原理是构造 coo 格式矩阵并连接它们的所有 row, col, data 属性,并从中创建一个新矩阵。

事实证明vstack 使用bmat

return bmat([[b] for b in blocks], format=format, dtype=dtype)

这构造了相同的 4x6 矩阵:

In [520]: zM = sparse.bmat([[yM, np.ones((3,2),int)],
                  [np.ones((1,4),int), np.ones((1,2),int)]])

==================

另一种可能性是从sum 问题中调整@Vadim 的dok 方法

https://stackoverflow.com/a/37241977/901925

它是迭代的并且高度依赖于较小矩阵的非零元素的数量 - 但它非常灵活。

【讨论】:

  • 进一步思考,y 的填充不需要全为 1;仅 1 对应于 x 的非零元素。
【解决方案2】:

可能有一个更 Pythonic 的方法来做到这一点,但从数学上讲,这是一个非常简单的方法。

from scipy.sparse import csc_matrix, lil_matrix, find

## create example matrices, A, B, assume B has values that are not in A
A = csc_matrix( (5,5) )
A[1,1] = 3.0
A[2,2] = 2.0
B = csc_matrix( (5,5) )
B[1,1] = 5.0
B[2,2] = 10.0
B[3,3] = 50.0

C = lil_matrix( (5,5) )  ## C will be a modification of A; 
## more efficient to do this with lil_matrix than csc_matrix; 
## you can convert later if needed

(I,J,V) = find(A)  ## get nonzero indices of A
(M,N,P) = find(B)  ## get nonzero indices of B
C[M,N] = 1.0  ## set all B-corresponding elements to 1.0
C[I,J] = A[I,J]  ## overwrite with corresponding elements in A

D = C.multiply(B)  ## EDIT: per hpaulj's suggestion, using multiply(), which works with most any sparse matrix type

【讨论】:

  • 对于匹配大小的csc 矩阵,有一个有效的(编译的)元素逐个元素相乘。 A.multiply(B).
猜你喜欢
  • 2021-08-21
  • 2012-06-17
  • 2019-09-30
  • 2011-11-20
  • 2013-06-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-31
相关资源
最近更新 更多