2013-02-13 20 views
15

Voglio verificare se tutti i valori nelle colonne di una matrice/matrice numpy sono gli stessi. Ho cercato di usare reduce del ufuncequal, ma non sembra funzionare in tutti i casi:Come verificare se tutti i valori nelle colonne di una matrice numpy sono uguali?

In [55]: a = np.array([[1,1,0],[1,-1,0],[1,0,0],[1,1,0]]) 

In [56]: a 
Out[56]: 
array([[ 1, 1, 0], 
     [ 1, -1, 0], 
     [ 1, 0, 0], 
     [ 1, 1, 0]]) 

In [57]: np.equal.reduce(a) 
Out[57]: array([ True, False, True], dtype=bool) 

In [58]: a = np.array([[1,1,0],[1,0,0],[1,0,0],[1,1,0]]) 

In [59]: a 
Out[59]: 
array([[1, 1, 0], 
     [1, 0, 0], 
     [1, 0, 0], 
     [1, 1, 0]]) 

In [60]: np.equal.reduce(a) 
Out[60]: array([ True, True, True], dtype=bool) 

Perché la colonna centrale, nel secondo caso valutare anche True, mentre dovrebbe essere False?

Grazie per qualsiasi aiuto!

+1

Questo problema mi ha infastidito per un po '. Mentre la soluzione di @ Ubuntu è abbastanza elegante, non è molto piacevole provare a eseguire questo su un array doppio 4096 ** 3 solo per ottenere un array booleano che si occupa di qualsiasi memoria rimasta. Stavo giocando con una pura implementazione Python usando 'np.equal (a, a [:, 0, None])', ma questo finisce con lo stesso problema. Sto quindi lavorando su un PR per numpy per aggiungere una nuova funzione 'np.same' per gestire esattamente questo tipo di situazione. –

risposta

24
In [45]: a 
Out[45]: 
array([[1, 1, 0], 
     [1, 0, 0], 
     [1, 0, 0], 
     [1, 1, 0]]) 

confronta ciascun valore al valore corrispondente nella prima fila:

In [46]: a == a[0,:] 
Out[46]: 
array([[ True, True, True], 
     [ True, False, True], 
     [ True, False, True], 
     [ True, True, True]], dtype=bool) 

Una colonna condivide un valore comune se tutti i valori in quella colonna sono True:

In [47]: np.all(a == a[0,:], axis = 0) 
Out[47]: array([ True, False, True], dtype=bool) 

Il problema con np.equal.reduce può essere visto analizzando in micro-analisi cosa succede quando viene applicato a [1, 0, 0, 1]:

In [49]: np.equal.reduce([1, 0, 0, 1]) 
Out[50]: True 

I primi due elementi, 1 e 0 sono testati per l'uguaglianza e il risultato è False:

In [51]: np.equal.reduce([False, 0, 1]) 
Out[51]: True 

Ora False e 0 sono testati per l'uguaglianza e il risultato è True:

In [52]: np.equal.reduce([True, 1]) 
Out[52]: True 

Ma True e 1 sono uguali, quindi il totale il risultato è True, che non è il risultato desiderato.

Il problema è che reduce tenta di accumulare il risultato "localmente", mentre vogliamo un test "globale" come np.all.

+0

Ottima risposta. C'è un modo per fare qualcosa di simile per i grandi array senza creare l'array di maschere? Questo deve essere stato l'appello iniziale dell'OP all'utilizzo di 'reduce'. –

+1

Non sono a conoscenza di alcun metodo NumPy in base al quale è possibile produrre il risultato senza gli array di dati (boolean) . Se si sta lavorando con un array molto grande e la memoria è stretta, è possibile "frammentare" l'array in pezzi (ad esempio array costituiti da N righe) e testare ciascun pezzo separatamente. Quindi combinare e testare i pezzi, aggregando il risultato. – unutbu

+1

Si potrebbe anche voler esaminare [numpy.memmap] (http://docs.scipy.org/doc/numpy-1.10.0/reference/generated/numpy.memmap.html), o [Pytables] (http://www.pytables.org/) o [h5py] (http://www.h5py.org/) per memorizzando il tuo grande array su disco in modo da poter estrarre e lavorare con una porzione di array in un tempo senza richiedere l'archiviazione dell'intero array in memoria. In questo modo si potrebbe avere più spazio per gli array temporanei che NumPy (di solito) richiede. – unutbu

7

impressionante spiegazione di ubuntu Dato, è possibile utilizzare reduce per risolvere il problema, ma bisogna applicarlo a bitwise_and e bitwise_or piuttosto che equal. Di conseguenza, questo non funzionerà con matrici in virgola mobile:

In [60]: np.bitwise_and.reduce(a) == a[0] 
Out[60]: array([ True, False, True], dtype=bool) 

In [61]: np.bitwise_and.reduce(b) == b[0] 
Out[61]: array([ True, False, True], dtype=bool) 

Fondamentalmente, si confrontano i bit di ciascun elemento della colonna. I bit identici sono invariati. Bit diversi sono impostati su zero. In questo modo, qualsiasi numero che abbia uno zero invece di un bit cambierà il valore ridotto. bitwise_and non intercetterà il caso in cui vengono introdotti i bit anziché rimossi:

In [62]: c = np.array([[1,0,0],[1,0,0],[1,0,0],[1,1,0]]) 

In [63]: c 
Out[63]: 
array([[1, 0, 0], 
     [1, 0, 0], 
     [1, 0, 0], 
     [1, 1, 0]]) 

In [64]: np.bitwise_and.reduce(c) == c[0] 
Out[64]: array([ True, True, True], dtype=bool) 

Il secondo coumn è chiaramente sbagliato.Dobbiamo usare bitwise_or per intrappolare nuovi bit:

In [66]: np.bitwise_or.reduce(c) == c[0] 
Out[66]: array([ True, False, True], dtype=bool) 

risposta definitiva

In [69]: np.logical_and(np.bitwise_or.reduce(a) == a[0], np.bitwise_and.reduce(a) == a[0]) 
Out[69]: array([ True, False, True], dtype=bool) 

In [70]: np.logical_and(np.bitwise_or.reduce(b) == b[0], np.bitwise_and.reduce(b) == b[0]) 
Out[70]: array([ True, False, True], dtype=boo 

In [71]: np.logical_and(np.bitwise_or.reduce(c) == c[0], np.bitwise_and.reduce(c) == c[0]) 
Out[71]: array([ True, False, True], dtype=bool) 

Questo metodo è più restrittiva e meno elegante di suggerimento di ubunut di utilizzare all, ma ha il vantaggio di non creare enormi array temporanei se il tuo contributo è enorme. Gli array temporanei dovrebbero essere grandi quanto la prima riga della matrice.

EDIT

Sulla base di questo Q/A e the bug I filed with numpy, la soluzione fornita funziona solo perché la matrice contiene zero e uno. Come accade, le operazioni bitwise_and.reduce() visualizzate possono sempre restituire zero o uno solo perché bitwise_and.identity è 1, non -1. Sto mantenendo questa risposta nella speranza che numpy venga corretto e la risposta diventi valida.

Modifica

Sembra che ci saranno in effetti essere un cambiamento a numpy presto. Certamente a bitwise_and.identity e forse anche un parametro facoltativo da ridurre.

Modifica

Buone notizie a tutti. L'identità per np.bitwise_and è stata impostata su -1 a partire dalla versione 1.12.0.

Problemi correlati