Numpy: Index der Elemente innerhalb des Bereichs finden


84

Ich habe eine Reihe von Zahlen, zum Beispiel

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

Ich möchte alle Indizes der Elemente innerhalb eines bestimmten Bereichs finden. Wenn der Bereich beispielsweise (6, 10) ist, sollte die Antwort (3, 4, 5) sein. Gibt es eine eingebaute Funktion, um dies zu tun?

Antworten:


137

Sie können verwenden np.where, um Indizes abzurufen und np.logical_andzwei Bedingungen festzulegen:

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
Übrigens wird das gleiche erreicht durch np.nonzero(np.logical_and(a>=6, a<=10)).
3lectrologos

8
Auch np.where((a > 6) & (a <= 10))
ELinda

scheint nicht gut mit mehrdimensionalen Arrays zu tun
Monica Heddneck

1
@ ELinda np.logical_andist ein bisschen schneller als &obwohl. Und np.whereist schneller als np.nonzero.
Skillmon mag topanswers.xyz

Es hat eine sehr schlechte Leistung für größere Arrays
EZLearner

62

Wie in der Antwort von @ deinonychusaur, aber noch kompakter:

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

18
Nett. Sie können auch tun, a[(a >= 6) & (a <= 10)]wenn aes sich um ein Numpy-Array handelt.
ws_e_c421

1
Nur für den Fall, dass jemand wie ich mit dem Wortlaut des Kommentars verwechselt wird: Dies funktioniert nicht für gewöhnliche Listen, es ist nur, wenn aes sich um ein numpy Array handelt
Prof

14

Ich dachte, ich würde dies hinzufügen, weil das ain dem von Ihnen angegebenen Beispiel sortiert ist:

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])


5

Zusammenfassung der Antworten

Um zu verstehen, was die beste Antwort ist, können wir mit der anderen Lösung ein Timing durchführen. Leider war die Frage nicht gut gestellt, so dass es Antworten auf verschiedene Fragen gibt. Hier versuche ich, die Antwort auf dieselbe Frage zu verweisen. Angesichts des Arrays:

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

Die Antwort sollten die Indizes der Elemente zwischen einem bestimmten Bereich sein, wir nehmen an, einschließlich, in diesem Fall 6 und 10.

answer = (3, 4, 5)

Entspricht den Werten 6,9,10.

Um die beste Antwort zu testen, können wir diesen Code verwenden.

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

Ergebnisse

Die Ergebnisse sind in der folgenden Darstellung angegeben. Oben die schnellsten Lösungen. Geben Sie hier die Bildbeschreibung ein Wenn Sie anstelle der Indizes die Werte extrahieren möchten, können Sie die Tests mit functions2 durchführen, aber die Ergebnisse sind fast gleich.


Diese Ergebnisse gelten nur für ein Array mit einer bestimmten Länge (hier haben Sie ein sehr kleines Array ausgewählt). Diese Ergebnisse werden für größere Arrays schnell geändert
EZLearner

4

Dieses Code-Snippet gibt alle Zahlen in einem Numpy-Array zwischen zwei Werten zurück:

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

Es funktioniert wie folgt: (a> 6) gibt ein numpy-Array mit True (1) und False (0) zurück, ebenso (a <10). Durch Multiplizieren dieser beiden Werte erhalten Sie ein Array mit entweder True, wenn beide Anweisungen True (weil 1x1 = 1) oder False (weil 0x0 = 0 und 1x0 = 0) sind.

Der Teil a [...] gibt alle Werte von Array a zurück, wobei das Array in Klammern eine True-Anweisung zurückgibt.

Natürlich können Sie dies komplizierter machen, indem Sie zum Beispiel sagen

...*(1-a<10) 

Dies ähnelt einer "und nicht" -Anweisung.


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

1

Wollte der Mischung numexpr hinzufügen :

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)

Wäre nur für größere Arrays mit Millionen sinnvoll ... oder wenn Sie an Speichergrenzen stoßen.


1

Ein anderer Weg ist mit:

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

was zurückgibt:

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

Es ist manchmal nützlich, um Zeitreihen, Vektoren usw. zu maskieren.


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)

Ausgabe:

(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

Dies ist vielleicht nicht die schönste, funktioniert aber für jede Dimension

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)

-3

Sie können verwenden np.clip(), um das gleiche zu erreichen:

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

Es enthält jedoch Werte kleiner und größer als 6 bzw. 10.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.