Matris karekök tersinin verimli hesaplanması


15

İstatistiklerde sık karşılaşılan bir problem, simetrik pozitif belirli bir matrisin ters kökünün hesaplanmasıdır. Bunu hesaplamanın en etkili yolu ne olabilir?

Burada (henüz okumadım) bazı literatür ve rastlantısal olarak burada çoğaltacağım bazı rastlantısal R kodlarıyla karşılaştım.

# 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))
}

Hattı anladığımdan tam olarak emin değilim d = (d+abs(d))/2. Matris karekökünü ters hesaplamanın daha etkili bir yolu var mı? R eigenişlevi LAPACK'i çağırır .


d(d+|d|)/2A - 1 / 2 A - 1 / 2 xmaksimum(d,0)bir-1/2bir-1/2x

@DanielShapero Yorumunuz için teşekkür ederiz. PSD matrisim varsa, bu çizgiye ihtiyacım yok mu? Uygulamam gibi karesel formların hesaplanmasını gerektiriyor . bir-1/2Bbir-1/2
tchakravarty

R'ye aşina değilim, ancak 7. satır verildiğinde Matlab gibi mantıksal indeksleme olduğunu varsayıyorum. Öyleyse, 5. satırı d[d<0] = 0daha etkileyici bir şekilde yeniden yazmanızı öneririm .
Federico Poloni

Bu kod doğru mu? Matlab'da basit bir örnek üzerinde çalıştım ve cevabın yanlış olduğunu buldum. Matrisim pozitif tanımlı ama kesinlikle simetrik değil. Lütfen aşağıdaki cevabıma bakın: Kodu matlab'a aktardım.
roni

Yanıtlar:


10

Gönderdiğiniz kod, değerini hesaplamak için simetrik matrisin özdeğer ayrışmasını kullanır . bir-1/2

İfade

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

d'deki herhangi bir negatif girişi etkili bir şekilde alır ve negatif olmayan girişleri yalnız bırakırken 0'a ayarlar. Yani herhangi olumsuz özdeğerin olan o Teoride, A'nın özdeğerleri olmayan tüm negatif olmamalıdır 0. oldu sanki tedavi edilir, ancak kesin bir sözde pozitif özdeğerlerini hesaplamak zaman pratikte 's yaygın küçük negatif özdeğer görmek neredeyse tekil olan kovaryans matrisi. bir

simetrik matris kare kökünün tersine gerçekten ihtiyacınız varsa ve makul derecede küçükse (1000'den 1000'e kadar daha büyük değildir), bu kullanabileceğiniz herhangi bir yöntem kadar iyidir. Abirbir

Birçok durumda, bunun yerine kovaryans matrisinin tersinin bir Cholesky faktörünü kullanabilirsiniz (veya pratikte aynı, kovaryans matrisinin Cholesky faktörü.) Cholesky faktörünün hesaplanması, genellikle özdeğer ayrışmasını hesaplamaktan daha hızlı bir büyüklük sırasıdır. yoğun matrisler ve büyük ve seyrek matrisler için çok daha verimli (hem hesaplama zamanında hem de gerekli depolama). Bu nedenle, Cholesky çarpanlarına ayırma yönteminin kullanılması büyük ve seyrek olduğunda çok arzu edilir hale gelir . bir


6
birbirbir=BTBBBR,bir

5

Deneyimlerime göre, Higham'ın polar-Newton yöntemi çok daha hızlı çalışır (bkz . N. Higham'ın Matrislerin İşlevleri Bölüm 6 ). Gelen benim bu kısa notu birinci dereceden yöntemlerine bu yöntemi karşılaştırmak araziler vardır. Ayrıca, çoğu polar matris yinelemesi en iyi şekilde iş görüyor gibi görünse de (ve özvektör hesaplamaları yapmaktan kaçınır), diğer birçok matris-kare-kök yaklaşımına yapılan atıflar sunulmaktadır.

% 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

Kodunuzu optimize edin:

Seçenek 1 - R kodunuzu optimize edin:
a. Şunları yapabilirsiniz apply()Bir işlev do irade hem max(d,0)ve d2[d==0]=0bir döngü içinde.
b. ei$valuesDoğrudan çalışmayı deneyin .

Seçenek 2 - C ++ kullanın:
Tüm işlevi C ++ ile yeniden yazın RcppArmadillo. Yine de R'den arayabilirsiniz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.