Este es el código expandido que mi vieja respuesta movió aquí desde otro hilo .
He estado haciendo durante mucho tiempo el cálculo de una matriz simétrica cuadrada de distancias de Mahalanobis por pares en SPSS a través de un enfoque de matriz de sombrero utilizando la resolución de un sistema de ecuaciones lineales (porque es más rápido que invertir la matriz de covarianza).
No soy usuario de R, así que intenté reproducir esta receta de @ahfoss aquí en SPSS junto con "mi" receta, en un dato de 1000 casos por 400 variables, y encontré mi camino considerablemente más rápido.
Una forma más rápida para calcular la matriz completa de los pares distancias de Mahalanobis es a través del sombrero matriz . Quiero decir, si está utilizando un lenguaje de alto nivel (como R) con funciones de inversión y multiplicación matricial bastante rápidas incorporadas, no necesitará ningún bucle, y será más rápido que hacer bucles de mayúsculas y minúsculas.H
Definición . La matriz de doble centrado de las distancias al cuadrado de Mahalanobis en pares es igual a , donde la matriz del sombrero es , calculada a partir de la columna centrada los datos .H (n-1)X ( X′X )- 1X′X
Entonces, centre las columnas de la matriz de datos, calcule la matriz del sombrero, multiplique por (n-1) y realice la operación opuesta al doble centrado. Obtienes la matriz de distancias cuadradas de Mahalanobis.
"Doble centrado" es la conversión geométricamente correcta de distancias cuadradas (como Euclidiana y Mahalanobis) en productos escalares definidos a partir del centroide geométrico de la nube de datos. Esta operación se basa implícitamente en el teorema del coseno . Imagine que tiene una matriz de distancias euclidianas cuadradas entre sus puntos de datos multivariados. Encuentra el centroide (media multivariada) de la nube y reemplaza cada distancia por pares por el producto escalar correspondiente (producto de puntos), se basa en las distancias s al centroide y el ángulo entre esos vectores, como se muestra en el enlace. Los s se encuentran en la diagonal de esa matriz de productos escalares yhh2h1h2cosson las entradas fuera de diagonal. Luego, usando directamente la fórmula del teorema del coseno, puede convertir fácilmente la matriz de "doble centrado" en la matriz de distancia al cuadrado.
En nuestra configuración, la matriz de "doble centrado" es específicamente la matriz del sombrero (multiplicada por n-1), no los productos escalares euclidianos, y la matriz de distancia al cuadrado resultante es, por lo tanto, la matriz de distancia al cuadrado de Mahalanobis, no la matriz de distancia al cuadrado euclidiana.
En notación matricial: Sea la diagonal de , un vector de columna. Propagar la columna en la matriz cuadrada: ; entonces .HH (n-1)H= {H,H,...}
re2m a h a l= H+ H′- 2 H ( n - 1 )
El código en SPSS y la sonda de velocidad está debajo.
Este primer código corresponde a la función @ahfoss fastPwMahal
de la respuesta citada . Es equivalente a esto matemáticamente. Pero estoy calculando la matriz simétrica completa de distancias (a través de operaciones matriciales) mientras que @ahfoss calculó un triángulo de la matriz simétrica (elemento por 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
La siguiente es mi modificación para hacerlo más rápido:
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
Finalmente, el "enfoque de matriz de sombrero". Para la velocidad, estoy calculando la matriz del sombrero (los datos deben estar centrados primero) través de inversa generalizada obtenido en solucionador de sistemas lineales . ( X ′ X ) - 1 X ′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