假设我有一个2D正方形数组,它是块对角矩阵大小(N,N)。 每个块是(例如)(N_b,N_b)。 这些块中的一些只是零(例如零的(N_b,N_b)矩阵)。 我想挤这些块被留下与不具有(N_B,N_B)0阵列的矩阵。
另外,我还想采用这些“压缩的”矩阵之一并将其扩展为原始大小(填充为零),要求所有元素都在同一位置
我能想到的一切都需要循环和大量的记账。 我很高兴使用稀疏矩阵,但这似乎使事情更加复杂。
问题的第一部分(“压缩”)可以通过以下方式完成:
import numpy as np
import scipy.sparse as sp
A = np.random.randn(3,3)*5
B = A*0.
M = np.array(sp.block_diag ( (A, B, A, A, A, B, A) ).todense())
n_b = A.shape[0]
n_blocks = M.shape[0]/n_b
block_locs = []
nonzero_blocks = []
for this_block in xrange ( n_blocks ):
if np.all(M[n_b*this_block:(this_block+1)*n_b, n_b*this_block:(this_block+1)*n_b] != 0):
nonzero_blocks.append (M[n_b*this_block:(this_block+1)*n_b, n_b*this_block:(this_block+1)*n_b] )
block_locs.append ( this_block )
squeezed_M = sp.block_diag ( nonzero_blocks ).tolil()
blocky = []
this_squeeze_block = 0
for this_block in xrange(n_blocks):
if this_block in block_locs:
blocky.append ( squeezed_M[this_squeeze_block*n_b:(this_squeeze_block+1)*n_b,
this_squeeze_block * n_b:(this_squeeze_block + 1) * n_b])
this_squeeze_block += 1
else:
blocky.append ( np.zeros((n_b, n_b)))
A_big = sp.block_diag(blocky).todense()
print np.allclose(M, A_big)
这是原始矩阵(顶部为零块)和压缩版本(底部)的图:
编辑利用问题的对称性的更简洁的方法可能是:
import numpy as np
import scipy.sparse as sp
import matplotlib.pyplot as plt
# First create a big matrix with gaps
n_b = 3
A = np.random.randn(n_b,n_b)*5
B = A*0.
M = sp.block_diag ( (A, B, A, A, A, B, A) )
# Select the rows which are not all zeros
no_zeros = np.any(np.array((M != 0).todense()), axis=1)
n_blocks = no_zeros.sum()
# where's the meat?
meat = np.outer ( no_zeros, no_zeros )
# We need to use a lil matrix to address by a boolean array
# And then we just reshape
A_squeeze = M.tolil()[meat].reshape((n_blocks, n_blocks))
reco = sp.lil_matrix ( M.shape)
reco[np.outer(no_zeros, no_zeros)]=A_squeeze.todense().ravel()
np.allclose(M.todense(), reco.todense())
plt.subplot(1,2,1)
plt.spy(M)
plt.subplot(1,2,2)
plt.spy(A_squeeze)