Comment échantillonner à partir d'une distribution normale avec moyenne et variance connues en utilisant un langage de programmation conventionnel?

36

Je n'ai jamais suivi de cours de statistiques et j'espère donc poser mes questions au bon endroit ici.

Supposons que je ne dispose que de deux données décrivant une distribution normale: la moyenne et la variance . Je souhaite utiliser un ordinateur pour échantillonner de manière aléatoire cette distribution, de manière à respecter ces deux statistiques.σ 2μσ2

Il est assez évident que je puisse gérer la moyenne en normalisant simplement autour de 0: ajoutez simplement à chaque échantillon avant de le sortir en sortie. Mais je ne vois pas comment générer par programme des échantillons pour respecter .σ 2μσ2

Mon programme sera dans un langage de programmation conventionnel; Je n'ai accès à aucun logiciel statistique.

Fixee
la source
Votre langue a-t-elle un générateur de nombres aléatoires? Ce générateur provient-il uniquement de la distribution uniforme ou peut-il également générer de la distribution normale?
ttnphns
@ttnphns: Presque tous les langages informatiques sont livrés avec un générateur de nombres aléatoires. Ce sont des générateurs extrêmement uniformes sur un domaine fini.
Fixee

Réponses:

33

Si vous pouvez échantillonner à partir d'une distribution donnée avec une moyenne 0 et une variance 1, vous pouvez facilement échantillonner à partir d'une transformation d' échelle-emplacement de cette distribution, qui a une moyenne et une variance . Si est un échantillon d'une distribution moyenne 0 et de variance 1 alors est un échantillon avec la moyenne et la variance . Donc, tout ce que vous avez à faire est d’adapter la variable à l’écart-type (racine carrée de la variance) avant d’ ajouter la moyenne .σ 2 x σ x + μ μ σ 2 σ μμσ2x

σx+μ
μσ2σμ

Comment vous obtenez réellement une simulation à partir d'une distribution normale avec une moyenne de 0 et une variance 1 est une autre histoire. C'est amusant et intéressant de savoir comment implémenter de telles choses, mais que vous utilisiez un logiciel de statistiques ou un langage de programmation ou non, je vous recommanderai d'obtenir et d'utiliser une fonction ou une bibliothèque appropriée pour la génération de nombres aléatoires. Si vous souhaitez des conseils sur la bibliothèque à utiliser, vous pouvez ajouter des informations spécifiques sur le ou les langages de programmation que vous utilisez.

Edit: À la lumière des commentaires, d’autres réponses et du fait que Fixee a accepté cette réponse, je vais donner quelques détails supplémentaires sur la manière dont on peut utiliser les transformations de variables uniformes pour produire des variables normales.

  • Une méthode, déjà mentionnée dans un commentaire de VitalStatistix , est la méthode de Box-Muller qui utilise deux variables aléatoires uniformes indépendantes et produit deux variables aléatoires normales indépendantes. Une méthode similaire qui évite le calcul de deux fonctions transcendantales sin et cos au détriment de quelques simulations supplémentaires a été publiée comme réponse par francogrex .
  • Une méthode tout à fait générale consiste à transformer une variable aléatoire uniforme par la fonction de distribution inverse. Si est uniformément distribué sur alors a une distribution normale standard. Bien qu'il n'y ait pas de formule analytique explicite pour , elle peut être calculée par approximations numériques précises. L'implémentation actuelle dans R (la dernière fois que j'ai vérifié) utilise cette idée. La méthode est très simple d'un point de vue conceptuel, mais nécessite une implémentation précise de , qui n'est probablement pas aussi répandue que les (autres) fonctions transcendantales log , sin et cos .[ 0 , 1 ] Φ - 1 ( U ) Φ - 1 Φ - 1U[0,1]
    Φ1(U)
    Φ1Φ1
  • Plusieurs réponses mentionnent la possibilité d'utiliser le théorème de la limite centrale pour approximer la distribution normale en tant que moyenne de variables aléatoires uniformes. Ce n'est généralement pas recommandé. Les arguments présentés, tels que l'appariement de la moyenne 0 et de la variance 1, et les considérations de soutien de la distribution ne sont pas convaincants. Dans l'exercice 2.3 de "Introduction aux méthodes de Monte Carlo avec R" de Christian P. Robert et George Casella, ce générateur est appelé obsolète et l'approximation est appelée très médiocre .
  • Il y a un nombre ahurissant d'autres idées. Le chapitre 3 et en particulier la section 3.4 de "L'art de la programmation informatique", vol. 2 de Donald E. Knuth est une référence classique sur la génération de nombres aléatoires. Brian Ripley a écrit « Génération informatique de variables aléatoires: un tutoriel» qui peut être utile. Le livre mentionné par Robert et Casella, ou peut-être le chapitre 2 de leur autre livre intitulé "Méthodes statistiques de Monte Carlo", est également recommandé.

À la fin de la journée, une méthode correctement mise en œuvre n'est pas meilleure que le générateur de nombre pseudo aléatoire uniforme utilisé. Personnellement, je préfère faire appel à des bibliothèques spécialisées qui, à mon avis, sont fiables. Je me base presque toujours sur les méthodes implémentées dans R, soit directement dans R, soit via l’API en C / C ++. Évidemment, ce n'est pas une solution pour tout le monde, mais je ne connais pas suffisamment les autres bibliothèques pour recommander des alternatives.

NRH
la source
(+1) Bonne réponse et conseil pour le PO.
cardinal
18
Je ne suis pas sûr de faire ici un commentaire inutile, mais si vous n’avez accès qu’à un générateur de nombres aléatoires uniformes, vous pouvez utiliser la transformation de Box-Muller pour générer des N nombres aléatoires indépendants (0,1). En résumé, si U_1 et U_2 sont indépendants de la distribution Uniform (0,1), alors et sont distribués sous forme de N (0,1) variables aléatoires indépendantes. L'idée de base
2log(U1)cos(2πU2)
2log(U1)sin(2πU2)
VitalStatistix
2
@Vital: Ce n'est pas un commentaire inutile; un bon. La transformation Box-Muller est probablement la plus facile à programmer avec une chance minime de faire quelque chose de mal par inadvertance. Ce n'est pas le plus rapide , mais c'est assez compétitif. Cela dit, l'utilisation d'une bibliothèque de codes établie est probablement encore plus sûre, d'autant plus que l'endroit où l'on risque le plus de faire une erreur est la manière dont les entrées de variables aléatoires uniformes sont générées!
cardinal
@ Vital: Merci, c'est ce que je cherchais. Si vous souhaitez convertir votre commentaire en réponse, je l’enverrai volontiers.
Fixee
1
@VitalStatistix, c'est un bon commentaire, et il semble que c'était ce que recherchait le PO. Pourquoi ne pas en faire une réponse et peut-être élaborer un peu sur l'idée générale d'utiliser des transformations de variables aléatoires uniformes. J’ai hésité à le faire pour la raison que Cardinal a mentionnée principalement parce que je ne sais pas si le générateur d’uniformes par défaut de n’importe quelle langue est un bon générateur.
NRH
10

Ceci est vraiment un commentaire sur la réponse de Michael Lew et celui de Fixee, mais est posté comme réponse car je n'ai pas la réputation sur ce site pour commenter.

[0,1]61

E[i=112Xi]=i=112E[Xi]=12×12=6
var[i=112Xi]=i=112var[Xi]=12×112=1.
i=112Xi610/12i=112Xi6[6,6]6
Dilip Sarwate
la source
5

Outre la réponse de NRH, si vous ne disposez toujours pas des moyens de générer des échantillons aléatoires à partir d'une "distribution normale standard" N (0,1), voici un moyen simple et bon (puisque vous indiquez que vous ne possédez pas de statistiques les fonctions ci-dessous devraient être disponibles dans la plupart des langages de programmation standard).

1. Générez u et v sous forme de deux nombres aléatoires uniformément répartis allant de -1 à 1, par
u = 2 r1 - 1etv = 2 r2 - 1

2.calculer w = u^2 + v^2si w> 1 le retour à 1

3.retournez u * z et y = v * z avec z= sqrt(-2ln(w)/w) Un exemple de code ressemblerait à ceci:

u = 2 * random() - 1;
v = 2 * random() - 1;
w = pow(u, 2) + pow(v, 2);
if (w < 1) {
    z = sqrt((-2 * log(w)) / w);
    x = u * z;
    y = v * z;
    }

utilisez ensuite ce que MHR a suggéré ci-dessus pour obtenir les écarts aléatoires N(mu, sigma^2).

francogrex
la source
Lorsque j'ai posté ma réponse ci-dessus, je n'ai pas remarqué que @vitalStatistix vous avait fourni l'algorithme de transformation de Box-Muller. Celui que je donne ci-dessus est aussi bon, je suppose.
francogrex
2
Pourriez-vous expliquer la raison pour laquelle nous avons généré des variables normales à partir d'une distribution uniforme (autrement que d'un point de vue algorithmique) et ne pas utiliser uniquement le pdf d'une distribution directement gaussienne / normale? Ou est-ce totalement faux?
Arun
4
@Arun Une des raisons: la méthode polaire de la Marsaglia est utile lorsque vous ne disposez que d'un générateur de ressources naturelles qui génère des déviations uniformes.
chl
1
@Arun c'est le moyen le plus simple. Vous pouvez également générer directement à partir du fichier pdf en utilisant, par exemple, la méthode "refus d'acceptation". J'ai posté pour vous un exemple simple sur mon site (car il n'y a pas assez d'espace dans la zone de commentaire ici).
francogrex
4

La distribution normale émerge quand on additionne beaucoup de valeurs aléatoires de distribution similaire (similaires les unes aux autres, je veux dire). Si vous additionnez au moins dix valeurs aléatoires uniformément réparties, la somme est presque normalement distribuée. (Ajoutez plus de dix si vous voulez que ce soit encore plus normal, mais dix suffisent à presque toutes les fins.)

Supposons que vos valeurs aléatoires uniformes soient uniformément réparties entre 0 et 1. La somme sera alors comprise entre 0 et 10. Soustrayez 5 de la somme et la moyenne de la distribution résultante sera 0. Vous divisez maintenant le résultat par l'écart type de la distribution (presque) normale et multipliez le résultat par l'écart type souhaité. Malheureusement, je ne sais pas quel est l'écart-type de la somme de dix écarts aléatoires uniformes, mais si nous avons de la chance, quelqu'un nous le dira dans un commentaire!

Je préfère parler aux étudiants de la distribution normale en ces termes car l'utilité de l'hypothèse d'une distribution normale dans de nombreux systèmes provient entièrement de la propriété que la somme de nombreuses influences aléatoires conduit à une distribution normale.

Michael Lew
la source
Vous utilisez la limite centrale Thm ici (un ensemble de variables aléatoires iid totales en une variable aléatoire normale). Je n'ai pas envisagé cela parce que je pensais que ce serait trop lent, mais vous dites que 10 est suffisant?! C'est mieux que de calculer un journal et un sin / cos et un sqrt!
Fixee
De plus, la moyenne de la va uniforme sur [0,1] est de 0,5 avec la variance 1/12. Si vous additionnez 10, vous obtenez une moyenne de 5 et une variance de 10/12 = 5/6.
Fixee
1
D'un point de vue pédagogique, cette méthode permet une discussion et une démonstration utiles et utiles. Cependant, je déconseillerais fortement à quiconque d'utiliser cette approche dans la pratique.
cardinal
1
logsincos
1
@ Michael: Déclarant donne la distribution « droite » est un peu exagéré, d' autant plus que la distribution de approchante support compact et, dans de nombreuses applications, on fait des soins sur la façon efficace les variables aléatoires peuvent être générés. :) Le fait est qu'il existe plusieurs options bien meilleures disponibles. Mais, je pense toujours que cela fournit quelque chose d’utile pédagogiquement.
cardinal