2016-10-15 2 views
15

Say Ich habe diese 2D-Arrays A und B.Entfernen von Elementen aus einem Array, das in einem anderen Array sind

Wie ich Elemente aus einem entfernen kann, die in B. sind (Complement in Mengenlehre: AB)

A=np.asarray([[1,1,1], [1,1,2], [1,1,3], [1,1,4]]) 
B=np.asarray([[0,0,0], [1,0,2], [1,0,3], [1,0,4], [1,1,0], [1,1,1], [1,1,4]]) 
#output = [[1,1,2], [1,1,3]] 

Um genau zu sein, würde ich gerne so etwas tun.

data = some numpy array 
label = some numpy array 
A = np.argwhere(label==0) #[[1 1 1], [1 1 2], [1 1 3], [1 1 4]] 
B = np.argwhere(data>1.5) #[[0 0 0], [1 0 2], [1 0 3], [1 0 4], [1 1 0], [1 1 1], [1 1 4]] 
out = np.argwhere(label==0 and data>1.5) #[[1 1 2], [1 1 3]] 
+0

nicht tat == wird Arbeit, ich rate nur, ich weiß nicht viel über numpy Arrays, von meiner Python-Konsole habe ich diese '>>> [1,1,1] == [1,1,1] >>> True ' –

+0

Eine einfache nicht-numpy Lösung -' [i für i in A für j in B wenn i == j] ' – JRodDynamite

Antwort

11

Basierend auf this solution-Find the row indexes of several values in a numpy array, hier ist eine NumPy basierte Lösung mit weniger Speicherbedarf und könnte von Vorteil sein, wenn sie mit großen Arrays arbeiten -

dims = np.maximum(B.max(0),A.max(0))+1 
out = A[~np.in1d(np.ravel_multi_index(A.T,dims),np.ravel_multi_index(B.T,dims))] 

Probelauf -

In [38]: A 
Out[38]: 
array([[1, 1, 1], 
     [1, 1, 2], 
     [1, 1, 3], 
     [1, 1, 4]]) 

In [39]: B 
Out[39]: 
array([[0, 0, 0], 
     [1, 0, 2], 
     [1, 0, 3], 
     [1, 0, 4], 
     [1, 1, 0], 
     [1, 1, 1], 
     [1, 1, 4]]) 

In [40]: out 
Out[40]: 
array([[1, 1, 2], 
     [1, 1, 3]]) 

Laufzeittest auf großen Arrays -

In [107]: def in1d_approach(A,B): 
    ...:  dims = np.maximum(B.max(0),A.max(0))+1 
    ...:  return A[~np.in1d(np.ravel_multi_index(A.T,dims),\ 
    ...:      np.ravel_multi_index(B.T,dims))] 
    ...: 

In [108]: # Setup arrays with B as large array and A contains some of B's rows 
    ...: B = np.random.randint(0,9,(1000,3)) 
    ...: A = np.random.randint(0,9,(100,3)) 
    ...: A_idx = np.random.choice(np.arange(A.shape[0]),size=10,replace=0) 
    ...: B_idx = np.random.choice(np.arange(B.shape[0]),size=10,replace=0) 
    ...: A[A_idx] = B[B_idx] 
    ...: 

Timings mit broadcasting basierten Lösungen -

In [109]: %timeit A[np.all(np.any((A-B[:, None]), axis=2), axis=0)] 
100 loops, best of 3: 4.64 ms per loop # @Kasramvd's soln 

In [110]: %timeit A[~((A[:,None,:] == B).all(-1)).any(1)] 
100 loops, best of 3: 3.66 ms per loop 

TIMING mit weniger Speicherbedarf basierte Lösung -

In [111]: %timeit in1d_approach(A,B) 
1000 loops, best of 3: 231 µs per loop 

weitere Leistungssteigerung

in1d_approach jede Zeile reduziert, indem jede Zeile als Berücksichtigung Indexierungstupel. Wir können effizienter das gleiche einiges durch die Einführung von Matrix-Multiplikation mit np.dot, wie so -

def in1d_dot_approach(A,B): 
    cumdims = (np.maximum(A.max(),B.max())+1)**np.arange(B.shape[1]) 
    return A[~np.in1d(A.dot(cumdims),B.dot(cumdims))] 

ist es gegenüber dem Vorjahr auf viel größere Arrays Lassen Sie testen -

In [251]: # Setup arrays with B as large array and A contains some of B's rows 
    ...: B = np.random.randint(0,9,(10000,3)) 
    ...: A = np.random.randint(0,9,(1000,3)) 
    ...: A_idx = np.random.choice(np.arange(A.shape[0]),size=10,replace=0) 
    ...: B_idx = np.random.choice(np.arange(B.shape[0]),size=10,replace=0) 
    ...: A[A_idx] = B[B_idx] 
    ...: 

In [252]: %timeit in1d_approach(A,B) 
1000 loops, best of 3: 1.28 ms per loop 

In [253]: %timeit in1d_dot_approach(A, B) 
1000 loops, best of 3: 1.2 ms per loop 
+0

Ihr in1d_Approach dauert 30 Sekunden, in1d_dot_approach dauert 45 Sekunden in meinem Programm. Mein Nummernfeld verwendet dtype = np.uint8. Also teste ich es mit Ihrem genauen Code mit dtype = np.uint8 Parameter für A, B. Dot-Funktion gibt mir 567 Nano-Sekunden, Original dauert 539 Nano-Sekunden. Irgendeine Erklärung, warum ein kleinerer Datentyp der ursprünglichen Funktion ein besseres Timing verleiht? –

+1

@JeeSeokYoon Na einfach, weil weniger Präzisionsdatentypen weniger Speicher in Bezug auf ihre binären Bits belegen würden und somit weniger Speicherbelegung erfordern würden und dies in den meisten Fällen zu einer schnelleren Verarbeitung führt, da weniger Daten verarbeitet werden, da eine geringere Anzahl binärer Bits verwendet wird jede Zahl. Man muss bedenken, dass CPUs auf unterster Ebene binäre Daten verarbeiten. Hoffnung, die Sinn ergab! – Divakar

+0

Ich frage, warum ist in1d_approach (A, B) langsamer als in1d_dot_approach (A, B) im Umgang mit Fließkomma, aber schneller für Integer? Ist es nur wie dumm gebaut wurde? Warum funktioniert Matrixmultiplikation besser mit Fließkomma/schlechter mit Ganzzahlen (im Vergleich zu anderen Methoden)? –

3

Wenn Sie die numpy Weise tun wollen,

import numpy as np 

A = np.array([[1, 1, 1,], [1, 1, 2], [1, 1, 3], [1, 1, 4]]) 
B = np.array([[0, 0, 0], [1, 0, 2], [1, 0, 3], [1, 0, 4], [1, 1, 0], [1, 1, 1], [1, 1, 4]]) 
A_rows = A.view([('', A.dtype)] * A.shape[1]) 
B_rows = B.view([('', B.dtype)] * B.shape[1]) 

diff_array = np.setdiff1d(A_rows, B_rows).view(A.dtype).reshape(-1, A.shape[1]) 

Als @Rahul, für eine nicht numpy einfache Lösung vorgeschlagen,

diff_array = [i for i in A if i not in B] 
+0

Ich denke, Sie bekommen falsches Ergebnis. –

+1

Danke für die Köpfe hoch. Aktualisiert. –

6

gibt es eine einfache Lösung mit list comprehension ,

A = [i for i in A if i not in B] 

Ergebnis

[[1, 1, 2], [1, 1, 3]] 

Liste Verständnis, es ist nicht die Elemente aus dem Array entfernt, es ist nur die Neuzuweisung,

, wenn Sie die Elemente verwenden diese Methode

for i in B: 
    if i in A: 
    A.remove(i) 
3

Eine weitere nicht-numpy Lösung entfernen mögen :

[i for i in A if i not in B] 
9

Hier ist ein Numpythonic Ansatz mit Rundfunk:

In [83]: A[np.all(np.any((A-B[:, None]), axis=2), axis=0)] 
Out[83]: 
array([[1, 1, 2], 
     [1, 1, 3]]) 

ist hier ein timeit mit anderer Antwort:

In [90]: def cal_diff(A, B): 
    ....:  A_rows = A.view([('', A.dtype)] * A.shape[1]) 
    ....:  B_rows = B.view([('', B.dtype)] * B.shape[1]) 
    ....:  return np.setdiff1d(A_rows, B_rows).view(A.dtype).reshape(-1, A.shape[1]) 
    ....: 

In [93]: %timeit cal_diff(A, B) 
10000 loops, best of 3: 54.1 µs per loop 

In [94]: %timeit A[np.all(np.any((A-B[:, None]), axis=2), axis=0)] 
100000 loops, best of 3: 9.41 µs per loop 

# Even better with Divakar's suggestion 
In [97]: %timeit A[~((A[:,None,:] == B).all(-1)).any(1)] 
100000 loops, best of 3: 7.41 µs per loop 

Nun, wenn Sie einen schnelleren Weg, suchen Sie nach Möglichkeiten suchen sollten, die die Anzahl der Vergleiche reduzieren. In diesem Fall (ohne Berücksichtigung der Reihenfolge) können Sie eine eindeutige Nummer aus Ihren Zeilen generieren und die Zahlen vergleichen, die mit der Summe der Potenz von Zwei durchgeführt werden können.Hier

ist der Maßstab mit Divakar der in1d Ansatz:

In [144]: def in1d_approach(A,B): 
    .....:   dims = np.maximum(B.max(0),A.max(0))+1 
    .....:   return A[~np.in1d(np.ravel_multi_index(A.T,dims),\ 
    .....:       np.ravel_multi_index(B.T,dims))] 
    .....: 

In [146]: %timeit in1d_approach(A, B) 
10000 loops, best of 3: 23.8 µs per loop 

In [145]: %timeit A[~np.in1d(np.power(A, 2).sum(1), np.power(B, 2).sum(1))] 
10000 loops, best of 3: 20.2 µs per loop 

Sie können np.diff verwenden, um die ein Auftrag unabhängige Ergebnisse zu erhalten:

In [194]: B=np.array([[0, 0, 0,], [1, 0, 2,], [1, 0, 3,], [1, 0, 4,], [1, 1, 0,], [1, 1, 1,], [1, 1, 4,], [4, 1, 1]]) 

In [195]: A[~np.in1d(np.diff(np.diff(np.power(A, 2))), np.diff(np.diff(np.power(B, 2))))] 
Out[195]: 
array([[1, 1, 2], 
     [1, 1, 3]]) 

In [196]: %timeit A[~np.in1d(np.diff(np.diff(np.power(A, 2))), np.diff(np.diff(np.power(B, 2))))] 
10000 loops, best of 3: 30.7 µs per loop 

Benchmark mit Divakar der Einrichtung:

In [198]: B = np.random.randint(0,9,(1000,3)) 

In [199]: A = np.random.randint(0,9,(100,3)) 

In [200]: A_idx = np.random.choice(np.arange(A.shape[0]),size=10,replace=0) 

In [201]: B_idx = np.random.choice(np.arange(B.shape[0]),size=10,replace=0) 

In [202]: A[A_idx] = B[B_idx] 

In [203]: %timeit A[~np.in1d(np.diff(np.diff(np.power(A, 2))), np.diff(np.diff(np.power(B, 2))))] 
10000 loops, best of 3: 137 µs per loop 

In [204]: %timeit A[~np.in1d(np.power(A, 2).sum(1), np.power(B, 2).sum(1))] 
10000 loops, best of 3: 112 µs per loop 

In [205]: %timeit in1d_approach(A, B) 
10000 loops, best of 3: 115 µs per loop 

Timing mit größeren Arrays (Divakars Lösung ist etwas schnell er):

In [231]: %timeit A[~np.in1d(np.diff(np.diff(np.power(A, 2))), np.diff(np.diff(np.power(B, 2))))] 
1000 loops, best of 3: 1.01 ms per loop 

In [232]: %timeit A[~np.in1d(np.power(A, 2).sum(1), np.power(B, 2).sum(1))] 
1000 loops, best of 3: 880 µs per loop 

In [233]: %timeit in1d_approach(A, B) 
1000 loops, best of 3: 807 µs per loop 
+1

Schön! War im Begriff, das gleiche zu posten! – Divakar

+1

Tatsächlich ist die Verwendung von 'equality' möglicherweise besser für die Leistung:' A [~ ((A [:, None ,:] == B) .all (-1)). Any (1)] '. – Divakar

+0

Tolle Lösung :) –

Verwandte Themen