2013-08-21 12 views
7

Ho un array di NumPy con una forma di:Get media della fetta 2D di una matrice 3D in NumPy

(11L, 5L, 5L) 

voglio calcolare la media sopra i 25 elementi di ogni 'fetta' di matrice [ 0,:,:], [1,:,:] ecc., Restituendo 11 valori.

Sembra sciocco, ma non riesco a capire come farlo. Ho pensato che la funzione mean(axis=x) avrebbe fatto questo, ma ho provato tutte le possibili combinazioni di assi e nessuno di loro mi dà il risultato che voglio.

Posso ovviamente farlo utilizzando un ciclo for e slicing, ma sicuramente c'è un modo migliore?

risposta

11

Utilizzare una tupla per asse:

>>> a = np.arange(11*5*5).reshape(11,5,5) 
>>> a.mean(axis=(1,2)) 
array([ 12., 37., 62., 87., 112., 137., 162., 187., 212., 
     237., 262.]) 

Modifica: Questo wor ks solo con numpy versione 1.7+.

+2

Funziona? Lo si potrebbe pensare per 1.7 e in seguito, ma i documenti dicono ancora solo un asse. – Jaime

+1

Non ho pensato alla versione numpy, ho 1.7.1 e funziona. Non è nella documentazione ma il changelog parla di ufuncs: http://www.softpedia.com/progChangelog/Numpy-Changelog-103892.html –

+2

Cool, non sapevo che fosse stato aggiunto! – lmjohns3

4

È possibile reshape(11, 25) e quindi chiamare mean solo una volta (più veloce):

a.reshape(11, 25).mean(axis=1) 

In alternativa, è possibile chiamare np.mean due volte (circa 2X più lento sul mio computer):

a.mean(axis=2).mean(axis=1) 
+1

Penso che questa sia la risposta più semplice, anche se il einsum sembra essere più veloce. – lmjohns3

5

sempre possibile utilizzare np.einsum:

>>> a = np.arange(11*5*5).reshape(11,5,5) 
>>> np.einsum('...ijk->...i',a)/(a.shape[-1]*a.shape[-2]) 
array([ 12, 37, 62, 87, 112, 137, 162, 187, 212, 237, 262]) 

Opere su array di dimensione superiore (tutti questi metodi sarebbero se le etichette degli assi vengono modificati):

>>> a = np.arange(10*11*5*5).reshape(10,11,5,5) 
>>> (np.einsum('...ijk->...i',a)/(a.shape[-1]*a.shape[-2])).shape 
(10, 11) 

più veloce per l'avvio:

a = np.arange(11*5*5).reshape(11,5,5) 

%timeit a.reshape(11, 25).mean(axis=1) 
10000 loops, best of 3: 21.4 us per loop 

%timeit a.mean(axis=(1,2)) 
10000 loops, best of 3: 19.4 us per loop 

%timeit np.einsum('...ijk->...i',a)/(a.shape[-1]*a.shape[-2]) 
100000 loops, best of 3: 8.26 us per loop 

Le scale sono leggermente migliori degli altri metodi con l'aumentare della dimensione dell'array.

Utilizzando dtype=np.float64 non cambia i tempi di cui sopra sensibilmente, così giusto per doppio controllo:

a = np.arange(110*50*50,dtype=np.float64).reshape(110,50,50) 

%timeit a.reshape(110,2500).mean(axis=1) 
1000 loops, best of 3: 307 us per loop 

%timeit a.mean(axis=(1,2)) 
1000 loops, best of 3: 308 us per loop 

%timeit np.einsum('...ijk->...i',a)/(a.shape[-1]*a.shape[-2]) 
10000 loops, best of 3: 145 us per loop 

anche qualcosa che è interessante:

%timeit np.sum(a) #37812362500.0 
100000 loops, best of 3: 293 us per loop 

%timeit np.einsum('ijk->',a) #37812362500.0 
100000 loops, best of 3: 144 us per loop 
+1

Penso che la velocità arrivi dalla tua chiamata a 'np.einsum' usando un accumulatore' int', invece di 'float' o' double', non sono sicuro, che 'np.mean' usi. Questa è una cosa rischiosa da fare con le statistiche di calcolo, in quanto è possibile sovraccaricare l'accumulatore e ottenere risultati molto sbagliati. Dare 'np.einsum' a' dtype = np.float' o 'dtype = np.double' renderebbe il calcolo più robusto e (immagino qui) più simile nelle prestazioni alle funzioni standard. Ma 'np.einsum' è ancora una funzione fantastica, quindi ottieni il tuo +1 ... – Jaime

+0

@Jamie. Questo è stato anche il mio pensiero, ma nei miei test iniziali ho dimostrato che 'einsum' era effettivamente più veloce per qualsiasi dimensione e tipo.Ho aggiornato il post con i tempi 'np.double'. – Daniel

+0

@Ophion ... è strano che 'sum()' non dia la stessa velocità di 'einsum()' ... molto ben osservata ... in realtà il secondo metodo più veloce per calcolare la media sarebbe: 'timeit a.sum (axis = (1,2))/a.shape [-1] /a.shape [-2] ' –

Problemi correlati