2009-10-23 28 views
37

Qualcuno si è mai presentato a questo problema? Diciamo che avete due array come la seguenteNumPy: confronto di elementi in due array

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

C'è un modo per confrontare quali elementi in un esistere in B? Ad esempio,

c = a == b # Wishful example here 
print c 
array([1,4,5]) 
# Or even better 
array([True, False, False, True, True, False]) 

Sto provando ad evitare i loop in quanto richiederebbero anni con milioni di elementi. Qualche idea?

Acclamazioni

+0

quali dati hai negli array? Interi unici univoci come l'esempio? – u0b34a0f6ae

risposta

47

In realtà, c'è una soluzione ancora più semplice di uno di questi:

import numpy as np 

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

c = np.in1d(a,b) 

Il c risultante è quindi:

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

Esiste una versione "quasi_equale" di questo? Dove puoi specificare la condizione usata per testare l'uguaglianza? – endolith

-2

vostro esempio implica set-simile comportamento, preoccuparsi più esistenza nella matrice che avere l'elemento giusto al posto giusto. Numpy lo fa diversamente con i suoi array e matrici matematiche, ti dirà solo degli oggetti nel punto esatto. Puoi fare quel lavoro per te?

>>> import numpy 
>>> a = numpy.array([1,2,3]) 
>>> b = numpy.array([1,3,3]) 
>>> a == b 
array([ True, False, True], dtype=bool) 
+0

scusa, questo esempio non funziona se lo provi; inoltre, dovresti prima ordinare gli array. – dalloliogm

+0

@dalloligom: Uh, ho copiato dalla mia sessione interattiva così almeno funziona esattamente così per alcune versioni di Python e Numpy. – u0b34a0f6ae

+0

ok, ma non funziona se i due array hanno una lunghezza diversa; in ogni caso, devi prima ordinarli (prova array ([1,2,3]) == array ([2,3,1]). Vuole sapere quali elementi di un array esistono in un altro. – dalloliogm

2

Grazie per la tua risposta kaizer.se. Non è esattamente quello che stavo cercando, ma con un suggerimento da parte di un amico e quello che hai detto ho trovato il seguente.

import numpy as np 

a = np.array([1,4,5]).astype(np.float32) 
b = np.arange(10).astype(np.float32) 

# Assigning matching values from a in b as np.nan 
b[b.searchsorted(a)] = np.nan 

# Now generating Boolean arrays 
match = np.isnan(b) 
nonmatch = match == False 

È un processo un po 'macchinoso, ma batte cicli di scrittura o utilizza trama con loop.

Acclamazioni

+0

Problema con questo approccio è che restituisce indici anche per valori in 'a' che non esistono in' b' (così come indici duplicati in altri casi). Ad esempio: 'numpy.searchsorted ([1, 2], [1.2, 1.3 ]) 'restituisce' [1, 1] 'che non è adatto per l'OP – sirfz

2

Numpy ha una funzione set numpy.setmember1d() che funziona su array ordinati e uniqued e restituisce esattamente l'array booleano che si desidera. Se gli array di input non corrispondono ai criteri, è necessario convertirli nel formato impostato e invertire la trasformazione sul risultato.

import numpy as np 
a = np.array([6,1,2,3,4,5,6]) 
b = np.array([1,4,5]) 

# convert to the uniqued form 
a_set, a_inv = np.unique1d(a, return_inverse=True) 
b_set = np.unique1d(b) 
# calculate matching elements 
matches = np.setmea_set, b_set) 
# invert the transformation 
result = matches[a_inv] 
print(result) 
# [False True False False True True False] 

Edit: Purtroppo il metodo setmember1d in NumPy è davvero inefficiente. La ricerca ordinata e assegnata al metodo che hai proposto funziona più velocemente, ma se puoi assegnare direttamente potresti anche assegnare direttamente al risultato ed evitare molte copie inutili. Anche il tuo metodo fallirà se b contiene qualcosa non in a. Di seguito corregge questi errori:

result = np.zeros(a.shape, dtype=np.bool) 
idxs = a.searchsorted(b) 
idxs = idxs[np.where(idxs < a.shape[0])] # Filter out out of range values 
idxs = idxs[np.where(a[idxs] == b)] # Filter out where there isn't an actual match 
result[idxs] = True 
print(result) 

mie benchmark mostrano questo a 91us 6.6ms contro per il vostro approccio e 109ms per setmember1d NumPy su 1M elemento a e 100 elemento b.

+0

Questa è una buona soluzione. Proverò il tuo suggerimento e ciò che ho appena scritto per vedere cosa c'è di più ottimale in termini di velocità. help! – ebressert

+0

Il metodo che ho scritto è un po 'più veloce. Per un array di 10000 elementi il ​​tempo impiegato in timeit in iPython è di circa 3 μs. ethod ha impiegato 3 ms. Penso che il tuo metodo sia più elegante, ma ho bisogno della velocità. – ebressert

+0

ti sei dimenticato di chiudere una parentesi nella 3 ° riga. dovresti sistemarlo prima che un professore di informatica lo noti ... – dalloliogm

18

Utilizzare np.intersect1d.

#!/usr/bin/env python 
import numpy as np 
a = np.array([1,2,3,4,5,6]) 
b = np.array([1,4,5]) 
c=np.intersect1d(a,b) 
print(c) 
# [1 4 5] 

Nota che np.intersect1d restituisce la risposta sbagliata se a o b hanno elementi non univoci. In tal caso, utilizzare np.intersect1d_nu.

C'è anche np.setdiff1d, setxor1d, setmember1d e union1d. Vedi Numpy Example List With Doc

+0

+1: eccellente. La funzione giusta per questo compito. – tom10

0

ebresset, your answer non funziona a meno che a sia un sottoinsieme di b (e a e b sono ordinati). Altrimenti, la ricerca fornita restituirà indici falsi.Dovevo fare qualcosa di simile, e la combinazione che con il codice:

# Assume a and b are sorted 
idxs = numpy.mod(b.searchsorted(a),len(b)) 
idxs = idxs[b[idxs]==a] 
b[idxs] = numpy.nan 
match = numpy.isnan(b) 
Problemi correlati