La question porte sur la façon de générer des variables aléatoires à partir d'une distribution normale multivariée avec une matrice de covariance (éventuellement) singulière . Cette réponse explique une manière qui fonctionnera pour n'importe quelle matrice de covariance. Il fournit une implémentation qui teste sa précision.CR
Analyse algébrique de la matrice de covariance
Parce que est une matrice de covariance, elle est nécessairement symétrique et semi-définie positive. Pour compléter les informations de base, soit μ le vecteur des moyennes souhaitées.Cμ
Parce que est symétrique, sa décomposition en valeurs singulières (SVD) et sa décomposition en eigendecomprendront automatiquement la formeC
C = Vré2V′
pour une matrice orthogonale et une matrice diagonale D 2 . En général, les éléments diagonaux de D 2 sont non négatifs (ce qui implique qu'ils ont tous de vraies racines carrées: choisissez les positifs pour former la matrice diagonale D ). Les informations dont nous disposons à propos de C indiquent qu'un ou plusieurs de ces éléments diagonaux sont nuls - mais cela n'affectera aucune des opérations suivantes et n'empêchera pas le calcul du SVD.Vré2ré2réC
Génération de valeurs aléatoires multivariées
Soit une distribution normale à plusieurs variables standard: chaque composant a une moyenne nulle, la variance unitaire et toutes covariances sont égales à zéro: la matrice de covariance est l'identité I . Alors la variable aléatoire Y = V D X a une matrice de covarianceXjeOui= V D X
Cov( Y) = E ( YOui′) = E ( V D XX′ré′V′) = V D E ( XX′) D V′= V D I D V′= V D2V′= C .
Par conséquent , la variable aléatoire a une distribution normale à plusieurs variables avec une moyenne μ et la matrice de covariance C .μ + YμC
Calcul et exemple de code
Le R
code suivant génère une matrice de covariance de dimensions et de rangs donnés, l'analyse avec le SVD (ou, dans le code commenté, avec une composition par eigendec), utilise cette analyse pour générer un nombre spécifié de réalisations de (avec le vecteur moyen 0 ) , puis compare la matrice de covariance de ces données à la matrice de covariance prévue à la fois numériquement et graphiquement. Comme on le voit, il génère 10 , 000 réalisations où la dimension de Y est de 100 et le rang de C est 50 . La sortie estOui010 , 000Oui100C50
rank L2
5.000000e+01 8.846689e-05
Autrement dit, le rang des données est également de et la matrice de covariance estimée à partir des données est à une distance de 8 × 10 - 5 de C - qui est proche. À titre de vérification plus détaillée, les coefficients de C sont comparés à ceux de son estimation. Ils se situent tous près de la ligne de l'égalité:508 × 10- 5CC
Le code est exactement parallèle à l'analyse précédente et devrait donc être explicite (même pour les non- R
utilisateurs, qui pourraient l'émuler dans leur environnement d'application préféré). Il révèle une nécessité de prudence lors de l'utilisation d'algorithmes à virgule flottante: les entrées de peuvent facilement être négatives (mais minuscules) en raison de l'imprécision. Ces entrées doivent être remises à zéro avant de calculer la racine carrée pour trouver D lui-même.ré2ré
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")