Ich habe versucht, Einträge in einem Array zu finden, das eine Teilzeichenfolge mit np.where und einer in-Bedingung enthält:
import numpy as np
foo = "aa"
bar = np.array(["aaa", "aab", "aca"])
np.where(foo in bar)
dies gibt nur ein leeres Array zurück.
Warum ist das so?
Und gibt es eine gute alternative Lösung?
Wir können np.core.defchararray.find
verwenden, um die Position von foo
string in jedem Element von bar
zu finden, das -1
zurückgibt, wenn es nicht gefunden wird. Somit könnte es verwendet werden, um zu erkennen, ob in jedem Element eine foo
vorhanden ist oder nicht, indem auf der Ausgabe von find
nach -1
gesucht wird. Schließlich würden wir np.flatnonzero
verwenden, um die Indexe der Übereinstimmungen zu erhalten. Also, wir hätten eine Implementierung wie folgt:
np.flatnonzero(np.core.defchararray.find(bar,foo)!=-1)
Probelauf -
In [91]: bar
Out[91]:
array(['aaa', 'aab', 'aca'],
dtype='|S3')
In [92]: foo
Out[92]: 'aa'
In [93]: np.flatnonzero(np.core.defchararray.find(bar,foo)!=-1)
Out[93]: array([0, 1])
In [94]: bar[2] = 'jaa'
In [95]: np.flatnonzero(np.core.defchararray.find(bar,foo)!=-1)
Out[95]: array([0, 1, 2])
Sie können auch Folgendes tun:
mask = [foo in x for x in bar]
filter = bar[ np.where( mask * bar != '') ]
Die Art und Weise, wie Sie versuchen, np.where
zu verwenden, ist falsch. Das erste Argument von np.where
sollte ein boolesches Array sein, und Sie übergeben es einfach als boolesches Array.
foo in bar
>>> False
np.where(False)
>>> (array([], dtype=int32),)
np.where(np.array([True, True, False]))
>>> (array([0, 1], dtype=int32),)
Das Problem ist, dass numpy den Operator in
nicht als elementweise boolesche Operation definiert.
Eine Möglichkeit, das zu erreichen, was Sie wollen, ist ein Listenverständnis.
foo = 'aa'
bar = np.array(['aaa', 'aab', 'aca'])
out = [i for i, v in enumerate(bar) if foo in v]
# out = [0, 1]
bar = ['aca', 'bba', 'baa', 'aaf', 'ccc']
out = [i for i, v in enumerate(bar) if foo in v]
# out = [2, 3]
Schauen Sie sich einige Beispiele für die Verwendung von in
an:
In [19]: bar = np.array(["aaa", "aab", "aca"])
In [20]: 'aa' in bar
Out[20]: False
In [21]: 'aaa' in bar
Out[21]: True
In [22]: 'aab' in bar
Out[22]: True
In [23]: 'aab' in list(bar)
Es sieht aus wie in
, wenn es mit einem Array verwendet wird, als ob das Array eine Liste wäre. ndarray
hat eine __contains__
Methode, also funktioniert in
, aber es ist wahrscheinlich einfach.
Beachten Sie jedoch in jedem Fall, dass in alist
nicht nach Teilzeichenfolgen sucht. Die strings
__contains__
führt den Teilzeichenfolgentest durch, aber ich kenne keine eingebaute Klasse, die den Test auf die Komponentenzeichenfolgen überträgt.
Wie Divakar
zeigt, gibt es eine Sammlung von Numpy-Funktionen, mit denen String-Methoden auf einzelne Elemente eines Arrays angewendet werden.
In [42]: np.char.find(bar, 'aa')
Out[42]: array([ 0, 0, -1])
Docstring:
Dieses Modul enthält eine Reihe von Funktionen für vektorisierte Zeichenfolgenoperationen und -methoden. Der bevorzugte Alias fürdefchararray
istnumpy.char
.
Für Operationen wie diese denke ich, sind die np.char
Geschwindigkeiten ungefähr gleich wie bei:
In [49]: np.frompyfunc(lambda x: x.find('aa'), 1, 1)(bar)
Out[49]: array([0, 0, -1], dtype=object)
In [50]: np.frompyfunc(lambda x: 'aa' in x, 1, 1)(bar)
Out[50]: array([True, True, False], dtype=object)
Weitere Tests legen nahe, dass der ndarray
__contains__
auf die flat
-Version des Arrays angewendet werden kann - das heißt, dass die Form das Verhalten nicht beeinflusst.