it-swarm.com.de

MATLAB-ähnliche find () -Funktion in Python

In MATLAB ist es einfach, die Indizes von Werten zu finden, die eine bestimmte Bedingung erfüllen:

>> a = [1,2,3,1,2,3,1,2,3];
>> find(a > 2)     % find the indecies where this condition is true
[3, 6, 9]          % (MATLAB uses 1-based indexing)
>> a(find(a > 2))  % get the values at those locations
[3, 3, 3]

Was wäre der beste Weg, um dies in Python zu tun?

Bisher habe ich mir Folgendes ausgedacht. Um nur die Werte zu erhalten:

>>> a = [1,2,3,1,2,3,1,2,3]
>>> [val for val in a if val > 2]
[3, 3, 3]

Aber wenn ich den Index jedes dieser Werte sehen möchte, ist das etwas komplizierter:

>>> a = [1,2,3,1,2,3,1,2,3]
>>> inds = [i for (i, val) in enumerate(a) if val > 2]
>>> inds
[2, 5, 8]
>>> [val for (i, val) in enumerate(a) if i in inds]
[3, 3, 3]

Gibt es eine bessere Möglichkeit, dies in Python zu tun, insbesondere für beliebige Bedingungen (nicht nur 'val> 2')?

Ich habe in NumPy Funktionen gefunden, die MATLAB 'find' entsprechen, habe aber derzeit keinen Zugriff auf diese Bibliotheken.

55
user344226

Sie können eine Funktion erstellen, die einen aufrufbaren Parameter übernimmt, der im Bedingungsteil Ihres Listenverständnisses verwendet wird. Dann können Sie ein Lambda oder ein anderes Funktionsobjekt verwenden, um Ihre beliebige Bedingung zu übergeben:

def indices(a, func):
    return [i for (i, val) in enumerate(a) if func(val)]

a = [1, 2, 3, 1, 2, 3, 1, 2, 3]

inds = indices(a, lambda x: x > 2)

>>> inds
[2, 5, 8]

Es ist ein bisschen näher an Ihrem Matlab-Beispiel, ohne dass Sie die ganze Zahl aufladen müssen.

26
John

in Zahlen haben Sie where:

>> import numpy as np
>> x = np.random.randint(0, 20, 10)
>> x
array([14, 13,  1, 15,  8,  0, 17, 11, 19, 13])
>> np.where(x > 10)
(array([0, 1, 3, 6, 7, 8, 9], dtype=int64),)
83
joaquin

Oder verwenden Sie die von Null verschiedene Funktion von numpy:

import numpy as np
a    = np.array([1,2,3,4,5])
inds = np.nonzero(a>2)
a[inds] 
array([3, 4, 5])
8
vincentv

Warum nicht einfach das benutzen:

[i for i in range(len(a)) if a[i] > 2]

oder definieren Sie für beliebige Bedingungen eine Funktion f für Ihre Bedingung und führen Sie Folgendes aus:

[i for i in range(len(a)) if f(a[i])]
5
JasonFruit

Die für diese Anwendung am häufigsten verwendete numpy -Routine ist numpy.where() ; Ich glaube jedoch, dass es genauso funktioniert wie numpy.nonzero() .

import numpy
a    = numpy.array([1,2,3,4,5])
inds = numpy.where(a>2)

Um die Werte zu erhalten, können Sie entweder die Indizes speichern und mit ihnen schneiden:

a[inds]

oder Sie können das Array als optionalen Parameter übergeben:

numpy.where(a>2, a)

oder mehrere Arrays:

b = numpy.array([11,22,33,44,55])
numpy.where(a>2, a, b)
4
ryanjdillon

Ich habe versucht, einen schnellen Weg zu finden, um genau dies zu erreichen. Dabei bin ich auf Folgendes gestoßen (verwendet numpy für den schnellen Vektorvergleich):

a_bool = numpy.array(a) > 2
inds = [i for (i, val) in enumerate(a_bool) if val]

Es stellt sich heraus, dass dies viel schneller ist als:

inds = [i for (i, val) in enumerate(a) if val > 2]

Es scheint, dass Python schneller im Vergleich ist, wenn es in einem Numpy-Array ausgeführt wird, und/oder dass es schneller Listenverständnisse ausführt, wenn nur die Wahrheit überprüft wird und nicht der Vergleich.

Bearbeiten:

Ich habe meinen Code überarbeitet und bin auf eine möglicherweise weniger speicherintensive, etwas schnellere und übersichtlichere Methode gestoßen, um dies in einer Zeile zu tun:

inds = np.arange( len(a) )[ a < 2 ]
3
Nate

Um Werte mit beliebigen Bedingungen zu erhalten, können Sie filter() mit einer Lambda-Funktion verwenden:

>>> a = [1,2,3,1,2,3,1,2,3]
>>> filter(lambda x: x > 2, a)
[3, 3, 3]

Eine Möglichkeit zum Abrufen der Indizes besteht darin, mit enumerate() ein Tupel mit Indizes und Werten zu erstellen und Folgendes zu filtern:

>>> a = [1,2,3,1,2,3,1,2,3]
>>> aind = Tuple(enumerate(a))
>>> print aind
((0, 1), (1, 2), (2, 3), (3, 1), (4, 2), (5, 3), (6, 1), (7, 2), (8, 3))
>>> filter(lambda x: x[1] > 2, aind)
((2, 3), (5, 3), (8, 3))
3
Blair

Ich glaube, ich habe einen schnellen und einfachen Ersatz gefunden. Übrigens war ich der Meinung, dass die Funktion np.where () nicht sehr zufriedenstellend ist, in dem Sinne, dass sie irgendwie eine nervige Reihe von Nullelementen enthält.

import matplotlib.mlab as mlab
a = np.random.randn(1,5)
print a

>> [[ 1.36406736  1.45217257 -0.06896245  0.98429727 -0.59281957]]

idx = mlab.find(a<0)
print idx
type(idx)

>> [2 4]
>> np.ndarray

Beste, Da

2
DidasW

Matlabs Suchcode hat zwei Argumente. Johns Code erklärt das erste Argument, aber nicht das zweite. Wenn Sie beispielsweise wissen möchten, wo im Index die Bedingung erfüllt ist, lautet die Funktion von Mtlab:

find(x>2,1)

Mit Johns Code müssen Sie lediglich ein [x] am Ende der Indexfunktion hinzufügen, wobei x die gesuchte Indexnummer ist.

def indices(a, func):
    return [i for (i, val) in enumerate(a) if func(val)]

a = [1, 2, 3, 1, 2, 3, 1, 2, 3]

inds = indices(a, lambda x: x > 2)[0] #[0] being the 2nd matlab argument

dies gibt >>> 2 zurück, den ersten Index, der 2 überschreitet.

0
Clayton Pipkin