乘以不同大小的 `csr` 稀疏矩阵 python
multiplying `csr` sparse matrices of different sizes python
我需要将两个不同大小的稀疏矩阵(按元素)相乘。以下是矩阵:
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
对于我正在处理的真实数据,矩阵非常大。如果您需要进一步说明,请告诉我。
谢谢!
可能有更 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
对于密集数组,执行这种乘法相对容易。而且速度很快,因为切片很快
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
小的几行 and/or 列,我怀疑我们可以有效地使用 sparse.vstack
和 hstack
。如果有很多填充,结果将有很多非零值,所以我们不妨使密集 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
方法
它是迭代的并且高度依赖于较小矩阵的非零元素的数量 - 但它非常灵活。
我需要将两个不同大小的稀疏矩阵(按元素)相乘。以下是矩阵:
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
对于我正在处理的真实数据,矩阵非常大。如果您需要进一步说明,请告诉我。
谢谢!
可能有更 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
对于密集数组,执行这种乘法相对容易。而且速度很快,因为切片很快
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
小的几行 and/or 列,我怀疑我们可以有效地使用 sparse.vstack
和 hstack
。如果有很多填充,结果将有很多非零值,所以我们不妨使密集 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
问题
dok
方法
它是迭代的并且高度依赖于较小矩阵的非零元素的数量 - 但它非常灵活。