2013-04-25 3 views
9

Ich habe zwei 2D-Arrays mit der gleichen GrößeTest für die Mitgliedschaft in einem 2d numpy Array

a = array([[1,2],[3,4],[5,6]]) 
b = array([[1,2],[3,4],[7,8]]) 

ich die Zeilen b wissen will, die in einem sind.

So sollte die Ausgabe sein:

array([ True, True, False], dtype=bool) 

, ohne:

array([any(i == a) for i in b]) 

Ursache a und b sind riesig.

Es ist eine Funktion, die für 1D-Arrays dies aber nur, dass: in1d

+2

Was ist der tatsächliche dtype von 'a' und' b'? – unutbu

+0

@unutbu float (könnte sich auf int setzen) – amine23

Antwort

8

Was wir wirklich tun möchten, ist np.in1d ... mit der Ausnahme, dass np.in1d nur mit 1-dimensionalen Arrays funktioniert. Unsere Arrays sind mehrdimensional. Jedoch können wir Ansicht die Arrays als 1-dimensionales Array von Zeichenketten :

a = a.ravel().view((np.str, a.itemsize*a.shape[1])) 

Zum Beispiel

In [15]: a = np.array([[1, 2], [2, 3], [1, 3]]) 

In [16]: a = a.ravel().view((np.str, a.itemsize*a.shape[1])) 

In [17]: a.dtype 
Out[17]: dtype('|S8') 

In [18]: a.shape 
Out[18]: (3,) 

In [19]: a 
Out[19]: 
array(['\x01\x00\x00\x00\x02', '\x02\x00\x00\x00\x03', 
     '\x01\x00\x00\x00\x03'], 
     dtype='|S8') 

Dies macht jede Reihe von a eine Zeichenfolge. Nun ist es nur noch eine Frage dies Einhaken zu np.in1d:

def inNd(a, b, assume_unique=False): 
    a = np.asarray(a, order='C') 
    b = np.asarray(b, order='C') 
    a = a.ravel().view((np.str, a.itemsize * a.shape[1])) 
    b = b.ravel().view((np.str, b.itemsize * b.shape[1])) 
    return np.in1d(a, b, assume_unique) 

import numpy as np 


def inNd(a, b, assume_unique=False): 
    a = np.asarray(a, order='C') 
    b = np.asarray(b, order='C') 
    a = a.ravel().view((np.str, a.itemsize * a.shape[1])) 
    b = b.ravel().view((np.str, b.itemsize * b.shape[1])) 
    return np.in1d(a, b, assume_unique) 

tests = [ 
    (np.array([[1, 2], [2, 3], [1, 3]]), 
    np.array([[2, 2], [3, 3], [4, 4]]), 
    np.array([False, False, False])), 
    (np.array([[1, 2], [2, 2], [1, 3]]), 
    np.array([[2, 2], [3, 3], [4, 4]]), 
    np.array([True, False, False])), 
    (np.array([[1, 2], [3, 4], [5, 6]]), 
    np.array([[1, 2], [3, 4], [7, 8]]), 
    np.array([True, True, False])), 
    (np.array([[1, 2], [5, 6], [3, 4]]), 
    np.array([[1, 2], [5, 6], [7, 8]]), 
    np.array([True, True, False])), 
    (np.array([[-0.5, 2.5, -2, 100, 2], [5, 6, 7, 8, 9], [3, 4, 5, 6, 7]]), 
    np.array([[1.0, 2, 3, 4, 5], [5, 6, 7, 8, 9], [-0.5, 2.5, -2, 100, 2]]), 
    np.array([False, True, True])) 
] 

for a, b, answer in tests: 
    result = inNd(b, a) 
    try: 
     assert np.all(answer == result) 
    except AssertionError: 
     print('''\ 
a: 
{a} 
b: 
{b} 

answer: {answer} 
result: {result}'''.format(**locals())) 
     raise 
else: 
    print('Success!') 

Ausbeuten

Success! 
+2

Betrachten Sie es als Record-Array, denke ich '.view (dtype ([('', a.dtype) * a.shape [1]])) 'ist was du brauchst, und du hast den gleichen Trick für jeden Typ. – Jaime

+0

@Jaime: Ich habe 'a1d = a.view ([('f0', 'int32'), ('f1', 'int32')])', 'b1d = ...', 'np.in1d ​​(a1d, b1d) 'aber bekam einen TypeError. Wenn Sie einen Weg sehen, würde ich es gerne wissen. – unutbu

+0

Das ist auch seltsamerweise der Testfall, den ich als Kommentar zu @ Jans Antwort gepostet habe. – amine23

4
In [1]: import numpy as np 

In [2]: a = np.array([[1,2],[3,4]]) 

In [3]: b = np.array([[3,4],[1,2]]) 

In [5]: a = a[a[:,1].argsort(kind='mergesort')] 

In [6]: a = a[a[:,0].argsort(kind='mergesort')] 

In [7]: b = b[b[:,1].argsort(kind='mergesort')] 

In [8]: b = b[b[:,0].argsort(kind='mergesort')] 

In [9]: bInA1 = b[:,0] == a[:,0] 

In [10]: bInA2 = b[:,1] == a[:,1] 

In [11]: bInA = bInA1*bInA2 

In [12]: bInA 
Out[12]: array([ True, True], dtype=bool) 

sollte dies tun ... Nicht sicher, ob dies noch effizient ist. Sie müssen mergesort tun, da andere Methoden instabil sind.

Edit:

Wenn Sie mehr als 2 Spalten haben, und wenn die Zeilen bereits sortiert sind, können Sie tun,

In [24]: bInA = np.array([True,]*a.shape[0]) 

In [25]: bInA 
Out[25]: array([ True, True], dtype=bool) 

In [26]: for k in range(a.shape[1]): 
    bInAk = b[:,k] == a[:,k] 
    bInA = bInAk*bInA 
    ....:  

In [27]: bInA 
Out[27]: array([ True, True], dtype=bool) 

Es für die Beschleunigung noch Platz ist, wie in der Iteration, Sie don Ich muss nicht die gesamte Spalte prüfen, sondern nur die Einträge, bei denen der aktuelle bInATrue ist.

+0

Was ist, wenn 'a = Array ([[1,2], [2,3], [1,3]])' und 'b = Array ([[2,3 ], [3,3], [4,4]])? – amine23

+0

ja .. Ich habe das gerade überprüft - dann schlägt es fehl ... Ich versuche das zu beheben – Jan

+0

Bearbeiten/Fix: Die Verwendung von 'in1d' kann fehlschlagen, weil es nicht nach dem Ort des Vorkommens sucht ... Habe es in den '==' – Jan

0

das numpy Modul kann über das Array tatsächlich ausgestrahlt und sagen, welche Teile sind die gleiche wie die andere und zurück wahr wenn sie sind und falsch wenn sie nicht sind:

import numpy as np 
a = np.array(([1,2],[3,4],[5,6])) #converting to a numpy array 
b = np.array(([1,2],[3,4],[7,8])) #converting to a numpy array 
new_array = a == b #creating a new boolean array from comparing a and b 

jetzt sieht new_array wie folgt aus:

[[ True True] 
[ True True] 
[False False]] 

aber das ist nicht das, was Sie wollen. So können Sie das Array transponieren (mit x und y umdrehen) und dann die beiden Zeilen mit einem & Gatter vergleichen.Dies wird nun ein 1-D-Array erstellen, die nur wahr zurück, wenn beide Spalten in der Zeile zutreffen:

new_array = new_array.T #transposing 
result = new_array[0] & new_array[1] #comparing rows 

, wenn Sie Sie jetzt print result bekommen, was Sie suchen:

[ True True False] 
+0

Was ist, wenn' a = Array ([[1,2], [3,4]]) 'und' b = Array ([[3,4], [1,2]]) '? – amine23

+0

es war nicht wirklich klar, dass man alles vergleichen wollte. Ihr Beispiel hat das nicht deutlich angezeigt ... und Sie möchten prüfen können, ob ein verschachteltes Array in b in einem ist, ohne eine for-Schleife zu verwenden? –

0

wenn Sie smth wie a=np.array([[1,2],[3,4],[5,6]]) und b=np.array([[5,6],[1,2],[7,6]]) haben, können Sie sie in komplexe 1-D-Array konvertieren:

c=a[:,0]+a[:,1]*1j 
d=b[:,0]+b[:,1]*1j 

Dieses ganze Zeug in meinem Interpreter wie folgt aussieht :

>>> c=a[:,0]+a[:,1]*1j 
>>> c 
array([ 1.+2.j, 3.+4.j, 5.+6.j]) 
>>> d=b[:,0]+b[:,1]*1j 
>>> d 
array([ 5.+6.j, 1.+2.j, 7.+6.j]) 

Und jetzt, dass Sie nur 1D-Array haben, können Sie leicht np.in1d(c,d) tun, und der Python gibt Ihnen:

>>> np.in1d(c,d) 
array([ True, False, True], dtype=bool) 

Und damit Sie brauchen keine Loops, zumindest mit diesem Datentyp