2015-07-31 25 views
5

Ho un gran numero di cross-correlazioni da calcolare e sto cercando il modo più veloce per farlo. Sto assumendo che la soluzione del problema sia più utile che con i loopcross-correlazione numpy - vettorizzazione

Ho un array 3D etichettato come elettrodo x cronometro x trial (forma: 64x256x913). Voglio calcolare la massima cross-correlazione dei tempi per ogni coppia di elettrodi, per ogni prova.

In particolare: per ogni prova, voglio prendere ciascuna combinazione di elettrodi di coppia e calcolare il valore di cross-correlazione massimo per ogni coppia. Ciò si tradurrà in 4096 (64 * 64) valori di cross-correlazione massimi in una singola riga/vettore. Questo sarà fatto per ogni prova, impilando ciascuna delle righe/vettori l'uno sopra l'altro risultando in un array 2D finale di forma 913 * 4096 contenente i valori di massima correlazione incrociata

Questo è un sacco di calcoli ma voglio prova a trovare il metodo più veloce per farlo. Ho preso in giro alcuni proto-codici usando elenchi come contenitori che potrebbero aiutare a spiegare un po 'meglio il problema. Ci possono essere degli errori logici, ma in entrambi i casi il codice non viene eseguito sul mio computer perché c'è così tanto da calcolare che Python si blocca. Eccolo:

#allData is a 64x256x913 array 

all_experiment_trials = [] 
for trial in range(allData.shape[2]): 
    all_trial_electrodes = [] 
    for electrode in range(allData.shape[0]): 
     for other_electrode in range(allData.shape[0]): 
      if electrode == other_electrode: 
       pass 
      else: 
       single_xcorr = max(np.correlate(allData[electrode,:,trial], allData[other_electrode,:,trial], "full")) 
       all_trial_electrodes.append(single_xcorr) 
    all_experiment_trials.append(all_trial_electrodes) 

Ovviamente i loop sono veramente lenti per questo tipo di cose. Esiste una soluzione vettoriale per questo usando array numpy?

Ho controllato le cose come correlate2d() e simili, ma non credo che lavorano veramente nel mio caso come io non sto moltiplicando 2 matrici insieme

risposta

3

Ecco un approccio vettorizzati sulla base di np.einsum -

def vectorized_approach(allData): 
    # Get shape 
    M,N,R = allData.shape 

    # Valid mask based on condition: "if electrode == other_electrode" 
    valid_mask = np.mod(np.arange(M*M),M+1)!=0 

    # Elementwise multiplications across all elements in axis=0, 
    # and then summation along axis=1 
    out = np.einsum('ijkl,ijkl->lij',allData[:,None,:,:],allData[None,:,:,:]) 

    # Use valid mask to skip columns and have the final output 
    return out.reshape(R,-1)[:,valid_mask] 

prova Runtime e verificare i risultati -

In [10]: allData = np.random.rand(20,80,200) 

In [11]: def org_approach(allData): 
    ...:  all_experiment_trials = [] 
    ...:  for trial in range(allData.shape[2]): 
    ...:   all_trial_electrodes = [] 
    ...:   for electrode in range(allData.shape[0]): 
    ...:    for other_electrode in range(allData.shape[0]): 
    ...:     if electrode == other_electrode: 
    ...:      pass 
    ...:     else: 
    ...:      single_xcorr = max(np.correlate(allData[electrode,:,trial], allData[other_electrode,:,trial])) 
    ...:      all_trial_electrodes.append(single_xcorr) 
    ...:   all_experiment_trials.append(all_trial_electrodes) 
    ...:  return all_experiment_trials 
    ...: 

In [12]: %timeit org_approach(allData) 
1 loops, best of 3: 1.04 s per loop 

In [13]: %timeit vectorized_approach(allData) 
100 loops, best of 3: 15.1 ms per loop 

In [14]: np.allclose(vectorized_approach(allData),np.asarray(org_approach(allData))) 
Out[14]: True 
+0

dovrò dare un'occhiata più da vicino a questo domani - non ho mai visto questo tipo di notazione di prima! Ma da quello che ho appena letto (brevemente), il metodo di sommazione di einstein può trasmettere operazioni di somma e moltiplicazione, che va bene per una correlazione incrociata a 0 lag, ma c'è anche un elemento di finestra scorrevole ... come fa il la funzione riallinea i vettori? – Simon

+0

@Nem Poiché si sta eseguendo la correlazione tra due array 1D di uguale lunghezza, quindi in base all'implementazione di 'np.correlate', non ha la" libertà "di scorrimento. Quindi, essenzialmente è la moltiplicazione e l'aggiunta elementare su tutta la lunghezza. Questo è fondamentalmente "abusato" qui con 'np.einsum'. Questo è tutto basato sul codice elencato nella domanda. Spero che abbia avuto senso! – Divakar

+0

ah hai ragione, il mio codice sopra non è corretto. Quello che sto cercando è una correlazione incrociata tra 2 vettori. Quindi, per ogni coppia di elettrodi, ho bisogno di spostare un vettore nel tempo, fare il calcolo che hai suggerito, spostare di nuovo, ricalcolare. Che restituirà un vettore contenente correlazioni in ogni momento possibile. Ho quindi bisogno solo del massimo di questi valori di correlazione. È questa volta che mi sta dando fastidio quando cerco di capire come vettorializzare. Questo spiega meglio: http://stackoverflow.com/questions/6284676/a-question-on-cross-correlation-correlation-coefficient – Simon

Problemi correlati