2015-07-18 15 views
10

devo matrice 1D NumPy come segue:mezzi di calcolo locali in una matrice 1D NumPy

import numpy as np 
d = np.array([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]) 

voglio calcolare mezzo di (1,2,6,7), (3,4,8,9), e così via. Ciò implica la media di 4 elementi: due elementi consecutivi e due elementi consecutivi 5 posizioni dopo.

ho provato la seguente:

>> import scipy.ndimage.filters as filt 
>> res = filt.uniform_filter(d,size=4) 
>> print res 
[ 1 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19] 

Questo, purtroppo, non mi dà i risultati desiderati. Come posso farlo?

+1

come hai scelto quei numeri 1,2,6,7? quali sono le regole? –

+0

@omri_saadon due elementi consecutivi e dopo 5 elementi altri due elementi consequenziali. – Borys

+0

Posso vedere che qui ci sono dati interpolati, possibilmente dati di immagine. Perché non riformulare la domanda in modo che sia chiara la sequenza necessaria per ciascuno dei 2 set? – gburton

risposta

11

Invece di indicizzare, è possibile avvicinarsi a questa con una prospettiva di elaborazione del segnale. In pratica stai eseguendo un discrete convolution del tuo segnale di input con un kernel a 7 tasti in cui i tre coefficienti centrali sono 0 mentre gli estremi sono 1, e dal momento che vuoi calcolare la media, devi moltiplicare tutti i valori per (1/4). Tuttavia, non stai calcolando la convoluzione di tutti gli elementi, ma ne parleremo più tardi. Un modo è quello di utilizzare scipy.ndimage.filters.convolve1d per questo:

import numpy as np 
from scipy.ndimage import filters 
d = np.arange(1, 21, dtype=np.float) 
ker = (1.0/4.0)*np.array([1,1,0,0,0,1,1], dtype=np.float) 
out = filters.convolve1d(d, ker)[3:-3:2] 

Perché stai usando un kernel 7 rubinetto, convoluzione si estenderà l'uscita per 3 a sinistra e 3 a destra, quindi è necessario fare in modo di ritaglia il primo e l'ultimo tre elementi. Si vuole anche saltare l'elemento ogni altro elemento perché la convoluzione implica una finestra scorrevole, ma si desidera scartare ogni altro elemento in modo da ottenere il risultato desiderato.

Otteniamo questo per out:

In [47]: out 
Out[47]: array([ 4., 6., 8., 10., 12., 14., 16.]) 

di controllare due volte per vedere se abbiamo il giusto risultato, provare alcuni esempi di calcolo per ogni elemento. Il primo elemento è uguale a (1+2+6+7)/4 = 4. Il secondo elemento è uguale a (3+4+8+9)/4 = 6 e così via.


Per una soluzione con meno mal di testa, prova a numpy.convolve con la bandiera mode=valid. Ciò evita il taglio fuori dalla imbottitura extra a sinistra ea destra, ma sarà ancora bisogno di saltare ogni altro elemento però:

import numpy as np 
d = np.arange(1, 21, dtype=np.float) 
ker = (1.0/4.0)*np.array([1,1,0,0,0,1,1], dtype=np.float) 
out = np.convolve(d, ker, mode='valid')[::2] 

Inoltre otteniamo:

In [59]: out 
Out[59]: array([ 4., 6., 8., 10., 12., 14., 16.]) 

Infine, se si vuole indicizzazione, qualcosa di simile può essere sufficiente:

length = len(d[6::2]) 
out = np.array([(a+b+c+e)/4.0 for (a,b,c,e) in zip(d[::2][:length], d[1::2][:length], d[5::2][:length], d[6::2])]) 

otteniamo:

In [69]: out 
Out[69]: array([ 4., 6., 8., 10., 12., 14., 16.]) 

Questo è davvero brutto, ma funziona. La lunghezza totale del segnale è regolata dal fatto che la fine di ogni finestra è al settimo indice. La lunghezza di questo array che contiene questi indici determina la lunghezza finale del segnale. Inoltre, si noti che per un elemento in una finestra, il suo elemento successivo può essere trovato saltando ogni altro elemento fino alla fine dell'array. Ci sono 4 di queste sequenze in totale e noi semplicemente zip su queste 4 sequenze in cui ogni sequenza salta ogni altro elemento, ma c'è un offset a cui iniziamo.La prima sequenza inizia con l'offset 0, il successivo a 1, il successivo a 5 e il successivo a 6. Raccogliamo questi quattro elementi e li valutiamo mediamente, quindi saltiamo su tutti gli array fino alla fine.

BTW, mi piace ancora la convoluzione.

+0

I commenti non sono per discussioni estese; questa conversazione è stata [spostata in chat] (http://chat.stackoverflow.com/rooms/83631/discussion-on-answer-by-rayryeng-array-indexing-for-calculating-mean). –

1

È possibile utilizzare numpy.lib.stride_tricks.as_strided() per ottenere una matrice raggruppamento applicabile per un caso più generico:

import numpy as np 
from numpy.lib.stride_tricks import as_strided 

d = np.arange(1, 21) 

consec = 2 
offset = 5 
nsub = 2 
pace = 2 

s = d.strides[0] 
ngroups= (d.shape[0] - (consec + (nsub-1)*offset - 1))//pace 
a = as_strided(d, shape=(ngroups, nsub, consec), 
       strides=(pace*s, offset*s, 1*s)) 

Dove:

  • consec è il numero di numeri consecutivi nel sottogruppo
  • offset lo scostamento tra la prima voce di ogni sottogruppo
  • nsub il numero di sottogruppi (1, 2 è un sottogruppo, separato dal secondo sottogruppo 6, 7 da offset
  • pace indica il passo fra il primo ingresso di due gruppi, che nel suo caso è pace=consec, ma potrebbe essere diverso in un altro caso generale

Nel tuo caso (utilizzando i valori riportati) a sarebbe:

array([[[ 1, 2], 
     [ 6, 7]], 

     [[ 3, 4], 
     [ 8, 9]], 

     [[ 5, 6], 
     [10, 11]], 

     [[ 7, 8], 
     [12, 13]], 

     [[ 9, 10], 
     [14, 15]], 

     [[11, 12], 
     [16, 17]], 

     [[13, 14], 
     [18, 19]]]) 

da dove è ancora pronto per ottenere la media desiderata facendo:

a.mean(axis=-1).mean(axis=-1) 

#array([ 4., 6., 8., 10., 12., 14., 16.]) 
+1

trucco molto interessante ... fammi fare l'acquolina in bocca ogni giorno che mi sono allontanato da MATLAB. Perfero la convoluzione ma è bello vedere ... – wbg

Problemi correlati