2013-10-23 13 views
11

Ho una matrice di numeri interi e voglio trovare dove tale array è uguale a qualsiasi valore in un elenco di valori multipli. Questo può essere fatto facilmente trattando ogni valore individualmente, o usando più istruzioni "o" in un ciclo, ma sento che ci deve essere un modo migliore/più veloce per farlo. In realtà sto a che fare con array di dimensioni 4000x2000, ma qui è un'edizione semplificata del problema:trovare dove un array numpy è uguale a qualsiasi valore di un elenco di valori

fake=arange(9).reshape((3,3)) 
array([[0, 1, 2], 
     [3, 4, 5], 
     [6, 7, 8]]) 
want=(fake==0)+(fake==2)+(fake==6)+(fake==8) 
print want 
array([[ True, False, True], 
     [False, False, False], 
     [ True, False, True]], dtype=bool) 

Quello che vorrei è un modo per ottenere want da un unico comando che coinvolge fake e l'elenco dei valori [0,2,6,8] . Potrei scrivere il comando da solo, ma suppongo che ci sia già un pacchetto che ha già incluso quello che sarebbe stato significativamente più veloce di se avessi appena scritto una funzione con un loop in python.

Grazie, -Adam

risposta

14

La funzione numpy.in1d sembra fare quello che vuoi. Gli unici problemi è che funziona solo su array 1D, così si dovrebbe usare in questo modo:

In [9]: np.in1d(fake, [0,2,6,8]).reshape(fake.shape) 
Out[9]: 
array([[ True, False, True], 
     [False, False, False], 
     [ True, False, True]], dtype=bool) 

non ho idea perché questo è limitata ai soli array 1D. Guardando il suo source code, sembra dapprima appiattire i due array, dopo di che fa alcuni intelligenti trucchi di classificazione. Ma nulla avrebbe impedito di sbloccare nuovamente il risultato alla fine, come dovevo fare a mano qui.

+0

Hmm. Ho scritto questa funzione molto semplice per fare questo lavoro: \t 'def EqualsAny (ar, vals): \t out = zeri (ar.shape, DTYPE = bool) \t per val a Vals: \t out + = (ar == val) \t ritorno esterno ne ho pensato che 'numpy.in1d' sarebbe più veloce, ma in realtà richiede più tempo (per lo stesso risultato): \t' In [11]:% timeit EqualsAny (badlabels, smallnum \t 1 loop, migliore di 3: 519 ms per loop \t In [7]:% timeit in1d (badlabels, smallnum) .reshape (badla) bels.shape) \t 1 loop, meglio di 3: 871 ms per loop' Non dovrebbe 'numpy.in1d' essere molto più veloce dato che è scritto in C? Non sto usando '% timeit' correttamente? – arwright3

+0

No, 'in1d' non è scritto in c ma in python, vedi il link al codice sorgente che ho dato. Usa varie funzioni di numpy come 'sort', che dovrebbero essere scritte con speranza in C. Ha anche qualche algoritmo ottimizzato per quando' vals' è breve, che è abbastanza simile alla tua soluzione (ma con '| =' invece di ' + = '). Non so perché la tua versione sia più veloce, questo potrebbe dipendere dalla lunghezza di entrambi gli input. –

5

@ La risposta di Bas è quella che probabilmente stai cercando. Ma ecco un altro modo per farlo, usando vectorize trucco di NumPy:

import numpy as np 
S = set([0,2,6,8]) 

@np.vectorize 
def contained(x): 
    return x in S 

contained(fake) 
=> array([[ True, False, True], 
      [False, False, False], 
      [ True, False, True]], dtype=bool) 

L'aria di questa soluzione è che contained() si chiama per ogni elemento (ad esempio in python-spazio), che rende questo molto più lento di un puro- soluzione numpy.

Problemi correlati