Numpy nơi chức năng nhiều điều kiện


132

Tôi có một khoảng cách gọi là dists. Tôi muốn chọn dists nằm giữa hai giá trị. Tôi đã viết dòng mã sau đây để làm điều đó:

 dists[(np.where(dists >= r)) and (np.where(dists <= r + dr))]

Tuy nhiên, điều này chỉ chọn cho điều kiện

 (np.where(dists <= r + dr))

Nếu tôi thực hiện các lệnh tuần tự bằng cách sử dụng một biến tạm thời, nó hoạt động tốt. Tại sao đoạn mã trên không hoạt động, và làm cách nào để nó hoạt động?

Chúc mừng

Câu trả lời:


203

Cách tốt nhất trong trường hợp cụ thể của bạn chỉ là thay đổi hai tiêu chí của bạn thành một tiêu chí:

dists[abs(dists - r - dr/2.) <= dr/2.]

Nó chỉ tạo ra một mảng boolean, và theo ý kiến của tôi là dễ đọc hơn vì nó nói, disttrong vòng một drhoặc r? (Mặc dù tôi xác định lại rlà trung tâm của khu vực bạn quan tâm thay vì bắt đầu, vì vậy r = r + dr/2.) Nhưng điều đó không trả lời câu hỏi của bạn.


Câu trả lời cho câu hỏi của bạn:
Bạn thực sự không cần wherenếu bạn chỉ cố gắng lọc ra các yếu tố distskhông phù hợp với tiêu chí của bạn:

dists[(dists >= r) & (dists <= r+dr)]

Bởi vì ý &chí sẽ cho bạn một yếu tố and(dấu ngoặc đơn là cần thiết).

Hoặc, nếu bạn muốn sử dụng wherevì một số lý do, bạn có thể làm:

 dists[(np.where((dists >= r) & (dists <= r + dr)))]

Tại sao:
Lý do nó không hoạt động là vì np.wheretrả về một danh sách các chỉ mục, không phải là một mảng boolean. Bạn đang cố gắng để có được andgiữa hai danh sách các số, tất nhiên không có True/ Falsegiá trị mà bạn mong đợi. Nếu ablà cả hai Truegiá trị, sau đó a and btrả về b. Vì vậy, nói một cái gì đó như [0,1,2] and [2,3,4]sẽ chỉ cung cấp cho bạn [2,3,4]. Đây là hành động:

In [230]: dists = np.arange(0,10,.5)
In [231]: r = 5
In [232]: dr = 1

In [233]: np.where(dists >= r)
Out[233]: (array([10, 11, 12, 13, 14, 15, 16, 17, 18, 19]),)

In [234]: np.where(dists <= r+dr)
Out[234]: (array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12]),)

In [235]: np.where(dists >= r) and np.where(dists <= r+dr)
Out[235]: (array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12]),)

Những gì bạn đang mong đợi để so sánh chỉ đơn giản là mảng boolean, ví dụ

In [236]: dists >= r
Out[236]: 
array([False, False, False, False, False, False, False, False, False,
       False,  True,  True,  True,  True,  True,  True,  True,  True,
        True,  True], dtype=bool)

In [237]: dists <= r + dr
Out[237]: 
array([ True,  True,  True,  True,  True,  True,  True,  True,  True,
        True,  True,  True,  True, False, False, False, False, False,
       False, False], dtype=bool)

In [238]: (dists >= r) & (dists <= r + dr)
Out[238]: 
array([False, False, False, False, False, False, False, False, False,
       False,  True,  True,  True, False, False, False, False, False,
       False, False], dtype=bool)

Bây giờ bạn có thể gọi np.wheretrên mảng boolean kết hợp:

In [239]: np.where((dists >= r) & (dists <= r + dr))
Out[239]: (array([10, 11, 12]),)

In [240]: dists[np.where((dists >= r) & (dists <= r + dr))]
Out[240]: array([ 5. ,  5.5,  6. ])

Hoặc chỉ đơn giản là lập chỉ mục mảng ban đầu với mảng boolean bằng cách lập chỉ mục ưa thích

In [241]: dists[(dists >= r) & (dists <= r + dr)]
Out[241]: array([ 5. ,  5.5,  6. ])

61

Câu trả lời được chấp nhận giải thích vấn đề đủ tốt. Tuy nhiên, cách tiếp cận Numpythonic nhiều hơn để áp dụng nhiều điều kiện là sử dụng các hàm logic numpy . Trong ase này, bạn có thể sử dụng np.logical_and:

np.where(np.logical_and(np.greater_equal(dists,r),np.greater_equal(dists,r + dr)))

11

Một điều thú vị để chỉ ở đây; cách thông thường sử dụng ORAND cũng sẽ hoạt động trong trường hợp này, nhưng với một thay đổi nhỏ. Thay vì "và" và thay vì "hoặc", thay vào đó hãy sử dụng Ampersand (&)Nhà khai thác ống (|) và nó sẽ hoạt động.

Khi chúng tôi sử dụng 'và' :

ar = np.array([3,4,5,14,2,4,3,7])
np.where((ar>3) and (ar<6), 'yo', ar)

Output:
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

Khi chúng tôi sử dụng Ampersand (&) :

ar = np.array([3,4,5,14,2,4,3,7])
np.where((ar>3) & (ar<6), 'yo', ar)

Output:
array(['3', 'yo', 'yo', '14', '2', 'yo', '3', '7'], dtype='<U11')

Và điều này cũng tương tự trong trường hợp khi chúng tôi đang cố gắng áp dụng nhiều bộ lọc trong trường hợp gấu trúc Dataframe. Bây giờ lý do đằng sau điều này phải làm một cái gì đó với Toán tử logic và Toán tử bitwise và để hiểu rõ hơn về điều tương tự, tôi khuyên bạn nên xem qua câu trả lời này hoặc Q / A tương tự trong stackoverflow.

CẬP NHẬT

Một người dùng đã hỏi, tại sao cần phải đưa ra (ar> 3) và (ar <6) trong ngoặc đơn. Vâng đây là điều. Trước khi tôi bắt đầu nói về những gì đang xảy ra ở đây, người ta cần biết về quyền ưu tiên của Người vận hành trong Python.

Tương tự như nội dung của BODMAS, python cũng được ưu tiên trước những gì nên được thực hiện trước tiên. Các mục bên trong dấu ngoặc đơn được thực hiện trước và sau đó toán tử bitwise hoạt động. Tôi sẽ trình bày bên dưới những gì xảy ra trong cả hai trường hợp khi bạn sử dụng và không sử dụng "(", ")".

Trường hợp 1:

np.where( ar>3 & ar<6, 'yo', ar)
np.where( np.array([3,4,5,14,2,4,3,7])>3 & np.array([3,4,5,14,2,4,3,7])<6, 'yo', ar)

Vì không có dấu ngoặc ở đây, toán tử bitwise ( &) đang bị nhầm lẫn ở đây rằng bạn thậm chí còn yêu cầu nó lấy logic VÀ của, bởi vì trong bảng ưu tiên toán tử nếu bạn thấy, &được ưu tiên hơn toán tử <hoặc >toán tử. Đây là bảng từ ưu tiên thấp nhất đến ưu tiên cao nhất.

nhập mô tả hình ảnh ở đây

Nó thậm chí không thực hiện <>vận hành và được yêu cầu thực hiện thao tác AND logic. Vì vậy, đó là lý do tại sao nó đưa ra lỗi đó.

Người ta có thể kiểm tra liên kết sau để tìm hiểu thêm về: quyền ưu tiên của nhà điều hành

Bây giờ đến trường hợp 2:

Nếu bạn sử dụng dấu ngoặc, bạn sẽ thấy rõ điều gì xảy ra.

np.where( (ar>3) & (ar<6), 'yo', ar)
np.where( (array([False,  True,  True,  True, False,  True, False,  True])) & (array([ True,  True,  True, False,  True,  True,  True, False])), 'yo', ar)

Hai mảng Đúng và Sai. Và bạn có thể dễ dàng thực hiện logic VÀ hoạt động trên chúng. Cung cấp cho bạn:

np.where( array([False,  True,  True, False, False,  True, False, False]),  'yo', ar)

Và phần còn lại bạn biết, np.where, đối với các trường hợp cụ thể, bất cứ nơi nào Đúng, gán giá trị đầu tiên (ví dụ ở đây 'yo') và nếu Sai, thì khác (tức là ở đây, giữ nguyên bản gốc).

Đó là tất cả. Tôi hy vọng tôi đã giải thích các truy vấn tốt.


1
Tại sao bạn phải đặt ()xung quanh (ar>3)(ar>6)?
RTrain3k

Đó là một câu hỏi thực sự tốt. Đó là một câu hỏi hay đến nỗi tôi phải tự nghĩ rằng những gì trên trái đất là nhu cầu của nó. Vì vậy, tôi đã làm, hỏi một đồng nghiệp quá và chúng tôi đã thảo luận về amd bây giờ tôi có một giải pháp cho bạn. Đặt nó trong câu trả lời là CẬP NHẬT. Nó thực sự đơn giản nhưng là một điều khó hiểu thực sự.
Amit Amola

Kiểm tra bản cập nhật RTrain3k, tôi đã trả lời truy vấn của bạn.
Amit Amola

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:

>>> # function which returns True when constraints are satisfied.
>>> func = lambda d: d >= r and d<= (r+dr) 
>>>
>>> # Apply constraints element-wise to the dists array.
>>> result = np.vectorize(func)(dists) 
>>>
>>> result = np.where(result) # Get output.

Bạn cũng có thể sử dụng np.argwherethay vì np.wherecho đầu ra rõ ràng. Nhưng đó là cuộc gọi của bạn :)

Hy vọng nó giúp.


2

Thử:

np.intersect1d(np.where(dists >= r)[0],np.where(dists <= r + dr)[0])

2

Điều này sẽ làm việc:

dists[((dists >= r) & (dists <= r+dr))]

Cách thanh lịch nhất ~ ~


2

Thử:

import numpy as np
dist = np.array([1,2,3,4,5])
r = 2
dr = 3
np.where(np.logical_and(dist> r, dist<=r+dr))

Đầu ra: (mảng ([2, 3]),)

Bạn có thể xem các hàm Logic để biết thêm chi tiết.


0

Tôi đã làm việc ra ví dụ đơn giản này

import numpy as np

ar = np.array([3,4,5,14,2,4,3,7])

print [X for X in list(ar) if (X >= 3 and X <= 6)]

>>> 
[3, 4, 5, 4, 3]

6
Không cần phải lặp đi lặp lại trong trường hợp này. NumPy có lập chỉ mục boolean.
M456
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.