Как разбить массив numpy на массивы numpy по столбцам? - PullRequest
2 голосов
/ 10 апреля 2020

Я хочу разделить массив numpy на основе столбцов, если все значения столбца равны нулю. Если последовательность столбцов имеет только 0, как первые два столбца выборочного массива, эту группу следует отбросить.

Есть ли какое-либо эффективное решение?

Пример ввода numpy массив:

[[0.   0.   0.   255.   0.   255.   0.   0.   0.  ]
 [0.   0.   0.   255.   0.   255.   0.   0.   0.  ]
 [0.   0.   0.   255.   0.   255.   255. 0.   0.  ]
 [0.   0.   255. 255.   0.   0.     0.   0.   255.]
 [0.   0.   0.   255.   0.   255.   0.   0.   0.  ]
 [0.   0.   0.   255.   0.   255.   0.   0.   0.  ]
 [0.   0.   0.   255.   0.   255.   0.   0.   0.  ]
]

Ожидаемый вывод numpy массив:

[[
  [0.    255.]
  [0.    255.]
  [0.    255.]
  [255.  255.]
  [0.    255.]
  [0.    255.]
  [0.    255.]
 ]
 [
  [255. 0.  ]
  [255. 0.  ]
  [255. 255.]
  [0.   0.  ]
  [255. 0.  ]
  [255. 0.  ]
  [255. 0.  ]
 ]
 [
  [0.  ]
  [0.  ]
  [0.  ] 
  [255.] 
  [0.  ]
  [0.  ]
  [0.  ]
 ]
]

Ответы [ 4 ]

4 голосов
/ 10 апреля 2020

Вы можете использовать itertools.groupby и понимание списка

from itertools import groupby

m = a.any(0)
out = [a[:,[*g]] for k, g in groupby(np.arange(len(m)), lambda x: m[x] != 0) if k]

Out[180]:
[array([[  0, 255],
        [  0, 255],
        [  0, 255],
        [255, 255],
        [  0, 255],
        [  0, 255],
        [  0, 255]]),
 array([[255,   0],
        [255,   0],
        [255, 255],
        [  0,   0],
        [255,   0],
        [255,   0],
        [255,   0]]),
 array([[  0],
        [  0],
        [  0],
        [255],
        [  0],
        [  0],
        [  0]])]

Примечание : a - это ваш образец массива


Как в комментарии, если вы хотите отбросить столбцы, имеющие только одно ненулевое значение, вам нужно только изменить m на другую маску, чтобы обрабатывать все 0 и one non-zero

m = (a != 0).sum(0) > 1    
out = [a[:,[*g]] for k, g in groupby(np.arange(len(m)), lambda x: m[x] != 0) if k]

Out[204]:
[array([[255],
        [255],
        [255],
        [255],
        [255],
        [255],
        [255]]),
 array([[255],
        [255],
        [255],
        [  0],
        [255],
        [255],
        [255]])]
3 голосов
/ 10 апреля 2020

Одним из решений является использование библиотеки scipy.ndimage для пометки столбцов любыми ненулевыми элементами, а затем разбиение массива по этим меткам.

https://docs.scipy.org/doc/scipy/reference/generated/scipy.ndimage.label.html

Например ...

import numpy as np
from scipy import ndimage

# convert input string to numpy array
s = '''[[0.   0.   0.   255.   0.   255.   0.   0.   0.  ]
 [0.   0.   0.   255.   0.   255.   0.   0.   0.  ]
 [0.   0.   0.   255.   0.   255.   255. 0.   0.  ]
 [0.   0.   255. 255.   0.   0.     0.   0.   255.]
 [0.   0.   0.   255.   0.   255.   0.   0.   0.  ]
 [0.   0.   0.   255.   0.   255.   0.   0.   0.  ]
 [0.   0.   0.   255.   0.   255.   0.   0.   0.  ]
]'''
X = eval("np.array(%s)" % s.replace('.', ',').replace('\n', ',')).astype(float)

# label continuous columns with any non-zero values
labels, N = ndimage.label((X > 0).any(0))

# display the column splits
for n in range(1, N+1):
    mask = labels == n
    print(X[:, mask])

Должен отображаться ...

[[  0. 255.]
 [  0. 255.]
 [  0. 255.]
 [255. 255.]
 [  0. 255.]
 [  0. 255.]
 [  0. 255.]]
[[255.   0.]
 [255.   0.]
 [255. 255.]
 [  0.   0.]
 [255.   0.]
 [255.   0.]
 [255.   0.]]
[[  0.]
 [  0.]
 [  0.]
 [255.]
 [  0.]
 [  0.]
 [  0.]]
2 голосов
/ 10 апреля 2020

Если вы не можете или не хотите использовать scipy, это также работает:

def twoCols():
    arr = np.array([[0. ,  0.,   0.,   255. ,  0.,   255.,   0.  , 0. ,  0.  ],[0.  , 0. ,  0. ,  255. ,  0.,   255.,   0.  , 0. ,  0.  ],[0.,   0. ,  0.  , 255.,   0.  , 255. ,  255. ,0. ,  0.  ],[0.   ,0. ,  255., 255. ,  0. ,  0. ,    0. ,  0. ,  255.],[0.,   0. ,  0. ,  255. ,  0.,   255. ,  0. ,  0.,   0.  ],[0.,   0. ,  0. ,  255.,   0. ,  255. ,  0. ,  0.,   0.  ],[0.,   0. ,  0. ,  255. ,  0. ,  255. ,  0. ,  0. ,  0.  ]], dtype=np.float64)
    arrs = []   
    for c in range(arr.shape[1]):
        if c == arr.shape[1]-1:
            if sum(arr[:,c]) > 0:
                    arrs.append(arr[:,c:])              
        elif sum(arr[:,c]) > 0 and sum(arr[:,c+1]) > 0:
            arrs.append(arr[:,c:c+2])                           
    return arrs

>>> twoCols()
[array([[   0.,  255.],
       [   0.,  255.],
       [   0.,  255.],
       [ 255.,  255.],
       [   0.,  255.],
       [   0.,  255.],
       [   0.,  255.]]), array([[ 255.,    0.],
       [ 255.,    0.],
       [ 255.,  255.],
       [   0.,    0.],
       [ 255.,    0.],
       [ 255.,    0.],
       [ 255.,    0.]]), array([[   0.],
       [   0.],
       [   0.],
       [ 255.],
       [   0.],
       [   0.],
       [   0.]])]
0 голосов
/ 10 апреля 2020

Это не тот формат, который вы просили. Но мне нравится элегантность:

import numpy as np
data = np.array([
 [0.,   0.,   0.,   255.,   0.,   255.,   0.,   0.,   0.  ],
 [0.,   0.,   0.,   255.,   0.,   255.,   0.,   0.,   0.  ],
 [0.,   0.,   0.,   255.,   0.,   255.,   255., 0.,   0.  ],
 [0.,   0.,   255., 255.,   0.,   0.,     0.,   0.,   255.],
 [0.,   0.,   0.,   255.,   0.,   255.,   0.,   0.,   0.  ],
 [0.,   0.,   0.,   255.,   0.,   255.,   0.,   0.,   0.  ],
 [0.,   0.,   0.,   255.,   0.,   255.,   0.,   0.,   0.  ],
])
a=np.zeros((data.shape[0]))            
cols = np.any(data!=0, axis=0)
for i, c in enumerate(cols):
    if c:
        a = np.column_stack((a, data[:,i]))
a = a[:,1:]
print(a)

Выход:


[[  0. 255. 255.   0.   0.]
 [  0. 255. 255.   0.   0.]
 [  0. 255. 255. 255.   0.]
 [255. 255.   0.   0. 255.]
 [  0. 255. 255.   0.   0.]
 [  0. 255. 255.   0.   0.]
 [  0. 255. 255.   0.   0.]]
...