Numpy: tìm chỉ mục của các phần tử trong phạm vi


85

Ví dụ: tôi có một dãy số vô cùng phức tạp,

a = np.array([1, 3, 5, 6, 9, 10, 14, 15, 56])  

Tôi muốn tìm tất cả các chỉ mục của các phần tử trong một phạm vi cụ thể. Ví dụ, nếu phạm vi là (6, 10), thì câu trả lời phải là (3, 4, 5). Có một chức năng tích hợp để làm điều này?

Câu trả lời:


140

Bạn có thể sử dụng np.wheređể nhận các chỉ số và np.logical_andđặt hai điều kiện:

import numpy as np
a = np.array([1, 3, 5, 6, 9, 10, 14, 15, 56])

np.where(np.logical_and(a>=6, a<=10))
# returns (array([3, 4, 5]),)

6
Btw, điều tương tự đạt được bởi np.nonzero(np.logical_and(a>=6, a<=10)).
3lectrologos 13/12/12

10
Ngoài ra np.where((a > 6) & (a <= 10))
ELinda

dường như không hoạt động tốt với mảng đa chiều
Monica Heddneck

1
@ELinda np.logical_andnhanh hơn một chút &. Và np.wherenhanh hơn np.nonzero.
Skillmon thích topanswers.xyz

Nó có hiệu suất rất tệ đối với các mảng lớn hơn
EZLearner

62

Như trong câu trả lời của @ deinonychusaur, nhưng cô đọng hơn:

In [7]: np.where((a >= 6) & (a <=10))
Out[7]: (array([3, 4, 5]),)

19
Đẹp. Bạn cũng có thể làm a[(a >= 6) & (a <= 10)]nếu alà một mảng numpy.
ws_e_c421

1
Chỉ trong trường hợp có người bị nhầm lẫn như tôi đã làm với cách diễn đạt của bình luận: điều này không làm việc cho các danh sách bình thường, nó chỉ nếu alà một mảng NumPy
Giáo sư

14

Tôi nghĩ rằng tôi sẽ thêm điều này bởi vì atrong ví dụ bạn đưa ra được sắp xếp:

import numpy as np
a = [1, 3, 5, 6, 9, 10, 14, 15, 56] 
start = np.searchsorted(a, 6, 'left')
end = np.searchsorted(a, 10, 'right')
rng = np.arange(start, end)
rng
# array([3, 4, 5])


6

Tóm tắt các câu trả lời

Để hiểu câu trả lời tốt nhất là gì, chúng ta có thể xác định thời gian bằng cách sử dụng các giải pháp khác nhau. Thật không may, câu hỏi không được đặt ra tốt nên có những câu trả lời cho các câu hỏi khác nhau, ở đây tôi cố gắng chỉ ra câu trả lời cho cùng một câu hỏi. Cho mảng:

a = np.array([1, 3, 5, 6, 9, 10, 14, 15, 56])

Câu trả lời phải là chỉ số của các phần tử giữa một phạm vi nhất định, chúng tôi giả định là bao gồm, trong trường hợp này là 6 và 10.

answer = (3, 4, 5)

Tương ứng với các giá trị 6,9,10.

Để kiểm tra câu trả lời tốt nhất, chúng ta có thể sử dụng mã này.

import timeit
setup = """
import numpy as np
import numexpr as ne

a = np.array([1, 3, 5, 6, 9, 10, 14, 15, 56])
# we define the left and right limit
ll = 6
rl = 10

def sorted_slice(a,l,r):
    start = np.searchsorted(a, l, 'left')
    end = np.searchsorted(a, r, 'right')
    return np.arange(start,end)
"""

functions = ['sorted_slice(a,ll,rl)', # works only for sorted values
'np.where(np.logical_and(a>=ll, a<=rl))[0]',
'np.where((a >= ll) & (a <=rl))[0]',
'np.where((a>=ll)*(a<=rl))[0]',
'np.where(np.vectorize(lambda x: ll <= x <= rl)(a))[0]',
'np.argwhere((a>=ll) & (a<=rl)).T[0]', # we traspose for getting a single row
'np.where(ne.evaluate("(ll <= a) & (a <= rl)"))[0]',]

functions2 = [
   'a[np.logical_and(a>=ll, a<=rl)]',
   'a[(a>=ll) & (a<=rl)]',
   'a[(a>=ll)*(a<=rl)]',
   'a[np.vectorize(lambda x: ll <= x <= rl)(a)]',
   'a[ne.evaluate("(ll <= a) & (a <= rl)")]',
]

Các kết quả

Kết quả được báo cáo trong biểu đồ sau. Về đầu trang các giải pháp nhanh nhất. nhập mô tả hình ảnh ở đây Nếu thay vì các chỉ mục bạn muốn trích xuất các giá trị, bạn có thể thực hiện các bài kiểm tra bằng cách sử dụng functions2 nhưng kết quả gần như giống nhau.


Các kết quả này chỉ áp dụng cho một mảng có độ dài cụ thể (ở đây bạn đã chọn một mảng rất nhỏ). Các kết quả này được thay đổi nhanh chóng đối với các mảng lớn hơn
EZLearner

4

Đoạn mã này trả về tất cả các số trong một mảng rỗng giữa hai giá trị:

a = np.array([1, 3, 5, 6, 9, 10, 14, 15, 56] )
a[(a>6)*(a<10)]

Nó hoạt động như sau: (a> 6) trả về một mảng numpy với True (1) và False (0), cũng vậy (a <10). Bằng cách nhân hai giá trị này với nhau, bạn sẽ nhận được một mảng có giá trị Đúng, nếu cả hai câu lệnh đều Đúng (vì 1x1 = 1) hoặc Sai (vì 0x0 = 0 và 1x0 = 0).

Phần a [...] trả về tất cả các giá trị của mảng a trong đó mảng giữa các dấu ngoặc trả về một câu lệnh True.

Tất nhiên, bạn có thể làm cho việc này phức tạp hơn bằng cách nói

...*(1-a<10) 

tương tự như câu lệnh "and Not".


1
a = np.array([1, 3, 5, 6, 9, 10, 14, 15, 56])
np.argwhere((a>=6) & (a<=10))

1

Muốn thêm sốxpr vào hỗn hợp:

import numpy as np
import numexpr as ne

a = np.array([1, 3, 5, 6, 9, 10, 14, 15, 56])  

np.where(ne.evaluate("(6 <= a) & (a <= 10)"))[0]
# array([3, 4, 5], dtype=int64)

Sẽ chỉ có ý nghĩa đối với các mảng lớn hơn với hàng triệu ... hoặc nếu bạn đạt đến giới hạn bộ nhớ.


1

Cách khác là với:

np.vectorize(lambda x: 6 <= x <= 10)(a)

trả về:

array([False, False, False,  True,  True,  True, False, False, False])

Nó đôi khi hữu ích để che chuỗi thời gian, vectơ, v.v.


0
s=[52, 33, 70, 39, 57, 59, 7, 2, 46, 69, 11, 74, 58, 60, 63, 43, 75, 92, 65, 19, 1, 79, 22, 38, 26, 3, 66, 88, 9, 15, 28, 44, 67, 87, 21, 49, 85, 32, 89, 77, 47, 93, 35, 12, 73, 76, 50, 45, 5, 29, 97, 94, 95, 56, 48, 71, 54, 55, 51, 23, 84, 80, 62, 30, 13, 34]

dic={}

for i in range(0,len(s),10):
    dic[i,i+10]=list(filter(lambda x:((x>=i)&(x<i+10)),s))
print(dic)

for keys,values in dic.items():
    print(keys)
    print(values)

Đầu ra:

(0, 10)
[7, 2, 1, 3, 9, 5]
(20, 30)
[22, 26, 28, 21, 29, 23]
(30, 40)
[33, 39, 38, 32, 35, 30, 34]
(10, 20)
[11, 19, 15, 12, 13]
(40, 50)
[46, 43, 44, 49, 47, 45, 48]
(60, 70)
[69, 60, 63, 65, 66, 67, 62]
(50, 60)
[52, 57, 59, 58, 50, 56, 54, 55, 51]  

0

Đây có thể không phải là đẹp nhất, nhưng phù hợp với mọi thứ

a = np.array([[-1,2], [1,5], [6,7], [5,2], [3,4], [0, 0], [-1,-1]])
ranges = (0,4), (0,4) 

def conditionRange(X : np.ndarray, ranges : list) -> np.ndarray:
    idx = set()
    for column, r in enumerate(ranges):
        tmp = np.where(np.logical_and(X[:, column] >= r[0], X[:, column] <= r[1]))[0]
        if idx:
            idx = idx & set(tmp)
        else:
            idx = set(tmp)
    idx = np.array(list(idx))
    return X[idx, :]

b = conditionRange(a, ranges)
print(b)

-4

Bạn có thể sử dụng np.clip()để đạt được điều tương tự:

a = [1, 3, 5, 6, 9, 10, 14, 15, 56]  
np.clip(a,6,10)

Tuy nhiên, nó giữ các giá trị nhỏ hơn và lớn hơn 6 và 10 tương ứng.

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.