矩阵平方根逆的高效计算


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


d(d+|d|)/2max(d,0)A1/2A1/2x

@DanielShapero感谢您的评论。因此,如果我有PSD矩阵,则不需要该行?我的应用程序需要计算二次形式,例如。A1/2BA1/2
tchakravarty

我不熟悉R,但是在第7行中,我假定它具有类似于Matlab的逻辑索引。如果是这样,我建议您将第5行改写为d[d<0] = 0,这更具表现力。
Federico Poloni 2014年

此代码正确吗?我在matlab的一个简单示例上运行了它,发现答案是错误的。我的矩阵是正定的,但绝对不是对称的。请在下面查看我的答案:我已将代码转移到matlab。
罗尼,2015年

Answers:


10

你已经发布使用对称矩阵计算的特征值分解的代码A1/2

该声明

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

有效地获取d中的任何负条目并将其设置为0,同时不保留非负条目。也就是说,将任何负特征值都视为0。从理论上讲,A的特征值都应为非负值,但是在实践中,当计算假设为正的定值的特征值时,通常会看到较小的负特征值几乎是奇异的协方差矩阵。 A

如果您确实需要的对称矩阵平方根的逆,并且A相当小(不超过1,000 x 1,000),那么这与您可以使用的任何方法一样好。 AA

在许多情况下,您可以使用协方差矩阵的逆函数的Cholesky因子(或几乎相同的协方差矩阵本身的Cholesky因子。)计算Cholesky因子通常比为计算特征值分解要快一个数量级。密集矩阵,对于大型和稀疏矩阵,效率更高(在计算时间和所需存储方面)。因此,当较大且稀疏时,使用Cholesky分解非常必要。 A


6
Brian的答案提供了很好的建议:请改用Cholesky系数(如果可以的话)。还有一种优化,你可以在此基础之上做:不要计算你的PSD矩阵。通常,您会从A = B T B的计算中获得A,并且B为矩形。在这种情况下,它足以计算的QR分解获得的Cholesky因数- [R,具有更好的精度。一种一种一种=Ť[R一种
Federico Poloni 2013年

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]=0在一个循环。
b。尝试ei$values直接操作。

选项2-使用C ++:使用
重写C ++中 的整个函数RcppArmadillo。您仍然可以从R调用它。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.