2012-01-30 30 views
8

ja próbuje obliczyć w R macierz projekcji P arbitralnej nX J matrycy S:Oblicz macierz projekcji/kapelusz poprzez QR faktoryzacji SVD (i faktoryzacji Choleskiego?)

P = S (S'S)^-1 S' 

mam stara się wykonać to z następujących funkcji:

P <- function(S){ 
    output <- S %*% solve(t(S) %*% S) %*% t(S) 
    return(output) 
} 

Ale kiedy używam tego pojawiają się błędy, które wyglądają tak:

# Error in solve.default(t(S) %*% S, t(S), tol = 1e-07) : 
# system is computationally singular: reciprocal condition number = 2.26005e-28 

Myślę, że jest to wynikiem liczbowego niedomiaru i/lub niestabilności omówionych w wielu miejscach, takich jak r-help i here, ale nie jestem wystarczająco doświadczony przy dekompozycji SVD lub QR, aby rozwiązać problem, lub umieścić ten istniejący kod w akcji. Próbowałem zostały również sugerowany kod, który jest napisanie rozwiązania jako system:

output <- S %*% solve (t(S) %*% S, t(S), tol=1e-7) 

Ale nadal nie działa. Wszelkie sugestie będą mile widziane.

Jestem prawie pewny, że moja macierz powinna być odwracalna i nie ma żadnych współliniowości, choćby dlatego, że próbowałem ją przetestować z macierzą ortogonalnych zmiennych fikcyjnych i nadal nie działa.

Również chciałbym zastosować to do dość dużych matryc, więc szukam schludnego ogólnego rozwiązania.

+1

Czy istnieje powód, dla którego nie chcesz używać polecenia princomp lub prcomp? Obliczanie głównych składników nie musi być wykonywane ręcznie. –

+0

Obawiam się, że nie ma ogólnego rozwiązania, jeśli jest to numer warunku, w którym masz problem. –

+0

Witam, nie próbuję zrobić PCA tak bardzo jak zaimplementować estymator, o którym czytałem. Uważam za dziwne, że nie mogę tego zrobić nawet dla prostej matrycy instrumentów dummy, gdy wydaje się, że to nie jest współliniowość. – bikeclub

Odpowiedz

-1

Jak o zastosowaniu chol do S'S, a następnie chol2inv. Powinien być bardziej stabilny:

chol2inv(chol(crossprod(S))) 
7

Mimo że OP nie był aktywny przez ponad rok, nadal decyduję się na opublikowanie odpowiedzi. Używałbym X zamiast S, ponieważ w statystykach często potrzebujemy matrycy projekcyjnej w kontekście regresji liniowej, gdzie X jest matrycą modelu, y jest wektorem odpowiedzi, podczas gdy H = X(X'X)^{-1}X' jest macierzą kapelusz/rzutowanie, dzięki czemu Hy podaje wartości predykcyjne.

Ta odpowiedź przyjmuje kontekst zwykłych najmniejszych kwadratów. W przypadku ważonych najmniejszych kwadratów patrz Get hat matrix from QR decomposition for weighted least square regression.


Przegląd

solve opiera się na LU faktoryzacji ogólny kwadratowy podłoża. Dla X'X (powinno być obliczone przez crossprod(X) zamiast t(X) %*% X w R, przeczytaj ?crossprod po więcej), co jest symetryczne, możemy użyć chol2inv, który jest oparty na faktoryzacji Choleksy'ego.

Jednak rozkład trójkątny jest mniej stabilny niż faktoryzacja QR. To nie jest trudne do zrozumienia. Jeśli X ma numer warunkowy kappa, X'X będzie mieć numer warunkowy kappa^2. Może to spowodować duże trudności liczbowe. Komunikat o błędzie:

# system is computationally singular: reciprocal condition number = 2.26005e-28 

mówi właśnie to.kappa^2 to około e-28, o wiele mniejsza niż precyzja maszyny około e-16. Z tolerancją tol = .Machine$double.eps, X'X będzie postrzegany jako niedobór rangi, a więc rozkład LU i Cholesky ulegnie rozpadowi.

Zasadniczo w tej sytuacji przełączamy się na SVD lub QR, ale obrócona Cholesky factorization to kolejny wybór.

  • SVD jest najbardziej stabilną metodą, ale za drogie;
  • QR jest satysfakcjonująco stabilny, przy umiarkowanych kosztach obliczeniowych i jest powszechnie stosowany w praktyce;
  • Pivoted Cholesky jest szybka, z akceptowalną stabilnością. W przypadku dużej matrycy jest to preferowane.

Poniżej wyjaśnię wszystkie trzy metody.


Stosując Qr faktoryzacji

QR factorization

Należy zauważyć, że macierz projekcji jest permutacją niezależnie, to znaczy, że nie ma znaczenia, czy wykonać QR faktoryzacji z lub bez obracania.

W języku R, qr.default można wywołać procedurę LINPACK DQRDC dla nieindukowanej faktoryzacji QR i procedurę RAPORTU LAPACK DGEQP3 dla blokowej analizy współczynnika QR. Załóżmy wygenerować macierz zabawki i przetestować obie opcje:

set.seed(0); X <- matrix(rnorm(50), 10, 5) 
qr_linpack <- qr.default(X) 
qr_lapack <- qr.default(X, LAPACK = TRUE) 

str(qr_linpack) 
# List of 4 
# $ qr : num [1:10, 1:5] -3.79 -0.0861 0.3509 0.3357 0.1094 ... 
# $ rank : int 5 
# $ qraux: num [1:5] 1.33 1.37 1.03 1.01 1.15 
# $ pivot: int [1:5] 1 2 3 4 5 
# - attr(*, "class")= chr "qr" 

str(qr_lapack) 
# List of 4 
# $ qr : num [1:10, 1:5] -3.79 -0.0646 0.2632 0.2518 0.0821 ... 
# $ rank : int 5 
# $ qraux: num [1:5] 1.33 1.21 1.56 1.36 1.09 
# $ pivot: int [1:5] 1 5 2 4 3 
# - attr(*, "useLAPACK")= logi TRUE 
# - attr(*, "class")= chr "qr" 

Zanotuj $pivot jest różna dla dwóch obiektów.

Teraz zdefiniowania funkcji opakowania w celu obliczenia QQ':

f <- function (QR) { 
    ## thin Q-factor 
    Q <- qr.qy(QR, diag(1, nrow = nrow(QR$qr), ncol = QR$rank)) 
    ## QQ' 
    tcrossprod(Q) 
    } 

zobaczymy że qr_linpack i qr_lapack dają taką samą matrycę do projekcji

H1 <- f(qr_linpack) 
H2 <- f(qr_lapack) 

mean(abs(H1 - H2)) 
# [1] 9.530571e-17 

za pomocą rozkładu wartości pojedynczą

SVD

W R, svd oblicza dekompozycję wartości osobliwych. My nadal korzystać z powyższego przykładu macierz X:

SVD <- svd(X) 

str(SVD) 
# List of 3 
# $ d: num [1:5] 4.321 3.667 2.158 1.904 0.876 
# $ u: num [1:10, 1:5] -0.4108 -0.0646 -0.2643 -0.1734 0.1007 ... 
# $ v: num [1:5, 1:5] -0.766 0.164 0.176 0.383 -0.457 ... 

H3 <- tcrossprod(SVD$u) 

mean(abs(H1 - H3)) 
# [1] 1.311668e-16 

Znów mamy tę samą macierz projekcji.


Korzystanie obracany Choleskiego faktoryzacji

Pivoted Cholesky factorization

Do demonstracji, my nadal korzystać z przykładu X powyżej.

## pivoted Chol for `X'X`; we want lower triangular factor `L = R'`: 
## we also suppress possible rank-deficient warnings (no harm at all!) 
L <- t(suppressWarnings(chol(crossprod(X), pivot = TRUE))) 

str(L) 
# num [1:5, 1:5] 3.79 0.552 -0.82 -1.179 -0.182 ... 
# - attr(*, "pivot")= int [1:5] 1 5 2 4 3 
# - attr(*, "rank")= int 5 

## compute `Q'` 
r <- attr(L, "rank") 
piv <- attr(L, "pivot") 
Qt <- forwardsolve(L, t(X[, piv]), r) 

## P = QQ' 
H4 <- crossprod(Qt) 

## compare 
mean(abs(H1 - H4)) 
# [1] 6.983997e-17 

Znów otrzymujemy tę samą matrycę projekcji.

+2

Bardzo wyjaśniający, zwłaszcza biorąc pod uwagę różne podejścia. –