2015-08-15 16 views
6

Cerco di sottrarre la media di ogni riga di una matrice in numpy utilizzando la trasmissione ma ottengo un errore. Qualche idea del perché?sottraendo la media di ogni riga numpy con broadcasting

Ecco il codice:

from numpy import * 
X = random.rand(5, 10) 
Y = X - X.mean(axis = 1) 

Errore:

ValueError: operands could not be broadcast together with shapes (5,10) (5,) 

Grazie!

+0

Ora si può spiegare il motivo per cui 'X - X.mean (axis = 0) 'funziona senza il parametro' keepdims'? :) – hpaulj

risposta

18

Il metodo mean è una riduzione operazione, ovvero converte una raccolta di numeri 1 in un numero singolo. Quando si applica una riduzione a una matrice n-dimensionale lungo un asse, numpy collassa quella dimensione sul valore ridotto, risultando in una matrice (n-1) -dimensionale. Nel suo caso, poiché X ha forma (5, 10), ed è stata eseguita una riduzione lungo l'asse 1, si finisce con una matrice di forma (5,):

In [8]: m = X.mean(axis=1) 

In [9]: m.shape 
Out[9]: (5,) 

Quando si tenta di sottrarre questo risultato da X, si sta tentando di sottrarre una matrice con forma (5,) da una matrice con forma (5, 10). Queste forme non sono compatibili per broadcasting. (Date un'occhiata a the description of broadcasting in the User Guide.)

Per trasmettere come funziona, il risultato dell'operazione mean deve essere un array di forma (5, 1) (compatibile con la forma (5, 10)). Nelle versioni recenti di numpy, le operazioni di riduzione, incluso mean, hanno un argomento chiamato keepdims che indica alla funzione di non comprimere la dimensione ridotta. Invece, una dimensione banale con lunghezza 1 viene mantenuto:

In [10]: m = X.mean(axis=1, keepdims=True) 

In [11]: m.shape 
Out[11]: (5, 1) 

Con le versioni precedenti di NumPy, è possibile utilizzare reshape per ripristinare la dimensione crollato:

In [12]: m = X.mean(axis=1).reshape(-1, 1) 

In [13]: m.shape 
Out[13]: (5, 1) 

Quindi, a seconda della versione di numpy, si può fare questo:

Y = X - X.mean(axis=1, keepdims=True) 

o questo:

Y = X - X.mean(axis=1).reshape(-1, 1) 
+0

Ottima risposta! Grazie. – yuval

1

Se stai cercando prestazioni, puoi anche considerare l'utilizzo di np.einsum presumibilmente più veloce rispetto all'utilizzo effettivo di np.sum o np.mean. Così, l'uscita desiderata potrebbe essere ottenuta in questo modo -

X - np.einsum('ij->i',X)[:,None]/X.shape[1] 

Si noti che la parte [:,None] è simile a keepdims per mantenere le dimensioni di essa stessa di quella della matrice di input. Questo potrebbe anche essere usato nelle trasmissioni.

Runtime mette alla prova

1) Confrontando solo il mean di calcolo -

In [47]: X = np.random.rand(500, 1000) 

In [48]: %timeit X.mean(axis=1, keepdims=True) 
1000 loops, best of 3: 1.5 ms per loop 

In [49]: %timeit X.mean(axis=1).reshape(-1, 1) 
1000 loops, best of 3: 1.52 ms per loop 

In [50]: %timeit np.einsum('ij->i',X)[:,None]/X.shape[1] 
1000 loops, best of 3: 832 µs per loop 

2) Confrontando intero calcolo -

In [52]: X = np.random.rand(500, 1000) 

In [53]: %timeit X - X.mean(axis=1, keepdims=True) 
100 loops, best of 3: 6.56 ms per loop 

In [54]: %timeit X - X.mean(axis=1).reshape(-1, 1) 
100 loops, best of 3: 6.54 ms per loop 

In [55]: %timeit X - np.einsum('ij->i',X)[:,None]/X.shape[1] 
100 loops, best of 3: 6.18 ms per loop 
Problemi correlati