マトリックス平方根逆関数の効率的な計算


15

統計の一般的な問題は、対称正定行列の逆平方根を計算することです。これを計算する最も効率的な方法は何でしょうか?

私が出会ったいくつかの文献(私はまだ読んでいない)、およびいくつかの偶発Rコードここで私は便宜のためにここに再現されます、

# function to compute the inverse square root of a matrix
fnMatSqrtInverse = function(mA) {
  ei = eigen(mA)
  d = ei$values
      d = (d+abs(d))/2
      d2 = 1/sqrt(d)
      d2[d == 0] = 0
      return(ei$vectors %*% diag(d2) %*% t(ei$vectors))
}

私はその行を理解しているかどうかはよくわかりませんd = (d+abs(d))/2。マトリックスの平方根逆関数を計算するより効率的な方法はありますか?R eigen関数はLAPACKを呼び出します


dd+|d|/2最大d0A1/2A1/2バツ

@DanielShaperoコメントありがとうございます。PSDマトリックスがある場合、その行は必要ありませんか?私のアプリケーションでは、A ^ {-1/2} BA ^ {-1/2}などの2次形式の計算が必要A1/2BA1/2です。
tchakravarty

私はRに精通していませんが、行7を考えると、Matlabのような論理的なインデックス付けがあると思います。もしそうなら、5行目をとして書き直すことをお勧めしますd[d<0] = 0
フェデリコポロニ

このコードは正しいですか?matlabの簡単な例で実行しましたが、答えが間違っていることがわかりました。私の行列は正定ですが、対称ではありません。以下の私の答えをご覧ください:コードをmatlabに転送しました。
ロニ

回答:


10

投稿したコードは、対称行列の固有値分解を使用してを計算します。 A1/2

声明

d =(d + abs(d))/ 2

dの負のエントリを事実上取得して0に設定し、負でないエントリのみを残します。つまり、負の固有値は0であるかのように扱われます。理論的には、Aの固有値はすべて非負でなければなりませんが、実際には正の定値の固有値を計算するときに小さな負の固有値を見るのが一般的ですほぼ特異な共分散行列。 A

対称行列平方根の逆行列が本当に必要で、が適度に小さい(1,000 x 1,000以下)場合、これは使用する方法とほぼ同じくらい良好です。 AA

多くの場合、代わりに共分散行列の逆数のコレスキー因子(または実質的に同じ、共分散行列自体のコレスキー因子)を使用できます。通常、コレスキー因子の計算は、次の固有値分解の計算よりも1桁高速です。密度の高い行列と、大規模で疎な行列に対して非常に効率的(計算時間と必要なストレージの両方)。したがって、コレスキー分解の使用は、Aが大きくてまばらなます。


6
AAA=BTBBBRA

5

私の経験では、Highamのポーラーニュートン法ははるかに高速に動作します(N. Highamによる行列関数の第6章を参照)。では私のこの短いメモ一次の方法には、この方法を比較するプロットがあります。また、他のいくつかの行列平方根アプローチへの引用も提示されていますが、ほとんどの場合、極ニュートン反復法が最適に機能するようです(そして固有ベクトル計算を回避します)。

% compute the matrix square root; modify to compute inverse root.
function X = PolarIter(M,maxit,scal)
  fprintf('Running Polar Newton Iteration\n');
  skip = floor(maxit/10);
  I = eye(size(M));
  n=size(M,1);
  if scal
    tm = trace(M);
    M  = M / tm;
  else
    tm = 1;
  end
  nm = norm(M,'fro');

  % to compute inv(sqrt(M)) make change here
  R=chol(M+5*eps*I);

  % computes the polar decomposition of R
  U=R; k=0;
  while (k < maxit)
    k=k+1;
    % err(k) = norm((R'*U)^2-M,'fro')/nm;
    %if (mod(k,skip)==0)
    %  fprintf('%d: %E\n', k, out.err(k));
    %end

    iU=U\I;
    mu=sqrt(sqrt(norm(iU,1)/norm(U,1)*norm(iU,inf)/norm(U,inf)));
    U=0.5*(mu*U+iU'/mu);

   if (err(k) < 1e-12), break; end
  end
  X=sqrt(tm)*R'*U;
  X = 0.5*(X+X');
end

0

コードを最適化する:

オプション1-Rコードを最適化します
。あなたはそれへapply()の機能dが両方max(d,0)d2[d==0]=01つのループでできます。
b。で試してみてくださいei$values直接。

オプション2-C ++を使用:
でC ++の関数全体を書き換えRcppArmadilloます。Rから呼び出すことができます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.