Comment générer des nombres aléatoires corrélés (étant donné les moyennes, les variances et le degré de corrélation)?

53

Je suis désolé si cela semble un peu trop fondamental, mais je suppose que je cherche simplement à confirmer que nous comprenons. J'ai l'impression que je devrais le faire en deux étapes et j'ai commencé à essayer de grogner des matrices de corrélation, mais cela commence à peine à sembler vraiment impliqué. Je cherche une explication concise (idéalement avec des suggestions pour une solution de pseudocode) d'un bon moyen, idéalement rapide, de générer des nombres aléatoires corrélés.

Étant donné deux variables pseudo-aléatoires taille et poids avec des moyennes et des variances connues et une corrélation donnée, je pense que j'essaie essentiellement de comprendre à quoi cette deuxième étape devrait ressembler:

   height = gaussianPdf(height.mean, height.variance)
   weight = gaussianPdf(correlated_mean(height.mean, correlation_coefficient), 
                        correlated_variance(height.variance, 
                        correlation_coefficient))
  • Comment calculer la moyenne et la variance corrélées? Mais je tiens à confirmer que c'est vraiment le problème pertinent ici.
  • Dois-je recourir à la manipulation matricielle? Ou ai-je quelque chose de très faux dans mon approche de base de ce problème?
Joseph Weissman
la source
1
Je ne suis pas sûr de bien vous comprendre, mais vous n’avez pas à calculer la "moyenne et la variance corrélées". Si vous supposez que les variables sont normales à deux variables, il devrait suffire de spécifier les moyennes et les variances individuelles ainsi que la corrélation. Y a-t-il un logiciel particulier que vous souhaitez utiliser pour cela?
mark999

Réponses:

44

Pour répondre à votre question sur "un bon moyen, idéalement rapide, de générer des nombres aléatoires corrélés": Soit une matrice de variance-covariance souhaitée , définie par définition positive, sa décomposition de Cholesky est la suivante: = ; étant la matrice triangulaire inférieure.C L L T LCCLLTL

Si vous utilisez maintenant cette matrice pour projeter un vecteur de variable aléatoire non corrélé , la projection résultante sera celle de variables aléatoires corrélées.X Y = L XLXY=LX

Vous pouvez trouver une explication concise pourquoi cela se produit ici .

usεr11852 dit Réintégrer Monic
la source
Merci! C'était extrêmement utile. Je pense au moins avoir une meilleure idée de ce que je dois regarder ensuite.
Joseph Weissman
7
Cette méthode s'applique-t-elle uniquement aux distributions gaussiennes (comme spécifié dans la question) ou peut-elle être utilisée pour générer des variables corrélées qui suivent d'autres distributions? Si non, connaissez-vous une méthode qui pourrait être utilisée dans ce cas?
user000001
1
@ Michael: Oui. Ceci dit, étant donné que est une matrice de covariance valide, la décomposition de Cholesky est le moyen le plus rapide. Vous pouvez également obtenir la matrice X (symétrique) de racine carrée de C en utilisant SVD (donc C = X X = X X T , où X = U S 0,5 V T de C = U S V T ), mais cela coûterait plus cher aussi. CXCC=XX=XXTX=US0.5VTC=USVT
usεr11852 dit Rétablir Monic
1
@ Michael: bien sûr. Leur covariance sera (approximativement) la même, pas les nombres eux-mêmes.
usεr11852 dit Rétablir Monic
1
@Sid: Toute distribution continue non supportée sur la totalité de la ligne réelle échouera immédiatement. Par exemple, si nous utilisons un uniforme [ 0 , 1 ], nous ne pouvons pas garantir que les "nombres corrélés" seront dans [ 0 , 1 ] ; de même pour un Poisson nous allons nous retrouver avec des nombres non discrets. En outre, toute distribution dans laquelle la somme des distributions ne correspond pas toujours (par exemple, la somme de la distribution t ne donne pas lieu à des distributions t ) échouera également. Dans tous les cas mentionnés, les nombres produits seront corrélés selon le CU[0,1][0,1]ttCmais ils ne correspondront pas à la distribution que nous avons commencée.
usεr11852 dit Rétablir Monic le
36

+1 à @ user11852 et @ jem77bfp, ce sont de bonnes réponses. Permettez-moi d’aborder la question sous un angle différent, non pas parce que je pense que c’est nécessairement meilleur dans la pratique , mais parce que je pense que c’est instructif. Voici quelques faits pertinents que nous connaissons déjà:

  1. est la pente de la droite de régression lorsque X et Y sont tous deuxnormalisés, c'est-à-dire N ( 0 , 1 ) , rXYN(0,1)
  2. est la proportion de la variance dans Y attribuable à la variance dans X , r2YX



    (aussi, à partir des règles pour les écarts ):

  3. la variance d'une variable aléatoire multipliée par une constante est la constante carré multipliée par la variance initiale:
    Var[aX]=a2Var[X]
  4. variances add , c’est-à-dire que la variance de la somme de deux variables aléatoires (en supposant qu’elles soient indépendantes) est la somme des deux variances:
    Var[X+ε]=Var[X]+Var[ε]

Nous pouvons maintenant combiner ces quatre faits pour créer deux variables normales standard dont les populations auront une corrélation donnée, (plus exactement, ρ ), bien que les échantillons que vous générez auront des corrélations d’échantillon variables. L’idée est de créer une variable pseudo-aléatoire, X , qui est normale normale, N ( 0 , 1 ) , puis de trouver un coefficient, a , et une variance d’erreur, v e , tels que Y N ( 0 , a 2 + v e ) , où unrρXN(0,1)aveYN(0,a2+ve) . (Notez que | a | doit être1 pour que cela fonctionne et que, en outre, a = r .) Ainsi, vous commencez avec le r que vous voulez; c'est votre coefficient, a . Ensuite, vous déterminez la variance d'erreur dont vous aurez besoin, il s'agit de 1 - r 2 . (Si votre logiciel nécessite l'utilisation de l'écart type, prenez la racine carrée de cette valeur.) Enfin, pour chaque variable pseudo-aléatoireque vous avez générée, x i , générez une variable d'erreur pseudo-aléatoire, e ia2+ve=1|a| 1a=rra1r2xiei, avec la variance d'erreur appropriée , et calculez la variable pseudo-aléatoire corrélée, y i , en multipliant et en ajoutant. veyi

Si vous voulez faire cela dans R, le code suivant peut fonctionner pour vous:

correlatedValue = function(x, r){
  r2 = r**2
  ve = 1-r2
  SD = sqrt(ve)
  e  = rnorm(length(x), mean=0, sd=SD)
  y  = r*x + e
  return(y)
}

set.seed(5)
x = rnorm(10000)
y = correlatedValue(x=x, r=.5)

cor(x,y)
[1] 0.4945964

(Edit: j'ai oublié de mentionner :) Comme je l'ai décrit, cette procédure vous donne deux variables corrélées normales standard. Si vous ne voulez pas standards Normales, mais que vous voulez les variables d'avoir des moyens de spécifiques (non 0) et (pas 1 SDs), vous pouvez les transformer sans affecter la corrélation. Ainsi, vous soustrairez la moyenne observée pour vous assurer que la moyenne est exactement égale à , multipliez la variable par le SD que vous voulez et ajoutez ensuite la moyenne de votre choix. Si vous souhaitez que la moyenne observée fluctue normalement autour de la moyenne souhaitée, vous devez rajouter la différence initiale. Il s’agit essentiellement d’une transformation z-score inversée. Puisqu'il s'agit d'une transformation linéaire, la variable transformée aura la même corrélation avec l'autre variable qu'avant. 0

Encore une fois, ceci, dans sa forme la plus simple, ne vous permet que de générer une paire de variables corrélées (cela peut être étendu, mais devient très vite), et ce n’est certainement pas le moyen le plus pratique d’accomplir votre travail. Dans R, vous voudriez utiliser ? Mvrnorm dans le package MASS , à la fois parce que c'est plus facile et parce que vous pouvez générer de nombreuses variables avec une matrice de corrélation de population donnée. Néanmoins, je pense que cela vaut la peine d'avoir parcouru ce processus pour voir comment certains principes de base s'appliquent de manière simple.

gung - Rétablir Monica
la source
Cette approche essentiellement régressive est particulièrement intéressante, permettant de générer un Y aléatoire corrélé à un nombre quelconque de "prédicteurs" X existants . Ai-je raison dans une telle compréhension?
ttnphns
Cela dépend de quel modèle de corrélation entre les variables que vous voulez, @ttnphns. Vous pouvez le parcourir les uns après les autres, mais cela deviendrait fastidieux. Pour créer de nombreuses variables corrélées avec un modèle donné, il est préférable d'utiliser la décomposition de Cholesky.
gung - Rétablir Monica
gung, savez-vous comment utiliser Cholesky pour générer un Y corrélé (approximativement, comme dans votre méthode) en fonction d'un vecteur de corrélations avec plusieurs X existants (non simulés)?
Le
@ttnphns, vous voulez générer un seul Y avec une corrélation de population donnée avec un ensemble de X, et non un ensemble de p variables qui ont toutes des corrélations de population prédéfinies? Une méthode simple consisterait à écrire une équation de régression pour générer un seul chapeau en Y à partir de vos X, puis à utiliser la méthode ci-dessus pour générer Y en tant que corrélat de votre chapeau. Vous pouvez poser une nouvelle question à ce sujet, si vous le souhaitez.
gung - Rétablir Monica
1
Voici ce que je voulais dire dans mon commentaire initial: cette méthode serait une extension directe de ce dont vous parlez dans votre réponse: il s’agit essentiellement d’une méthode de régression (Hat).
Le
16

En général, ce n’est pas une chose simple à faire, mais je pense qu’il existe des packages pour la génération de variables normales multivariées (au moins dans R, voir mvrnorml’ MASSemballage), dans lesquels vous entrez simplement une matrice de covariance et un vecteur moyen.

(X1,X2)F(x1,x2)Fx2

FX1(x1)=F(x1,x2)dx2.
FX11FX1ξ1[0,1]x^1=FX11(ξ)

F(x1,x2)x1=x^1

F(x2|X1=x^1)=F(x^1,x2)fX1(x^1),
fX1X1FX1(x1)=fX1(x1)

ξ2[0,1]ξ1F(x2|X1=x^1)x^2=(F(x2|X1=x^1))1(ξ)x^2F(x^2|X1=x^1)=ξ

Si vous ne comprenez pas le sens de l'insertion d'une variable uniforme dans une fonction de distribution de probabilité inverse, essayez de faire un croquis du cas univarié, puis souvenez-vous de l'interprétation géométrique de la fonction inverse.

jem77bfp
la source
Bonne idée! A simple appel intuitif. Mais oui semble coûteux en calcul.
MichaelChirico
fX,Y(x,y)=fX(x)fY|X(y)
1

Si vous êtes prêt à abandonner votre efficacité, vous pouvez utiliser un alogorithme à jeter. Son avantage est qu'il permet tout type de distribution (pas seulement gaussienne).

{xi}i=1N{yi}i=1NC

cold=corr({xi},{yi})

n1n2:1n1,2N

xn1xn2

cnew=corr({xi},{yi})

|Ccnew|<|Ccold|

|Cc|<ϵ

xi

Bonne chance!

F. Jatpil
la source
xicorr(xi,yi)
xi{xi}ycorr(xi,yi)corr({xi},{yi})=(1/N)Σi=1N(xix¯)(yyy¯)
{}corr({xi},{yi})