2012-02-13 24 views
10

Ho due matrici molto grandi (60x25000) e vorrei calcolare la correlazione tra le colonne solo tra le due matrici. Ad esempio:Qual è un modo veloce per calcolare la correlazione colonna per colonna in MATLAB

corrVal(1) = corr(mat1(:,1), mat2(:,1); 
corrVal(2) = corr(mat1(:,2), mat2(:,2); 
... 
corrVal(i) = corr(mat1(:,i), mat2(:,i); 

per matrici inferiori posso semplicemente utilizzare:

colCorr = diag(corr(mat1, mat2)); 

ma questo non funziona molto grandi matrici come ho esaurito la memoria. Ho considerato di affettare le matrici per calcolare le correlazioni e poi combinare i risultati, ma mi sembra uno spreco calcolare la correlazione tra le combinazioni di colonne che non sono realmente interessato.

C'è un modo rapido per calcolare direttamente ciò che mi interessa?

Edit: ho usato un ciclo in passato, ma il suo solo modo per rallentare:

mat1 = rand(60,5000); 
mat2 = rand(60,5000); 
nCol = size(mat1,2); 
corrVal = zeros(nCol,1); 

tic; 
for i = 1:nCol 
    corrVal(i) = corr(mat1(:,i), mat2(:,i)); 
end 
toc; 

Questo richiede ~ 1 secondo

tic; 
corrVal = diag(corr(mat1,mat2)); 
toc; 

Questo richiede ~ 0,2 secondi

+0

Ho apportato una modifica al tuo post; per favore controlla se è corretto – Jacob

+1

Inoltre, cosa c'è di sbagliato nell'ovvio ciclo? – Jacob

+0

la modifica è corretta, grazie! Anche il ciclo è un modo per rallentare – slayton

risposta

15

posso ottenere un x100 miglioramento velocità calcolando a mano.

An=bsxfun(@minus,A,mean(A,1)); %%% zero-mean 
Bn=bsxfun(@minus,B,mean(B,1)); %%% zero-mean 
An=bsxfun(@times,An,1./sqrt(sum(An.^2,1))); %% L2-normalization 
Bn=bsxfun(@times,Bn,1./sqrt(sum(Bn.^2,1))); %% L2-normalization 
C=sum(An.*Bn,1); %% correlation 

È possibile confrontare con quel codice:

A=rand(60,25000); 
B=rand(60,25000); 

tic; 
C=zeros(1,size(A,2)); 
for i = 1:size(A,2) 
    C(i)=corr(A(:,i), B(:,i)); 
end 
toc; 

tic 
An=bsxfun(@minus,A,mean(A,1)); 
Bn=bsxfun(@minus,B,mean(B,1)); 
An=bsxfun(@times,An,1./sqrt(sum(An.^2,1))); 
Bn=bsxfun(@times,Bn,1./sqrt(sum(Bn.^2,1))); 
C2=sum(An.*Bn,1); 
toc 
mean(abs(C-C2)) %% difference between methods 

Qui ci sono i tempi di calcolo:

Elapsed time is 10.822766 seconds. 
Elapsed time is 0.119731 seconds. 

La differenza tra i due risultati è molto piccolo:

mean(abs(C-C2)) 

ans = 
    3.0968e-17 

EDIT: spiegazione

bsxfun fa un'operazione colonna per colonna (o riga per riga a seconda dell'ingresso).

An=bsxfun(@minus,A,mean(A,1)); 

Questa linea rimuoverà (@minus) la media di ogni colonna (mean(A,1)) per ogni colonna di A ... Quindi, fondamentalmente rende le colonne di A a media nulla.

An=bsxfun(@times,An,1./sqrt(sum(An.^2,1))); 

Questa riga moltiplica (@times) ogni colonna per l'inverso della sua norma. Quindi li rende normalizzati L-2.

volta che le colonne sono a media zero e L2-normalizzata, per calcolare la correlazione, è sufficiente a rendere il prodotto scalare di ogni colonna di An con ogni colonna di B.Quindi li moltiplichi a livello di elemento An.*Bn e quindi sommi ogni colonna: sum(An.*Bn);.

+0

wow che è veloce. Puoi darmi una rapida spiegazione del motivo per cui funziona? – slayton

+1

Ho aggiunto qualche spiegazione. Spero non sia chiaro ... – Oli

+0

@Oli: Ottima risposta! – Jacob

1

Penso che il ciclo ovvio potrebbe essere sufficiente per la dimensione del problema. Sul mio computer portatile ci vuole meno di 6 secondi per effettuare le seguenti operazioni:

A = rand(60,25000); 
B = rand(60,25000); 
n = size(A,1); 
m = size(A,2); 

corrVal = zeros(1,m); 
for k=1:m 
    corrVal(k) = corr(A(:,k),B(:,k)); 
end 
+0

whoops, non ho visto la tua modifica. Wow, diag è molto più veloce. –

+0

Aspetta, cosa mi manca? diag (corr (A, B)); richiede più di 10 secondi per me. –

+0

Sì. Anch'io. – Jacob

Problemi correlati