Сделать все нули в массиве numpy 2d за пределами ограничительной рамки - PullRequest
1 голос
/ 20 февраля 2020

Скажем, у меня есть numpy 2d-массив вроде:

>>> ar
array([[1, 2, 3, 1, 2, 3, 1, 7, 2, 3],
       [4, 3, 2, 4, 5, 5, 6, 5, 2, 1],
       [5, 4, 2, 4, 6, 2, 4, 2, 1, 4],
       [1, 5, 6, 1, 4, 2, 2, 4, 1, 4],
       [7, 4, 5, 6, 2, 5, 3, 5, 6, 7]])

Я определяю ограничивающую рамку следующим образом, и я хочу, чтобы все элементы в ar, которые не в ограничительной рамке все становятся нулями:

>>> my_bbox = ((2, 7), (1, 3))

>>> make_zeros(ar, bounding_box)
array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
       [0, 0, 2, 4, 5, 5, 6, 5, 0, 0],
       [0, 0, 2, 4, 6, 2, 4, 2, 0, 0],
       [0, 0, 6, 1, 4, 2, 2, 4, 0, 0],
       [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])

Помимо «очевидных» (а также уродливых и неэффективных) циклических методов, существует ли операция среза / векторного типа для достижения этого? Я считаю, что маски массивов могут работать, но не знаю, как именно.

Ответы [ 5 ]

1 голос
/ 20 февраля 2020

Как насчет этого?

import numpy as np

arr = np.array([[1, 2, 3, 1, 2, 3, 1, 7, 2, 3],
                [4, 3, 2, 4, 5, 5, 6, 5, 2, 1],
                [5, 4, 2, 4, 6, 2, 4, 2, 1, 4],
                [1, 5, 6, 1, 4, 2, 2, 4, 1, 4],
                [7, 4, 5, 6, 2, 5, 3, 5, 6, 7]])

print(arr, end='\n\n')

first_idx = (1, 3)
second_idx = (2, 7)

first_slice = slice(first_idx[0], first_idx[1] + 1)
second_slice = slice(second_idx[0], second_idx[1] + 1)

res = np.zeros_like(arr)
res[first_slice, second_slice] = arr[first_slice, second_slice]

print(res)

Вывод:

[[1 2 3 1 2 3 1 7 2 3]
 [4 3 2 4 5 5 6 5 2 1]
 [5 4 2 4 6 2 4 2 1 4]
 [1 5 6 1 4 2 2 4 1 4]
 [7 4 5 6 2 5 3 5 6 7]]

[[0 0 0 0 0 0 0 0 0 0]
 [0 0 2 4 5 5 6 5 0 0]
 [0 0 2 4 6 2 4 2 0 0]
 [0 0 6 1 4 2 2 4 0 0]
 [0 0 0 0 0 0 0 0 0 0]]

Я почти уверен, что все еще можно улучшить, хотя.

1 голос
/ 20 февраля 2020

Вы можете создать копию массива, а затем написать нужную подматрицу поверх него:

ar_zeroed = np.zeros(ar.shape).astype(int)
slice1, slice2 = slice(my_bbox[0][0], my_bbox[0][1]+1),
                 slice(my_bbox[1][0], my_bbox[1][1]+1)
ar_zeroed[slice2, slice1] = ar[slice2, slice1]

Обратите внимание, что измерения поменяются местами в ограничительной рамке

0 голосов
/ 20 февраля 2020

Думаю, на него уже ответили, но я все равно попробую:

import numpy as np

bbox = ((2, 7), (1, 3))

arr = np.array([[1, 2, 3, 1, 2, 3, 1, 7, 2, 3],
       [4, 3, 2, 4, 5, 5, 6, 5, 2, 1],
       [5, 4, 2, 4, 6, 2, 4, 2, 1, 4],
       [1, 5, 6, 1, 4, 2, 2, 4, 1, 4],
       [7, 4, 5, 6, 2, 5, 3, 5, 6, 7]])

zeros = np.zeros(arr.shape)

zeros[bbox[1][0]:bbox[1][1]+1, 
      bbox[0][0]:bbox[0][1]+1] = arr[bbox[1][0]:bbox[1][1]+1, 
                                     bbox[0][0]:bbox[0][1]+1]

print(zeros)

Out:

[[0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
 [0. 0. 2. 4. 5. 5. 6. 5. 0. 0.]
 [0. 0. 2. 4. 6. 2. 4. 2. 0. 0.]
 [0. 0. 6. 1. 4. 2. 2. 4. 0. 0.]
 [0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]]
0 голосов
/ 20 февраля 2020

Я только думал об этом решении

a = np.random.uniform(1, 10, [7, 8]).astype(int)
print(a)

b = np.zeros([7, 8]).astype(int)
b[1:4, 2:5] = 1

print(a * b)

Выходы

[[8 3 8 5 8 3 5 7]
 [8 8 2 8 5 4 3 5]
 [5 2 2 2 5 1 4 7]
 [5 8 9 3 5 6 4 1]
 [3 6 1 1 4 6 4 8]
 [9 5 2 7 8 2 1 1]
 [1 4 5 4 2 6 2 4]]

[[0 0 0 0 0 0 0 0]
 [0 0 2 8 5 0 0 0]
 [0 0 2 2 5 0 0 0]
 [0 0 9 3 5 0 0 0]
 [0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0]]

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

0 голосов
/ 20 февраля 2020

Вы пытаетесь что-то сделать с кусочками ar[1:3+1, 2:7+1]. Выражение в квадратных скобках преобразуется интерпретатором в кортеж из slice объектов. Вы можете программно создать ту же последовательность фрагментов и передать их в качестве индекса в массив. Это может быть использовано в нескольких подходах.

"Самое простое" - создать новый массив нулей и назначить необходимый диапазон:

index = tuple(slice(start, stop + 1) for start, stop in bounding_box)
result = np.zeros_like(ar)
result[index] = ar[index]

Другой способ - создать маску. , инвертируйте его и установите элементы, которым он соответствует, в ноль:

mask = np.ones(ar.shape, dtype=np.bool)
mask[index] = zero
ar[mask] = 0

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

index = [slice(None) for _ in range(ar.ndim)]
for dim, (start, stop) in enumerate(bounding_box):
    # Blank out initial portion
    index[dim] = slice(None, start)
    ar[tuple(index)] = 0
    # Blank out trailing portion
    index[dim] = slice(stop + 1, None)
    ar[tuple(index)] = 0
    # Reinstate ":"
    index[dim] = slice(None)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...