Las preocupaciones de interrogación cómo generar variables aleatorias al azar de una distribución normal multivariante con una (posiblemente) singular matriz de covarianza C . Esta respuesta explica una forma que funcionará para cualquier matriz de covarianza. Proporciona una R
implementación que prueba su precisión.
Análisis algebraico de la matriz de covarianza.
Como C es una matriz de covarianza, es necesariamente simétrica y semidefinida positiva. Para completar la información de fondo, dejemos que μ sea el vector de los medios deseados.
Debido a que es simétrica, su descomposición de valor singular (SVD) y su descomposición propia tendrán automáticamente la formaC
C = Vre2V′
para alguna matriz ortogonal y matriz diagonal D 2 . En general, los elementos diagonales de D 2 no son negativos (lo que implica que todos tienen raíces cuadradas reales: elija los positivos para formar la matriz diagonal D ). La información que tenemos sobre C dice que uno o más de esos elementos diagonales son cero, pero eso no afectará ninguna de las operaciones posteriores ni impedirá que se calcule la SVD.Vre2re2reC
Generando valores aleatorios multivariados
Let tiene una distribución normal multivariante estándar: cada componente tiene media cero, varianza unitaria, y todas las covarianzas son cero: su matriz de covarianza es la identidad I . Entonces la variable aleatoria Y = V D X tiene una matriz de covarianzaXyoY= V D X
Cov( Y) = E ( YY′) = E ( V D XX′re′V′)=VDE(XX′)DV′=VDIDV′=VD2V′=C.
En consecuencia, la variable aleatoria tiene una distribución normal multivariante con media μ y matriz de covarianza C .μ+YμC
Cálculo y código de ejemplo
El siguiente R
código genera una matriz de covarianza de dimensiones y rangos dados, la analiza con la SVD (o, en el código comentado, con una descomposición propia), usa ese análisis para generar un número específico de realizaciones de (con el vector medio 0 ) , y luego compara la matriz de covarianza de esos datos con la matriz de covarianza prevista, tanto numérica como gráficamente. Como se muestra, genera 10 , 000 realizaciones donde la dimensión de Y es 100 y el rango de C es 50 . La salida esY010,000Y100C50
rank L2
5.000000e+01 8.846689e-05
Es decir, el rango de los datos también es y la matriz de covarianza estimada a partir de los datos se encuentra a una distancia de 8 × 10 - 5 de C --que está cerca. Como una verificación más detallada, los coeficientes de C se grafican contra los de su estimación. Todos se encuentran cerca de la línea de igualdad:508×10−5CC
El código es exactamente paralelo al análisis anterior y, por lo tanto, debe explicarse por sí mismo (incluso para los no R
usuarios, que podrían emularlo en su entorno de aplicación favorito). Una cosa que revela es la necesidad de precaución cuando se utilizan algoritmos de punto flotante: las entradas de pueden ser fácilmente negativas (pero pequeñas) debido a la imprecisión. Dichas entradas deben ponerse a cero antes de calcular la raíz cuadrada para encontrar D en sí.D2D
n <- 100 # Dimension
rank <- 50
n.values <- 1e4 # Number of random vectors to generate
set.seed(17)
#
# Create an indefinite covariance matrix.
#
r <- min(rank, n)+1
X <- matrix(rnorm(r*n), r)
C <- cov(X)
#
# Analyze C preparatory to generating random values.
# `zapsmall` removes zeros that, due to floating point imprecision, might
# have been rendered as tiny negative values.
#
s <- svd(C)
V <- s$v
D <- sqrt(zapsmall(diag(s$d)))
# s <- eigen(C)
# V <- s$vectors
# D <- sqrt(zapsmall(diag(s$values)))
#
# Generate random values.
#
X <- (V %*% D) %*% matrix(rnorm(n*n.values), n)
#
# Verify their covariance has the desired rank and is close to `C`.
#
s <- svd(Sigma <- cov(t(X)))
(c(rank=sum(zapsmall(s$d) > 0), L2=sqrt(mean(Sigma - C)^2)))
plot(as.vector(C), as.vector(Sigma), col="#00000040",
xlab="Intended Covariances",
ylab="Estimated Covariances")
abline(c(0,1), col="Gray")