これは、私の古い答えが別のスレッドからここに移動したコードで拡張されています。
私は長年にわたり、線形方程式系の解法を使用したハットマトリックスアプローチを介して、SPSSのペアワイズマハラノビス距離の正方対称マトリックスの計算を行ってきました(共分散マトリックスの反転よりも高速であるため)。
私はRユーザーではないので、SPSSで@ahfossのこのレシピを「私の」レシピと一緒に、変数が1000個、変数が400個のデータで再現しようとしましたが、かなり速くなりました。
ペアワイズマハラノビス距離の完全な行列を計算するより高速な方法は、ハット行列を使用することです H。つまり、非常に高速な行列乗算と反転関数が組み込まれた高水準言語(Rなど)を使用している場合、ループはまったく必要なく、ケースワイズループを実行するよりも高速になります。
定義。2乗ペアワイズマハラノビス距離の二重中心行列は、H(n−1)、ここで帽子行列は X (X′X )− 1バツ′、列中心のデータから計算 バツ。
したがって、データ行列の列を中央に配置し、ハット行列を計算し、(n-1)を掛けて、二重センタリングと逆の操作を実行します。平方マハラノビス距離の行列を取得します。
「ダブルセンタリング」とは、距離の2乗(ユークリッドやマハラノビスなど)を、データクラウドの幾何学的重心から定義されたスカラー積に幾何学的に正しく変換することです。この操作は、コサイン定理に暗黙的に基づいています。多変量データポイト間にユークリッド距離の2乗の行列があるとします。雲の重心(多変量平均)を見つけ、各ペアワイズ距離を対応するスカラー積(ドット積)で置き換えます。距離に基づいていますhリンクに示されているように、重心とそれらのベクトル間の角度。のh2sは、スカラー積の行列の対角線上にあり、 h1h2cos are the off-diagonal entries. Then, using directly the cosine theorem formula you easily convert the "double-centrate" matrix back into the squared distance matrix.
In our settings, the "double-centrate" matrix is specifically the hat matrix (multiplied by n-1), not euclidean scalar products, and the resultant squared distance matrix is thus the squared Mahalanobis distance matrix, not squared euclidean distance matrix.
In matrix notation: Let H be the diagonal of H(n−1), a column vector. Propagate the column into the square matrix: H= {H,H,...}
; then D2mahal=H+H′−2H(n−1).
SPSSとスピードプローブのコードは次のとおりです。
この最初のコードfastPwMahal
は、引用された回答の @ahfoss関数に対応しています。数学的には同等です。しかし、@ ahfossは対称行列の三角形を(要素ごとに)計算しながら、距離の完全な対称行列を計算しています(行列演算を使用)。
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
以下は、高速化するための私の変更です。
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 )− 1バツ′ 一般化された逆経由 (X′X )− 1バツ′線形システムソルバーで得られ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