2012-01-30 20 views
8

Estoy intentando calcular en R una matriz de proyección P de una matriz J N x arbitraria S:Compute matriz de proyección/sombrero a través de factorización QR, SVD (y Cholesky factorización?)

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

he estado tratando de llevar a cabo esto con la siguiente función:

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

Pero cuando se utiliza este recibo errores que se ven así:

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

Creo que esto es un resultado de subdesbordamiento numérico y/o inestabilidad como se discutió en numerosos lugares como r-help y here, pero no tengo suficiente experiencia usando la descomposición SVD o QR para solucionar el problema, o bien coloque este código existente en acción. También he probado el código sugerido, que es escribir a resolver como un sistema:

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

Pero aún así no funciona. Cualquier sugerencia sera apreciada.

Estoy bastante seguro de que mi matriz debe ser invertible y no tiene correlineidades conjuntas, aunque solo sea porque he intentado probar esto con una matriz de variables ficticias ortogonales, y todavía no funciona.

Además, me gustaría aplicar esto a matrices bastante grandes, por lo que estoy buscando una buena solución general.

+1

¿Hay algún motivo por el que no desee utilizar princomp o prcomp? El cálculo de los componentes principales no necesita hacerse a mano. –

+0

Miedo a que no haya una solución general, si ese es el número de condición, tiene un problema. –

+0

Hola, no estoy tratando de hacer PCA tanto como implementar un estimador sobre el que he leído. Me parece extraño que no pueda hacer que esto funcione, incluso para una matriz simple de instrumentos ficticios, cuando parece que eso no es colineal. – bikeclub

Respuesta

-1

¿Qué le parece aplicar chol a S'S, luego chol2inv. Debería ser más estable:

chol2inv(chol(crossprod(S))) 
7

Aunque OP no ha estado activo durante más de un año, todavía decido publicar una respuesta. Me gustaría utilizar en lugar de XS, al igual que en las estadísticas, muchas veces queremos matriz de proyección en el contexto de regresión lineal, donde X es la matriz del modelo, y es el vector de respuesta, mientras que H = X(X'X)^{-1}X' es la matriz sombrero/proyección de manera que Hy da valores predictivos.

Esta respuesta asume el contexto de mínimos cuadrados ordinarios. Para mínimos cuadrados ponderados, vea Get hat matrix from QR decomposition for weighted least square regression.


Una visión general

solve se basa en factorización LU de una matriz cuadrada general. Para X'X (debe calcularse por crossprod(X) en lugar de t(X) %*% X en R, lea ?crossprod para obtener más información) que es simétrico, podemos usar chol2inv que se basa en la factorización de Choleksy.

Sin embargo, la factorización triangular es menos estable que la factorización QR. Esto no es difícil de entender. Si X tiene el número condicional kappa, X'X tendrá el número condicional kappa^2. Esto puede causar una gran dificultad numérica. El mensaje de error que aparece:

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

es solo decir esto.kappa^2 es aproximadamente e-28, mucho más pequeño que la precisión de la máquina en alrededor de e-16. Con la tolerancia tol = .Machine$double.eps, X'X se considerará como rango deficiente, por lo que las factorías LU y Cholesky se descompondrán.

Generalmente, cambiamos a SVD o QR en esta situación, pero pivotó La factorización de Cholesky es otra opción.

  • SVD es el método más estable, pero demasiado caro;
  • QR es satisfactoriamente estable, a costos computacionales moderados, y se usa comúnmente en la práctica;
  • Pivoted Cholesky es rápido, con una estabilidad aceptable. Para una matriz grande, esta es la preferida.

A continuación, explicaré los tres métodos.


Uso de factorización QR

QR factorization

Tenga en cuenta que la matriz de proyección es de permutación independiente, es decir, no importa si realizamos factorización QR con o sin pivotar.

En R, qr.default puede llamar a la rutina LINPACK DQRDC para la factorización QR no pivotada, y la rutina LAPACK DGEQP3 para la factorización QR pivotante de bloque. Vamos a generar una matriz de juguete y probar las dos opciones:

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" 

Nota del $pivot es diferente para los dos objetos.

Ahora, se define una función de contenedor para calcular QQ':

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

veremos que qr_linpack y qr_lapack dan la misma matriz de proyección:

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

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

El uso de la descomposición en valores singulares

SVD

En R, svd calcula la descomposición en valores singulares. Todavía usamos el ejemplo de matriz anterior 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 

Una vez más, se obtiene la misma matriz de proyección.


Usando Pivotado factorización de Cholesky

Pivoted Cholesky factorization

Para la demostración, todavía usamos el ejemplo anterior X.

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

De nuevo, obtenemos la misma matriz de proyección.

+2

Muy explicativo, especialmente teniendo en cuenta varios enfoques. –

Cuestiones relacionadas