Questo è l'espansione con codice che la mia vecchia risposta ha spostato qui da un altro thread .
Ho fatto per molto tempo il calcolo di una matrice quadrata simmetrica di distanze Mahalanobis a coppie in SPSS tramite un approccio a matrice di cappelli usando la risoluzione di un sistema di equazioni lineari (poiché è più veloce dell'inversione della matrice di covarianza).
Non sono un utente R, quindi ho appena provato a riprodurre questa ricetta di @ahfoss qui in SPSS insieme alla "mia" ricetta, su un dato di 1000 casi per 400 variabili, e ho trovato la mia strada molto più veloce.
H
H (n-1)X ( X'X )- 1X'X
Quindi, centra le colonne della matrice dei dati, calcola la matrice del cappello, moltiplica per (n-1) ed esegui l'operazione opposta al doppio centraggio. Ottieni la matrice delle distanze quadrate di Mahalanobis.
hh2h1h2cos
Nelle nostre impostazioni, la matrice "double-centrate" è specificamente la matrice di cappello (moltiplicata per n-1), non prodotti scalari euclidei, e la risultante matrice di distanza quadrata è quindi la matrice di distanza quadrata di Mahalanobis, non la matrice di distanza euclidea quadrata.
HH (n-1)H= {H,H,...}
D2m a h a l= H+ H'- 2 H (n-1)
Il codice in SPSS e sonda di velocità è sotto.
Questo primo codice corrisponde alla funzione @ahfoss fastPwMahal
della risposta citata . È equivalente ad esso matematicamente. Ma sto calcolando la matrice simmetrica completa delle distanze (tramite operazioni di matrice) mentre @ahfoss ha calcolato un triangolo della matrice simmetrica (elemento per elemento).
matrix. /*Matrix session in SPSS;
/*note: * operator means matrix multiplication, &* means usual, elementwise multiplication.
get data. /*Dataset 1000 cases x 400 variables
!cov(data%cov). /*compute usual covariances between variables [this is my own matrix function].
comp icov= inv(cov). /*invert it
call svd(icov,u,s,v). /*svd
comp isqrcov= u*sqrt(s)*t(v). /*COV^(-1/2)
comp Q= data*isqrcov. /*Matrix Q (see ahfoss answer)
!seuclid(Q%m). /*Compute 1000x1000 matrix of squared euclidean distances;
/*computed here from Q "data" they are the squared Mahalanobis distances.
/*print m. /*Done, print
end matrix.
Time elapsed: 3.25 sec
Di seguito è la mia modifica per renderlo più veloce:
matrix.
get data.
!cov(data%cov).
/*comp icov= inv(cov). /*Don't invert.
call eigen(cov,v,s2). /*Do sdv or eigen decomposition (eigen is faster),
/*comp isqrcov= v * mdiag(1/sqrt(s2)) * t(v). /*compute 1/sqrt of the eigenvalues, and compose the matrix back, so we have COV^(-1/2).
comp isqrcov= v &* (make(nrow(cov),1,1) * t(1/sqrt(s2))) * t(v). /*Or this way not doing matrix multiplication on a diagonal matrix: a bit faster .
comp Q= data*isqrcov.
!seuclid(Q%m).
/*print m.
end matrix.
Time elapsed: 2.40 sec
X ( X'X )- 1X'( X'X )- 1X'solve(X'X,X')
matrix.
get data.
!center(data%data). /*Center variables (columns).
comp hat= data*solve(sscp(data),t(data))*(nrow(data)-1). /*hat matrix, and multiply it by n-1 (i.e. by df of covariances).
comp ss= diag(hat)*make(1,ncol(hat),1). /*Now using its diagonal, the leverages (as column propagated into matrix).
comp m= ss+t(ss)-2*hat. /*compute matrix of squared Mahalanobis distances via "cosine rule".
/*print m.
end matrix.
[Notice that if in "comp ss" and "comp m" lines you use "sscp(t(data))",
that is, DATA*t(DATA), in place of "hat", you get usual sq.
euclidean distances]
Time elapsed: 0.95 sec