2009-08-13 3 views
3

hier ist mein Problem. Ich möchte eine Boolesche Matrix B erstellen, die True enthält überall die Matrix A einen Wert in Vektor v enthalten ist, besitzt eine unbequeme Lösung wäre:Wie kann ich den `ismember()` `Befehl von Matlabs in Python implementieren?

import numpy as np 
>>> A = np.array([[0,1,2], [1,2,3], [2,3,4]]) 
array([[0, 1, 2], 
     [1, 2, 3], 
     [2, 3, 4]]) 
>>> v = [1,2] 
>>> B = (A==v[0]) + (A==v[1]) # matlab: ``B = ismember(A,v)`` 
array([[False, True, True], 
     [ True, True, False], 
     [ True, False, False]], dtype=bool) 

Gibt es vielleicht eine Lösung, die wäre es bequemer, wenn A und v mehr Werte hätten?

Prost!

Antwort

1

Hier ist ein naiver Einzeiler:

[any (value in item for value in v) for item in A] 

Beispielausgabe:

>>> A = ([0,1,2], [1,2,3], [2,3,4]) 
>>> v = [1,2] 
>>> [any (value in item for value in v) for item in A] 
[True, True, True] 
>>> v = [1] 
>>> [any (value in item for value in v) for item in A] 
[True, True, False] 

Es ist ein sehr Pythonic Ansatz, aber ich bin sicher, dass es nicht gut auf große Arrays skaliert oder Vektoren weil der Operator in von Python eine lineare Suche ist (zumindest für Listen/Tupel).

Wie Brooks Moses im folgenden Kommentar darauf hingewiesen, sollte die Ausgabe eine 3x3-Matrix sein. Deshalb geben Sie in Ihren Fragen eine Beispielausgabe. (Danke Brooks)

>>> v=[1,2] 
>>> [ [item in v for item in row] for row in A] 
[[False, True, True], [True, True, False], [True, False, False]] 
>>> v=[1] 
>>> [ [item in v for item in row] for row in A] 
[[False, True, False], [True, False, False], [False, False, False]] 
+1

Sie haben eine gute Antwort auf die falsche Frage, ich denke - Sie wollen, dass A ein 3x3-Array ist und einen 3x3 Wahrheitswert für jedes dieser 9 Elemente zurückgibt.Also, passen Sie Ihre Antwort leicht an: [[(Element in v) für Element in Zeile] für Zeile in A) funktioniert gut. Ich bin auch neugierig, warum Sie erwarten, dass dies langsam wäre. –

4

Ich weiß nicht viel numpy, sei hier eine rohe Python ein:

>>> A = [[0,1,2], [1,2,3], [2,3,4]] 
>>> v = [1,2] 
>>> B = [map(lambda val: val in v, a) for a in A] 
>>> 
>>> B 
[[False, True, True], [True, True, False], [True, False, False]] 

bearbeiten: Als Brooks Moses Notizen und einige einfache Timing scheint, dies zu zeigen man sein wahrscheinlich besser:

>>> B = [ [val in v for val in a] for a in A] 
+0

+1: Dies funktioniert mit Numy Arrays. –

+3

Naive Frage: Warum die Map (Lambda ...) Syntax, anstatt nur [(val in v) für v in a]? Gibt es in diesem Fall einen sinnvollen Unterschied? –

+0

@Brooks Moses: Du hast Recht, ich denke, es ist nicht, und das Doppelverständnis scheint sogar ein wenig schneller zu sein (ich habe nur ein bisschen naives Timing gemacht). Bearbeitet. – balpha

3

Mit numpy Primitiven:

>>> import numpy as np 
>>> A = np.array([[0,1,2], [1,2,3], [2,3,4]]) 
>>> v = [1,2] 
>>> print np.vectorize(lambda x: x in v)(A) 
[[False True True] 
[ True True False] 
[ True False False]] 

Für nicht winzige Eingänge konvertieren Sie v zuerst in einen Satz für eine große Beschleunigung.

Zur Nutzung numpy.setmember1d:

Auniq, Ainv = np.unique1d(A, return_inverse=True) 
result = np.take(np.setmember1d(Auniq, np.unique1d(v)), Ainv).reshape(A.shape) 
+0

Das ist kaputt: Siehe die 2. Zeile, rechte Spalte - Was ist das denn? Es entspricht 3 in A, was NICHT in v ist. Leider unterstützt setmember1d keine Arrays mit Duplikaten. –

+0

Korrigiert, die Dokumentation zu setmember1d könnte hier klarer sein. –

1

Ich denke, die nächstgelegene Sie numpy.ismember1d ist zu bekommen, aber es wird mit Ihrem Beispiel nicht gut funktionieren. Ich denke, Ihre Lösung (B = (A==v[0]) + (A==v[1])) könnte tatsächlich die beste sein.

3

Ach, setmember1d wie es in numpy vorhanden ist, ist gebrochen, wenn beide Array Elemente dupliziert (wie A hier tut). Herunterladen this Version, nennen es zB sem.py irgendwo auf Ihrem sys.path, fügen Sie eine erste Zeile import numpy as nm, und dann wird diese schließlich funktioniert:

>>> import sem 
>>> print sem.setmember1d(A.reshape(A.size), v).reshape(A.shape) 
[[False True True] 
[True True False] 
[True False False]] 

Beachten Sie den Unterschied WRT @Aants' ähnliche Antwort: Diese Version hat die zweite Zeile des resultierenden Bool-Array korrekt, während seine Version (mit der setmember1d, die als Teil von numpy kommt) falsch die zweite Zeile als alle True s hat.

Verwandte Themen