Заміна елементів Numpy, якщо умова виконана


94

У мене є великий масив numpy, яким мені потрібно маніпулювати, щоб кожен елемент змінився на 1 або 0, якщо умова дотримана (пізніше буде використана як піксельна маска). У масиві є близько 8 мільйонів елементів, і мій поточний метод займає занадто багато часу для трубопроводу скорочення:

for (y,x), value in numpy.ndenumerate(mask_data): 

    if mask_data[y,x]<3: #Good Pixel
        mask_data[y,x]=1
    elif mask_data[y,x]>3: #Bad Pixel
        mask_data[y,x]=0

Чи існує функція numpy, яка могла б це пришвидшити?


1
Що ви хочете, щоб сталося, якщо mask_data[y,x]==3?
DSM

Хороший момент, це все одно буде поганий піксель. Я зміню умову наif mask_data[y,x]>=3:
ChrisFro

Відповіді:


128
>>> import numpy as np
>>> a = np.random.randint(0, 5, size=(5, 4))
>>> a
array([[4, 2, 1, 1],
       [3, 0, 1, 2],
       [2, 0, 1, 1],
       [4, 0, 2, 3],
       [0, 0, 0, 2]])
>>> b = a < 3
>>> b
array([[False,  True,  True,  True],
       [False,  True,  True,  True],
       [ True,  True,  True,  True],
       [False,  True,  True, False],
       [ True,  True,  True,  True]], dtype=bool)
>>> 
>>> c = b.astype(int)
>>> c
array([[0, 1, 1, 1],
       [0, 1, 1, 1],
       [1, 1, 1, 1],
       [0, 1, 1, 0],
       [1, 1, 1, 1]])

Ви можете скоротити це за допомогою:

>>> c = (a < 3).astype(int)

2
як зробити так, щоб це сталося з певними стовпцями, ніколи не вирізавши деякі стовпці, а потім призначивши знову? наприклад, лише елементи у стовпцях [2, 3] повинні змінювати значення, коли виконуються умови, тоді як інші стовпці не змінюватимуться, незалежно від того, дотримуються умови чи ні.
kuixiong

Правда, але лише у випадку нулів та одиниць. Дивіться нижче загальну відповідь нижче (за ціною ефективності)
borgr

89
>>> a = np.random.randint(0, 5, size=(5, 4))
>>> a
array([[0, 3, 3, 2],
       [4, 1, 1, 2],
       [3, 4, 2, 4],
       [2, 4, 3, 0],
       [1, 2, 3, 4]])
>>> 
>>> a[a > 3] = -101
>>> a
array([[   0,    3,    3,    2],
       [-101,    1,    1,    2],
       [   3, -101,    2, -101],
       [   2, -101,    3,    0],
       [   1,    2,    3, -101]])
>>>

Див., Наприклад, Індексація за допомогою булевих масивів .


3
чудові речі, дякую! Якщо ви хочете посилатися на змінене значення, ви можете використати щось на зразок a[a > 3] = -101+a[a > 3].
pexmar

1
@pexmar Хоча, якщо ви це зробите, a[a > 3] = -101+a[a > 3]замість a[a > 3] += -101вас, швидше за все, зіткнеться витік пам'яті.
Самуель Превост

1
як ви посилаєтесь на значення, яке ви змінюєте, як запитував pexmar ??
Хуан,

34

Швидкий (і самий гнучкий) спосіб полягає у використанні np.where , який вибирає між двома масивами в відповідно до маскою (масив дійсних і помилкових значень):

import numpy as np
a = np.random.randint(0, 5, size=(5, 4))
b = np.where(a<3,0,1)
print('a:',a)
print()
print('b:',b)

який дасть:

a: [[1 4 0 1]
 [1 3 2 4]
 [1 0 2 1]
 [3 1 0 0]
 [1 4 0 1]]

b: [[0 1 0 0]
 [0 1 0 1]
 [0 0 0 0]
 [1 0 0 0]
 [0 1 0 0]]

1
який буде найкращий спосіб, якщо я не хочу замінювати чим-небудь, якщо умова не виконується? тобто замінювати лише наданим значенням, коли умова виконується, якщо не залишити оригінальне число як є ....
Абхішек Сенгупта

1
щоб замінити всі значення в a, які менше 3, а решта зберегти як є, використовуйтеa[a<3] = 0
Markus Dutschke

3

Ви можете створити свій масив маски в один крок, як це

mask_data = input_mask_data < 3

Це створює логічний масив, який потім можна використовувати як піксельну маску. Зверніть увагу, що ми не змінювали вхідний масив (як у вашому коді), але створили новий масив для зберігання даних маски - я б рекомендував зробити це таким чином.

>>> input_mask_data = np.random.randint(0, 5, (3, 4))
>>> input_mask_data
array([[1, 3, 4, 0],
       [4, 1, 2, 2],
       [1, 2, 3, 0]])
>>> mask_data = input_mask_data < 3
>>> mask_data
array([[ True, False, False,  True],
       [False,  True,  True,  True],
       [ True,  True, False,  True]], dtype=bool)
>>> 

1
Так. Якщо ОП дійсно хоче 0 і 1, він міг би використовувати .astype(int)або *1, але масив Trueі Falseтак само хороший, як він.
DSM

-4

Я не впевнений, що зрозумів ваше запитання, але якщо ви напишете:

mask_data[:3, :3] = 1
mask_data[3:, 3:] = 0

Це зробить усі значення даних маски, індекси x та y яких менші за 3, рівними 1, а всі інші - рівними 0

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.