Làm thế nào để tôi chọn các phần tử của một điều kiện cho trước?


156

Giả sử tôi có một mảng NumPy x = [5, 2, 3, 1, 4, 5], y = ['f', 'o', 'o', 'b', 'a', 'r']. Tôi muốn chọn các phần tử ytương ứng với các phần tử xlớn hơn 1 và nhỏ hơn 5.

Tôi đã thử

x = array([5, 2, 3, 1, 4, 5])
y = array(['f','o','o','b','a','r'])
output = y[x > 1 & x < 5] # desired output is ['o','o','a']

nhưng điều này không làm việc. Làm thế nào tôi sẽ làm điều này?

Câu trả lời:


220

Biểu thức của bạn hoạt động nếu bạn thêm dấu ngoặc đơn:

>>> y[(1 < x) & (x < 5)]
array(['o', 'o', 'a'], 
      dtype='|S1')

1
Điều đó thật tuyệt .. vecMask = 1 <x tạo ra mặt nạ vector như vecMask = (Sai, Đúng, ...), có thể được kết hợp với các mặt nạ vector khác. Mỗi phần tử là điều kiện để lấy các phần tử của vectơ nguồn (Đúng) hoặc không (Sai). Điều này cũng có thể được sử dụng với phiên bản đầy đủ numpy.extract (vecMask, vecSrc) hoặc numpy.where (vecMask, vecSrc, vecSrc2).
MasterControl

6
@JennyYueJin: Nó xảy ra vì sự ưu tiên. (Bitwise) &có độ ưu tiên cao hơn <>, do đó có độ ưu tiên cao hơn (logic) and. x > 1 and x < 5trước hết là tạo ra sự bất bình đẳng và sau đó là sự kết hợp logic; x > 1 & x < 5đánh giá kết hợp bitwise của 1và (các giá trị trong) x, sau đó là bất đẳng thức. (x > 1) & (x < 5)buộc các bất đẳng thức phải đánh giá trước, vì vậy tất cả các hoạt động xảy ra theo thứ tự dự định và kết quả đều được xác định rõ. Xem tài liệu ở đây.
calavicci

@ ru111 Nó cũng hoạt động trên Python 3.6 (không có lý do gì để nó ngừng hoạt động).
jfs

Tôi nhận được "ValueError: Giá trị thật của một mảng có nhiều phần tử là mơ hồ. Sử dụng a.any () hoặc a.all ()"
ru111

@ ru111 bạn nên viết (0 < x) & (x < 10)(như trong câu trả lời) thay vì 0 < x < 10không hoạt động cho các mảng khó hiểu trên bất kỳ phiên bản Python nào.
jfs

34

IMO OP không thực sự muốn np.bitwise_and()(aka &) nhưng thực sự muốn np.logical_and()vì họ đang so sánh các giá trị logic như TrueFalse- xem bài đăng SO này trên logic so với bitwise để thấy sự khác biệt.

>>> x = array([5, 2, 3, 1, 4, 5])
>>> y = array(['f','o','o','b','a','r'])
>>> output = y[np.logical_and(x > 1, x < 5)] # desired output is ['o','o','a']
>>> output
array(['o', 'o', 'a'],
      dtype='|S1')

Và cách tương đương để làm điều này là bằng np.all()cách thiết lập axisđối số một cách thích hợp.

>>> output = y[np.all([x > 1, x < 5], axis=0)] # desired output is ['o','o','a']
>>> output
array(['o', 'o', 'a'],
      dtype='|S1')

Bởi các con số:

>>> %timeit (a < b) & (b < c)
The slowest run took 32.97 times longer than the fastest. This could mean that an intermediate result is being cached.
100000 loops, best of 3: 1.15 µs per loop

>>> %timeit np.logical_and(a < b, b < c)
The slowest run took 32.59 times longer than the fastest. This could mean that an intermediate result is being cached.
1000000 loops, best of 3: 1.17 µs per loop

>>> %timeit np.all([a < b, b < c], 0)
The slowest run took 67.47 times longer than the fastest. This could mean that an intermediate result is being cached.
100000 loops, best of 3: 5.06 µs per loop

vì vậy sử dụng np.all()chậm hơn, nhưng&logical_andlà như nhau.


7
Bạn cần cẩn thận một chút về cách bạn nói về những gì được đánh giá. Ví dụ, trong output = y[np.logical_and(x > 1, x < 5)], x < 5 được đánh giá (có thể tạo ra một mảng khổng lồ), mặc dù đó là đối số thứ hai, bởi vì đánh giá đó xảy ra bên ngoài hàm. IOW, logical_andđược thông qua hai đối số đã được đánh giá. Điều này khác với trường hợp thông thường a and b, trong đó bkhông được đánh giá nếu alà truelike.
DSM

15
không có sự khác biệt giữa bitwise_and () và logic_and () cho mảng boolean
jfs

21

Thêm một chi tiết vào câu trả lời của @JF Sebastian và @Mark Mikofski:
Nếu một người muốn có được các chỉ số tương ứng (thay vì các giá trị thực của mảng), đoạn mã sau sẽ thực hiện:

Để đáp ứng nhiều điều kiện (tất cả):

select_indices = np.where( np.logical_and( x > 1, x < 5) )[0] #   1 < x <5

Để đáp ứng nhiều điều kiện (hoặc):

select_indices = np.where( np.logical_or( x < 1, x > 5 ) )[0] # x <1 or x >5

2
Lưu ý rằng numpy.where sẽ không chỉ trả về một mảng các chỉ mục, mà thay vào đó sẽ trả về một tuple (đầu ra của condition.nonzero ()) có chứa các mảng - trong trường hợp này (the array of indices you want,), vì vậy bạn sẽ cần select_indices = np.where(...)[0]nhận được kết quả bạn muốn và mong đợi.
calavicci

5

Tôi thích sử dụng np.vectorizecho các nhiệm vụ như vậy. Hãy xem xét những điều sau đây:

>>> # Arrays
>>> x = np.array([5, 2, 3, 1, 4, 5])
>>> y = np.array(['f','o','o','b','a','r'])

>>> # Function containing the constraints
>>> func = np.vectorize(lambda t: t>1 and t<5)

>>> # Call function on x
>>> y[func(x)]
>>> array(['o', 'o', 'a'], dtype='<U1')

Ưu điểm là bạn có thể thêm nhiều loại ràng buộc hơn trong hàm vectơ.

Hy vọng nó giúp.


1
Đây không phải là một cách tốt để lập chỉ mục trong NumPy (nó sẽ rất chậm).
Alex Riley

1

Thật ra tôi sẽ làm theo cách này:

L1 là danh sách chỉ mục của các yếu tố thỏa mãn điều kiện 1; (có thể bạn có thể sử dụng somelist.index(condition1)hoặc np.where(condition1)để lấy L1.)

Tương tự, bạn nhận được L2, một danh sách các yếu tố thỏa mãn điều kiện 2;

Sau đó, bạn tìm giao lộ bằng cách sử dụng intersect(L1,L2).

Bạn cũng có thể tìm thấy giao điểm của nhiều danh sách nếu bạn có nhiều điều kiện để đáp ứng.

Sau đó, bạn có thể áp dụng chỉ mục trong bất kỳ mảng nào khác, ví dụ: x.


0

Đối với mảng 2D, bạn có thể làm điều này. Tạo mặt nạ 2D bằng điều kiện. Kiểu chữ mặt nạ điều kiện thành int hoặc float, tùy thuộc vào mảng và nhân nó với mảng ban đầu.

In [8]: arr
Out[8]: 
array([[ 1.,  2.,  3.,  4.,  5.],
       [ 6.,  7.,  8.,  9., 10.]])

In [9]: arr*(arr % 2 == 0).astype(np.int) 
Out[9]: 
array([[ 0.,  2.,  0.,  4.,  0.],
       [ 6.,  0.,  8.,  0., 10.]])
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.