2017-01-25 1 views
0

블록 대각선 행렬 크기 (N, N) 인 정사각형 2D 배열이 있다고 가정 해 보겠습니다. 각 블록은 (말) (N_b, N_b)입니다. 이들 블록 중 일부는 단지 0 (예 : (N_b, N_b) 0의 행렬)입니다. 이 블록을 (N_b, N_b) 0 배열이없는 행렬로 남겨두고 싶습니다.2d numpy 배열에서 0 인 사각형 부분 행렬 제거

또한, 나는 또한 모든 요소가 같은 장소

모든 I에있는 요구 사항이 "압착"매트릭스 중 하나를 수행하고 (제로 패딩) 원래 크기로 확장합니다 싶습니다 요구 루프와 많은 회계를 생각할 수 있습니다. 나는 희소 행렬을 사용하게되어 기쁩니다. 그러나 그것은 훨씬 더 복잡하게 보입니다.

("스퀴즈") 문제의 첫 번째 부분은이 방식으로 수행 될 수있다 : 여기

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) 
+0

블록 매트릭스 또는 블록 대각 매트릭스로 시작 하시겠습니까? – James

+0

@James 블록 대각선입니다. – Jose

+0

블록 대각선 행렬에는 모든 대각선이 아닌 모든 요소에 0이 있습니다. 그러면 대각선에서 0을 제거하기 만하면됩니까? http://mathworld.wolfram.com/BlockDiagonalMatrix.html – James

답변

0

제로와 같은 대각선 요소를 찾아서 2D 부울 마스크를 만들어 배열을 선택할 수 있습니다.

import numpy as np 

a = [[1,1,0,0,0,0,0], 
    [1,1,0,0,0,0,0], 
    [0,0,0,0,0,0,0], 
    [0,0,0,0,0,0,0], 
    [0,0,0,0,2,2,2], 
    [0,0,0,0,2,2,2], 
    [0,0,0,0,2,2,2]] 

# find the diagonal elements not equal to zero 
b = np.diag(a) != 0 

# create a boolean 2d mask 
mask = b[np.newaxis] * np.transpose(b[np.newaxis]) 

> mask # this is the mask output 
# array([[ True, True, False, False, True, True, True], 
#  [ True, True, False, False, True, True, True], 
#  [False, False, False, False, False, False, False], 
#  [False, False, False, False, False, False, False], 
#  [ True, True, False, False, True, True, True], 
#  [ True, True, False, False, True, True, True], 
#  [ True, True, False, False, True, True, True]], dtype=bool) 

마스크가 원하지 않는 행과 열을 제거하는 방법을 확인하십시오. 그러나 numpy는 지그재그 배열을 허용하지 않으므로 amask을 1D 배열에 다시 형성해야하며 부울 색인을 사용하고 다시 정사각형으로 다시 형성해야합니다.

a_squished = np.ravel(a)[np.ravel(mask)] 

# reshape the squished array to a 2D square 
out = a_squished.reshape(      # reshape the array 
      np.sqrt(a_squished.size).astype(int), # pass to int to stop warning 
      -1          # fill next axis with leftover 
    ) 

> out 
# array([[1, 1, 0, 0, 0], 
#  [1, 1, 0, 0, 0], 
#  [0, 0, 2, 2, 2], 
#  [0, 0, 2, 2, 2], 
#  [0, 0, 2, 2, 2]])