La domanda riguarda come generare variate casuali da una distribuzione normale multivariata con una matrice di covarianza (forse) singolare . Questa risposta spiega un modo che funzionerà per qualsiasi matrice di covarianza. Fornisce un'implementazione che ne verifica l'accuratezza.CR
Analisi algebrica della matrice di covarianza
Poiché è una matrice di covarianza, è necessariamente simmetrica e semidefinita positiva. Per completare le informazioni di base, lasciare essere il vettore di mezzi desiderati. μCμ
Poiché è simmetrico, la sua decomposizione del valore singolare (SVD) e la sua composizione eigend avranno automaticamente la formaC
C = VD2V'
per una matrice ortogonale e una matrice diagonale . In generale, gli elementi diagonali di sono non negativi (implicando che tutti hanno reali radici quadrate: scegli quelli positivi per formare la matrice diagonale ). Le informazioni che abbiamo su dicono che uno o più di quegli elementi diagonali sono zero - ma ciò non influirà su nessuna delle operazioni successive, né impedirà il calcolo dell'SVD.D 2 D 2 D CVD2D2DC
Generazione di valori casuali multivariati
Che abbia una distribuzione normale multivariata standard: ogni componente ha media zero, varianza unitaria e tutte le covarianze sono zero: la sua matrice di covarianza è l'identità . Quindi la variabile casuale ha una matrice di covarianzaI Y = V D XXioY= V D X
Cov( Y) = E ( YY') = E ( V D XX'D'V') = V D E ( XX') D V'=VDIDV′=VD2V′=C.
Di conseguenza la variabile casuale ha una distribuzione normale multivariata con media e matrice di covarianza .μ + YμC
Codice di calcolo ed esempio
Il R
codice seguente genera una matrice di covarianza di dimensioni e rango dati, analizza con SVD (o, nel codice commentato, con una composizione di eigend), utilizza tale analisi per generare un numero specificato di realizzazioni di (con vettore medio ) , quindi confronta la matrice di covarianza di tali dati con la matrice di covarianza prevista sia numericamente che graficamente. Come mostrato, genera realizzazioni in cui la dimensione di è e il rango di è . L'output èY010 , 000Y100C50
rank L2
5.000000e+01 8.846689e-05
Cioè, anche il rango dei dati è e la matrice di covarianza, come stimata dai dati, è a distanza di - che è vicina. Come controllo più dettagliato, i coefficienti di sono tracciati rispetto a quelli della sua stima. Sono tutti vicini alla linea di uguaglianza:508 × 10−5CC
Il codice è esattamente parallelo all'analisi precedente e quindi dovrebbe essere autoesplicativo (anche per i non R
utenti, che potrebbero emularlo nel loro ambiente di applicazione preferito). Una cosa che rivela è la necessità di cautela quando si usano algoritmi a virgola mobile: le voci di possono essere facilmente negative (ma minuscole) a causa dell'imprecisione. Tali voci devono essere azzerate prima di calcolare la radice quadrata per trovare stesso.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")