Numpy: aralık içindeki öğelerin dizinini bulun


88

Uyuşmuş bir sayı dizim var, örneğin,

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

Belirli bir aralıktaki öğelerin tüm dizinlerini bulmak istiyorum. Örneğin, aralık (6, 10) ise yanıt (3, 4, 5) olmalıdır. Bunu yapmak için yerleşik bir işlev var mı?

Yanıtlar:


148

np.whereEndeksleri almak ve np.logical_andiki koşul ayarlamak için kullanabilirsiniz :

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, aynısı ile elde edilir np.nonzero(np.logical_and(a>=6, a<=10)).
3lectrologos

14
Ayrıca np.where((a > 6) & (a <= 10))
ELinda

çok boyutlu dizilerle pek iyi görünmüyor
Monica Heddneck

2
@ELinda np.logical_and, &gerçi biraz daha hızlı . Ve np.wheredaha hızlıdır np.nonzero.
Skillmon topanswers.xyz'i seviyor

66

@ Deinonychusaur'un yanıtında olduğu gibi, ancak daha da kompakt:

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

20
Güzel. Ayrıca yapabilirsiniz a[(a >= 6) & (a <= 10)]eğer abir numpy dizidir.
ws_e_c421

1
Birinin yorumun ifadesiyle benim yaptığım gibi kafası karışması durumunda: bu sıradan listeler için işe yaramaz, sadece auyuşmuş bir diziyse
Prof

15

Bunu ekleyeceğimi düşündüm çünkü averdiğiniz örnekte sıralandı:

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

Cevapların özeti

En iyi cevabın ne olduğunu anlamak için farklı çözümü kullanarak biraz zamanlama yapabiliriz. Maalesef soru iyi sorulmadı, bu yüzden farklı soruların cevapları var, burada cevabı aynı soruya göstermeye çalışıyorum. Dizi verildiğinde:

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

Cevap, belirli bir aralık arasındaki elemanların indeksleri olmalıdır , bu durumda 6 ve 10'u kapsayıcı varsayıyoruz.

answer = (3, 4, 5)

6,9,10 değerlerine karşılık gelir.

En iyi cevabı test etmek için bu kodu kullanabiliriz.

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)")]',
]

Sonuçlar

Sonuçlar aşağıdaki grafikte rapor edilmektedir. En üstte en hızlı çözümler. görüntü açıklamasını buraya girin Dizinlerin yerine değerleri çıkarmak isterseniz, testleri fonksiyonlar2 kullanarak gerçekleştirebilirsiniz, ancak sonuçlar hemen hemen aynıdır.


1
Bu sonuçlar yalnızca belirli uzunlukta bir dizi için geçerlidir (burada çok küçük bir dizi seçtiniz). Bu sonuçlar daha büyük diziler için hızla değişti
EZLearner

4

Bu kod parçacığı, iki değer arasında bir numpy dizisindeki tüm sayıları döndürür:

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

Aşağıdaki gibi çalışır: (a> 6) True (1) ve False (0) ile uyuşmuş bir dizi döndürür, (a <10) da öyle. Bu ikisini çarparak, her iki ifade de True ise (çünkü 1x1 = 1) veya False (0x0 = 0 ve 1x0 = 0) ise True olan bir dizi elde edersiniz.

A [...] bölümü, parantezler arasındaki dizinin bir True ifadesi döndürdüğü, a dizisinin tüm değerlerini döndürür.

Elbette şunu söyleyerek daha karmaşık hale getirebilirsiniz:

...*(1-a<10) 

bu bir "ve Değil" ifadesine benzer.


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

2

Diğer yol şudur:

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

döndüren:

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

Bazen zaman serilerini, vektörleri vb. Maskelemek için kullanışlıdır.


1

Karışıma numexpr eklemek istedi :

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)

Yalnızca milyonları olan daha büyük diziler için ... veya bir bellek sınırına ulaşırsanız mantıklı olur.


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)

Çıktı:

(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

Bu en güzel olmayabilir, ancak her boyut için işe yarar

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

np.clip()Aynı şeyi başarmak için kullanabilirsiniz :

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

Ancak, sırasıyla 6 ve 10'dan küçük ve büyük değerleri tutar.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.