Thay thế các phần tử Numpy nếu điều kiện được đáp ứng


94

Tôi có một mảng numpy lớn mà tôi cần thao tác để mỗi phần tử được thay đổi thành 1 hoặc 0 nếu một điều kiện được đáp ứng (sẽ được sử dụng làm mặt nạ pixel sau này). Có khoảng 8 triệu phần tử trong mảng và phương pháp hiện tại của tôi mất quá nhiều thời gian cho quá trình giảm:

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

Có một chức năng numpy sẽ tăng tốc độ này không?


1
Bạn muốn điều gì xảy ra nếu mask_data[y,x]==3?
DSM

Điểm tốt, đó vẫn sẽ là một pixel xấu. Tôi sẽ thay đổi điều kiện thànhif mask_data[y,x]>=3:
ChrisFro

Câu trả lời:


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]])

Bạn có thể rút ngắn điều này bằng:

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

2
Làm thế nào để làm cho điều này xảy ra với các cột cụ thể mà không bao giờ cắt ra một số cột và sau đó gán lại một lần nữa? ví dụ: chỉ các phần tử trong cột [2, 3] mới nên thay đổi giá trị khi đáp ứng các điều kiện, trong khi các cột khác sẽ không thay đổi bất kể điều kiện có được đáp ứng hay không.
kuixiong 20/07/19

Đúng, nhưng chỉ đối với trường hợp số không và số một. Xem thêm câu trả lời chung bên dưới (với chi phí hiệu quả)
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]])
>>>

Hãy xem, ví dụ: Lập chỉ mục với mảng boolean .


3
công cụ tuyệt vời, cảm ơn! Nếu bạn muốn tham chiếu đến giá trị bạn thay đổi, bạn có thể sử dụng một cái gì đó như a[a > 3] = -101+a[a > 3].
pexmar

1
@pexmar Mặc dù nếu bạn làm a[a > 3] = -101+a[a > 3]thay vì a[a > 3] += -101bạn rất có thể sẽ nhớ khuôn mặt rò rỉ.
Samuel Prevost

1
làm thế nào để bạn tham khảo giá trị bạn thay đổi như pexmar đã hỏi ??
Juan

34

Cách nhanh nhất (và linh hoạt nhất) là sử dụng np.where , chọn giữa hai mảng theo một mặt nạ (mảng giá trị đúng và sai):

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)

sẽ tạo ra:

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
Cách tốt nhất sẽ là gì nếu tôi không muốn thay thế bằng bất cứ thứ gì nếu điều kiện không được đáp ứng? tức là Chỉ thay thế bằng giá trị cung cấp khi điều kiện được đáp ứng, nếu không để nguyên số ban đầu ....
Abhishek Sengupta

1
để thay thế tất cả các giá trị trong a, nhỏ hơn 3 và giữ nguyên giá trị còn lại, hãy sử dụnga[a<3] = 0
Markus Dutschke

3

Bạn có thể tạo mảng mặt nạ của mình trong một bước như thế này

mask_data = input_mask_data < 3

Điều này tạo ra một mảng boolean sau đó có thể được sử dụng làm mặt nạ pixel. Lưu ý rằng chúng tôi chưa thay đổi mảng đầu vào (như trong mã của bạn) nhưng đã tạo một mảng mới để giữ dữ liệu mặt nạ - tôi khuyên bạn nên làm theo cách này.

>>> 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
Vâng. Nếu OP thực sự muốn các số 0 và 1, anh ta có thể sử dụng .astype(int)hoặc *1, nhưng một mảng của TrueFalsecũng tốt như nó.
DSM

-4

Tôi không chắc mình đã hiểu câu hỏi của bạn, nhưng nếu bạn viết:

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

Điều này sẽ làm cho tất cả các giá trị của dữ liệu mặt nạ có chỉ số x và y nhỏ hơn 3 bằng 1 và tất cả các giá trị còn lại bằng 0

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.