Извлечение нескольких подматриц в Python

Я пытаюсь извлечь несколько подматриц, если моя разреженная матрица имеет несколько областей ненулевых значений.

Например, Скажем, у меня есть следующая матрица:

x = np.array([0,0,0,0,0,0],
             [0,1,1,0,0,0],
             [0,1,1,0,0,1],
             [0,0,0,0,1,1],
             [0,0,0,0,1,0])

Затем мне нужно иметь возможность извлекать области с ненулевыми значениями, т.е.

x_1 = [[1,1]
       [1,1]]

и

x_2 = [[0,1],
       [1,1],
       [1,0]]

Я использовал np.where() для поиска индексов ненулевых значений и возвращения области только для одной подматрицы, но как это можно распространить на все возможные субрегионы в моей разреженной матрице?

Спасибо!

Ответ 1

Процедура:

  • Удалить ведущие и завершающие строки и столбцы со всеми нулями. (Не средние)
  • Найти все пустые строки и столбцы и разбить матрицу на эти индексы. Это создает список матриц
  • Для каждой вновь созданной матрицы повторите процедуру рекурсивно, пока не будет возможно дальнейшее расщепление.

код:

def delrc(arr):
    while True:     # delete leading rows with all zeros
    if np.all(arr[0]==0):
        arr=np.delete(arr,0,axis=0)
    else: break
    while True:     # delete trailing rows with all zeros
    if np.all(arr[-1]==0):
        arr=np.delete(arr,-1,axis=0)
    else: break
    while True:     # delete leading cols with all zeros
    if np.all(arr[:,0]==0):
        arr=np.delete(arr,0,axis=1)
    else: break
    while True:     # delete trailing cols with all zeros
    if np.all(arr[:,-1]==0):
        arr=np.delete(arr,-1,axis=1)
    else: break
    return arr

def rcsplit(arr):
    if np.all(arr==0): return []    # if all zeros return
    global  res
    arr = delrc(arr)        # delete leading/trailing rows/cols with all zeros
    print arr
    indr = np.where(np.all(arr==0,axis=1))[0]
    indc = np.where(np.all(arr==0,axis=0))[0]
    if not indr and not indc:   # If no further split possible return
    res.append(arr)
    return
    arr=np.delete(arr,indr,axis=0)  #delete empty rows in between non empty rows
    arr=np.delete(arr,indc,axis=1)  #delete empty cols in between non empty cols
    arr=np.split(arr,indc,axis=1)   # split on empty (all zeros) cols 
    print arr
    arr2=[]
    for i in arr:
    z=delrc(i)  
    arr2.extend(np.split(z,indr,axis=0))   # split on empty (all zeros) rows
    for i in arr2:
    rcsplit(np.array(i))        # recursive split again no further splitting is possible

if __name__=="__main__":

    import numpy as np 
    res = []   
    arr = np.array([[0,0,0,0,0,0],
        [0,1,1,0,0,0],
        [0,1,1,0,0,1],
        [0,0,0,0,1,1],
        [0,0,0,0,1,0]])
    rcsplit(arr)
    for i in res: print i

Ответ 2

Для этого вы можете использовать встроенные модули.

from scipy.ndimage.measurements import find_objects, label
from scipy.ndimage import generate_binary_structure as gbs

import numpy as np

# create array
x = np.array([[0,0,0,0,0,0],
             [0,1,1,0,0,0],
             [0,1,1,0,0,1],
             [0,0,0,0,1,1],
             [0,0,0,0,1,0]])

# define labeling structure to inlcude adjacent (including diagonal) cells
struc = gbs(2,2)

# generate array of labeled sections labels
x2, numlabels = label(x,struc)

# pull out first group of "ones"
xy1 = find_objects(x2==1)[0]

# pull out second group of "ones"
xy2 = find_objects(x2==2)[0]

Теперь протестируйте:

>>> x[xy1]
    array([[1, 1],
           [1, 1]])

>>> x[xy2]
    array([[0, 1],
           [1, 1],
           [1, 0]])

Voila! Если вы хотите вытащить все подразделы, вы можете перебирать их, что говорит вам, сколько разных групп у вас в массиве.