2015-07-31 15 views
5

Hesaplamak için çok sayıda çapraz korelasyon var ve bunu yapmanın en hızlı yolunu arıyorum. Ben sorunu vectorized varsayarak yardımcı olacağını varsayarak döngülernumpy çapraz korelasyon - vectorize

Elektrot x zaman noktası x deneme olarak etiketlenmiş bir 3D dizi var (şekil: 64x256x913). Her deneme için her elektrot çifti için zaman noktalarının maksimum çapraz korelasyonunu hesaplamak istiyorum.

Spesifik olarak: her deneme için, her bir çift elektrot kombinasyonunu almak ve her bir çift için maksimum çapraz korelasyon değerini hesaplamak istiyorum. Bu, tek bir satırda/vektörde 4096 (64 * 64) max çapraz korelasyon değeriyle sonuçlanacaktır. Bu, her bir deneme için, her biri üst üste dizilmiş satır/vektörlerin üst üste yerleştirilmesiyle, maksimum çapraz korelasyon değerlerini içeren son 912 * 4096 şeklindeki son 2B dizi ile sonuçlanır.

Bunu yapmak için en hızlı yöntemi bulmaya çalışın. Listeleri problemi biraz daha iyi açıklamaya yardımcı olabilecek kapsayıcılar olarak kullanarak bazı proto-kodu alay ettim. Orada bazı mantıksal hatalar olabilir, ancak her iki durumda da bilgisayarımda kod çalışmaz, çünkü bu pitonun sadece donması için hesaplaması çok fazladır. İşte bu:
#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) 

Açıktır ki bu tür şeyler için döngüler gerçekten yavaştır. Numpy dizileri kullanarak buna vektör çözüm var mı?

ben correlate2d() ve benzeri gibi şeyler kontrol ettik ama ben birlikte

cevap

3

2 matris çarpma değilim ben İşte bir vectorized yaklaşım np.einsum dayalı olduğunu onlar gerçekten benim durumumda işe sanmıyorum -

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] 

Süre testi ve doğrulama sonuçları -

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

bu yarın daha yakından bakmak gerekecek - Daha önce gösterimde bu şekil görmemiştim! Fakat sadece (kısaca) okuduğumdan, einstein toplama yöntemi toplam ve çarpma işlemlerini iletebilir, bu da 0 gecikme çapraz korelasyon için iyidir, fakat aynı zamanda sürgülü pencere elemanı da vardır ... işlev vektörleri yeniden hizalamak mı? – Simon

+0

@Nem İki eşit uzunluklu 1D dizisi arasında ilişki kurduğunuzdan, "np.correlate" uygulamasına göre, kayma "özgürlüğüne" sahip değil. Yani, esas olarak tüm uzunluk boyunca elemansal çarpma ve ekleme. Bu, "np.einsum" ile temelde "kötüye kullanıldı". Bu, soruda listelenen kodlara dayanmaktadır. Umarım bu mantıklıdır! – Divakar

+0

ah haklısın, yukarıdaki kodum yanlış. Aradığım şey 2 vektör arasında bir çapraz korelasyon. Yani, herhangi bir elektrot çifti için, bir vektörü zaman içinde kaydırmam, önerdiğin hesaplamayı yap, tekrar kaydır, tekrar hesapla. Hangi olası her vardiyada korelasyon içeren bir vektör döndürecektir. O zaman sadece bu korelasyon değerlerinin maksimumuna ihtiyacım var. Bu zaman kaydırma, bu, nasıl vektörleştirileceğini anlamaya çalışırken başımı ağrıtıyor. Bu açıklamanın daha iyi bir işi: http://stackoverflow.com/questions/6284676/a-question-on-cross-correlation-correlation-coefficient – Simon