Mam numeryczną tablicę liczb, na przykład
a = np.array([1, 3, 5, 6, 9, 10, 14, 15, 56])
Chciałbym znaleźć wszystkie indeksy elementów w określonym zakresie. Na przykład, jeśli zakres to (6, 10), odpowiedź powinna wynosić (3, 4, 5). Czy jest do tego wbudowana funkcja?
np.nonzero(np.logical_and(a>=6, a<=10))
.np.where((a > 6) & (a <= 10))
np.logical_and
jest odrobinę szybsza niż&
chociaż. Inp.where
jest szybszy niżnp.nonzero
.Jak w odpowiedzi @ deinonychusaur, ale jeszcze bardziej zwięzłe:
In [7]: np.where((a >= 6) & (a <=10)) Out[7]: (array([3, 4, 5]),)
źródło
a[(a >= 6) & (a <= 10)]
jeślia
jest tablicą numpy.a
jest tablicą numpyPomyślałem, że dodam to, ponieważ
a
w podanym przykładzie jest posortowany: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])
źródło
a = np.array([1,2,3,4,5,6,7,8,9]) b = a[(a>2) & (a<8)]
źródło
Podsumowanie odpowiedzi
Aby zrozumieć, jaka jest najlepsza odpowiedź, możemy określić czas, używając innego rozwiązania. Niestety pytanie nie było dobrze postawione, więc są odpowiedzi na różne pytania, tutaj staram się wskazać odpowiedź na to samo pytanie. Biorąc pod uwagę tablicę:
a = np.array([1, 3, 5, 6, 9, 10, 14, 15, 56])
Odpowiedzią powinny być indeksy elementów między pewnym przedziałem, który zakładamy włącznie, w tym przypadku 6 i 10.
answer = (3, 4, 5)
Odpowiadające wartościom 6,9,10.
Aby przetestować najlepszą odpowiedź, możemy użyć tego kodu.
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)")]', ]
Wyniki
Wyniki przedstawiono na poniższym wykresie. Na górze najszybsze rozwiązania. Jeśli zamiast indeksów chcesz wyodrębnić wartości, możesz przeprowadzić testy przy użyciu funkcji functions2, ale wyniki są prawie takie same.
źródło
Ten fragment kodu zwraca wszystkie liczby w tablicy numpy między dwiema wartościami:
a = np.array([1, 3, 5, 6, 9, 10, 14, 15, 56] ) a[(a>6)*(a<10)]
Działa w następujący sposób: (a> 6) zwraca tablicę numpy z True (1) i False (0), tak samo jak (a <10). Mnożąc te dwa razem, otrzymujemy tablicę z wartością True, jeśli obie instrukcje są True (ponieważ 1x1 = 1) lub False (ponieważ 0x0 = 0 i 1x0 = 0).
Część a [...] zwraca wszystkie wartości tablicy a, gdzie tablica między nawiasami zwraca instrukcję True.
Oczywiście możesz to bardziej skomplikować, mówiąc na przykład
...*(1-a<10)
co jest podobne do instrukcji „i nie”.
źródło
a = np.array([1, 3, 5, 6, 9, 10, 14, 15, 56]) np.argwhere((a>=6) & (a<=10))
źródło
Chciałem dodać numexpr do miksu:
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)
Miałoby to sens tylko w przypadku większych tablic z milionami ... lub w przypadku przekroczenia limitu pamięci.
źródło
Innym sposobem jest:
np.vectorize(lambda x: 6 <= x <= 10)(a)
która zwraca:
array([False, False, False, True, True, True, False, False, False])
Czasami jest przydatny do maskowania szeregów czasowych, wektorów itp.
źródło
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)
Wynik:
(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]
źródło
To może nie być najładniejsze, ale działa w każdym wymiarze
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)
źródło
Możesz użyć,
np.clip()
aby osiągnąć to samo:a = [1, 3, 5, 6, 9, 10, 14, 15, 56] np.clip(a,6,10)
Jednak przechowuje wartości mniejsze niż i większe niż odpowiednio 6 i 10.
źródło