2008-09-16 6 views
85

Comment puis-je convertir une distribution uniforme (comme la plupart des générateurs de nombres aléatoires produisent, par exemple entre 0,0 et 1,0), en une distribution normale? Que faire si je veux une déviation moyenne et standard de mon choix?Conversion d'une distribution uniforme en distribution normale

+3

Avez-vous une spécification de langue ou s'agit-il simplement d'une question d'algorithme générale? –

+2

Question d'algorithme général. Je me fiche de quelle langue. Mais je préférerais que la réponse ne repose pas sur des fonctionnalités spécifiques que seul ce langage fournit. – Terhorst

Répondre

44

Le Ziggurat algorithm est assez efficace pour cela, bien que le Box-Muller transform soit plus facile à implémenter à partir de rien (et pas fou lent).

+7

Les avertissements habituels concernant les générateurs congruents linéaires s'appliquent à ces deux méthodes, utilisez donc un générateur de sous-sol décent. À votre santé. – dmckee

+3

Comme Mersenee Twister, ou avez-vous d'autres suggestions? –

1

Je voudrais utiliser Box-Muller. Deux choses à ce sujet:

  1. Vous vous retrouvez avec deux valeurs par itération
    En règle générale, vous mettez en cache une valeur et retourner l'autre. Lors de l'appel suivant pour un exemple, vous renvoyez la valeur mise en cache.
  2. Box-Muller donne un Z-score
    Vous devez ensuite mettre à l'échelle le Z-score par l'écart-type et ajouter la moyenne pour obtenir la valeur complète dans la distribution normale.
+0

Comment redimensionnez-vous le score Z? – Terhorst

+2

mis à l'échelle = mean + stdDev * zScore // vous donne normal (mean, stdDev^2) – yoyoyoyosef

1

Le module bibliothèque standard Python aléatoire a ce que vous voulez:

normalvariate (mu, sigma)
de distribution normale. mu est la moyenne, et sigma est l'écart-type.

Pour l'algorithme lui-même, jetez un oeil à la fonction dans random.py dans la bibliothèque Python.

Le manual entry is here

+1

Malheureusement, la bibliothèque de python utilise Kinderman, A.J. et Monahan, J.F., "Génération informatique de variables aléatoires utilisant le rapport des écarts uniformes", ACM Trans Math Software, 3, (1977), pages 257-260. Cela utilise deux variables aléatoires uniformes pour générer la valeur normale, plutôt qu'une seule, donc il n'est pas évident de savoir comment l'utiliser comme le mappage que l'OP voulait. – Ian

-1
function distRandom(){ 
    do{ 
    x=random(DISTRIBUTION_DOMAIN); 
    }while(random(DISTRIBUTION_RANGE)>=distributionFunction(x)); 
    return x; 
} 
+0

Pas sûr de revenir, cependant, n'est-ce pas? ;-) –

+0

il revient presque sûrement. –

+4

Les nombres aléatoires sont trop importants pour être laissés au hasard. –

23

Modification de la répartition d'une fonction à l'autre consiste à utiliser l'inverse de la fonction que vous voulez. En d'autres termes, si vous visez une fonction de probabilité spécifique p (x) vous obtenez la distribution en l'intégrant -> d (x) = intégrale (p (x)) et utilisez son inverse: Inv (d (X)). Utilisez maintenant la fonction de probabilité aléatoire (qui a une distribution uniforme) et lancez la valeur de résultat à travers la fonction Inv (d (x)). Vous devriez obtenir des valeurs aléatoires avec distribution selon la fonction que vous avez choisie.

C'est l'approche mathématique générique - en l'utilisant, vous pouvez maintenant choisir n'importe quelle fonction de probabilité ou de distribution que vous avez tant qu'elle a une approximation inverse ou une bonne approximation inverse.

Espérons que cela a aidé et merci pour la petite remarque sur l'utilisation de la distribution et non la probabilité elle-même.

+4

+1 Ceci est une méthode négligée pour générer des variables gaussiennes qui fonctionne très bien. La CDF inverse peut être calculée efficacement avec la méthode de Newton dans ce cas (la dérivée est e^{- t^2}), une approximation initiale est facile à obtenir en tant que fraction rationnelle, donc vous avez besoin de 3-4 évaluations de erf et exp. Il est obligatoire si vous utilisez des nombres quasi-aléatoires, un cas où vous devez utiliser exactement un nombre uniforme pour obtenir un nombre gaussien. –

+7

Notez que vous devez inverser la fonction de distribution cumulative, pas la fonction de distribution de probabilité. Alexandre le laisse entendre, mais je pensais que le mentionner plus explicitement pourrait ne pas blesser - puisque la réponse semble suggérer le PDF – ltjax

+0

Vous pouvez utiliser le PDF si vous êtes prêt à sélectionner aléatoirement une direction par rapport à la moyenne; est-ce que je comprends bien? –

4

Utilisez le théorème de la limite centrale wikipedia entrymathworld entry à votre avantage.

Génération n des nombres uniformément distribués, les additionner, soustraire n * 0,5 et vous avez la sortie d'une distribution à peu près normale avec une moyenne égale à 0 et de variance égale à (1/12) * (1/sqrt(N)) (voir wikipedia on uniform distributions pour ce dernier)

n = 10 vous donne quelque chose de rapide moitié décent.Si vous voulez quelque chose de plus de la moitié décent aller pour la solution tylers (comme indiqué dans le wikipedia entry on normal distributions)

+1

Cela ne donnera pas un normal particulièrement proche (les "queues" ou points d'extrémité ne seront pas proches de la distribution normale réelle). Box-Muller est meilleur, comme d'autres l'ont suggéré. –

+1

Box Muller a aussi des failles (il renvoie un nombre compris entre -6 et 6 en double précision) –

+0

n = 12 (somme 12 nombres aléatoires dans la plage 0 à 1, et soustraction 6) donne stddev = 1 et mean = 0 . Cela peut ensuite être utilisé pour générer une distribution normale. Multipliez simplement le résultat par le stddev désiré et ajoutez la moyenne. – JerryM

20

Voici une implémentation javascript utilisant la forme polaire de la transformation Box-Muller.

/* 
* Returns member of set with a given mean and standard deviation 
* mean: mean 
* standard deviation: std_dev 
*/ 
function createMemberInNormalDistribution(mean,std_dev){ 
    return mean + (gaussRandom()*std_dev); 
} 

/* 
* Returns random number in normal distribution centering on 0. 
* ~95% of numbers returned should fall between -2 and 2 
* ie within two standard deviations 
*/ 
function gaussRandom() { 
    var u = 2*Math.random()-1; 
    var v = 2*Math.random()-1; 
    var r = u*u + v*v; 
    /*if outside interval [0,1] start over*/ 
    if(r == 0 || r >= 1) return gaussRandom(); 

    var c = Math.sqrt(-2*Math.log(r)/r); 
    return u*c; 

    /* todo: optimize this algorithm by caching (v*c) 
    * and returning next time gaussRandom() is called. 
    * left out for simplicity */ 
} 
38

Il y a beaucoup de méthodes:

  • Est-ce pas utiliser Box Muller. Surtout si vous dessinez beaucoup de nombres gaussiens. Box Muller donne un résultat qui est serré entre -6 et 6 (en supposant une double précision, les choses empirent avec les flotteurs). Et c'est vraiment moins efficace que les autres méthodes disponibles.
  • Ziggurat est bien, mais nécessite une recherche de table (et quelques ajustements spécifiques à la plate-forme en raison de problèmes de taille de cache)
  • Ratio-des-uniformes est mon préféré, seulement quelques addition/multiplications et un log 1/50e de l'heure (par exemple look there).
  • Inverser le CDF est efficace (et négligé, pourquoi?), Vous avez des implémentations rapides de celui-ci disponible si vous recherchez google. Il est obligatoire pour les nombres quasi-aléatoires.
+1

Êtes-vous sûr du serrage [-6,6]? C'est un point assez significatif si c'est vrai (et digne d'une note sur la page wikipedia). – redcalx

+1

@locster: c'est ce que m'a enseigné un de mes professeurs (il a étudié de tels générateurs, et j'ai confiance en sa parole). Je pourrais être en mesure de vous trouver une référence. –

+7

@locster: cette propriété indésirable est également partagée par la méthode CDF inverse. Voir http://www.cimat.mx/~src/prope08/randomgauss.pdf. Cela peut être atténué en utilisant un RNG uniforme qui a une probabilité non nulle de donner un nombre à virgule flottante très proche de zéro. La plupart des RNG ne le font pas, car ils génèrent un entier (généralement de 64 bits) qui est ensuite mappé à [0,1]. Cela rend ces méthodes inadaptées pour l'échantillonnage des queues de variables gaussiennes (pensez à la tarification des options de faible/haute grève dans la finance computationnelle). –

1

Où R1, R2 sont des nombres uniformes aléatoires:

distribution normale, avec SD de 1: sqrt (-2 * log (R1)) * cos (2 * pi * R2)

C'est exact ... pas besoin de faire toutes ces boucles lentes!

+0

Avant que quelqu'un ne me corrige ... voici l'approximation que j'ai trouvée: (1.5- (R1 + R2 + R3)) * 1.88. J'aime ça aussi. –

0

Je pense que vous devriez essayer ceci dans EXCEL: =norminv(rand();0;1). Cela produira les nombres aléatoires qui devraient être normalement distribués avec la moyenne nulle et la variance unitaire. "0" peut être fourni avec n'importe quelle valeur, de sorte que les nombres seront de la moyenne désirée, et en changeant "1", vous obtiendrez la variance égale au carré de votre entrée.

Par exemple: =norminv(rand();50;3) va céder aux nombres normale de moyenne = 50 ÉCART = 9.

-3

Approximation:

function rnd_snd() { 
    return (Math.random()*2-1)+(Math.random()*2-1)+(Math.random()*2-1); 
} 

Voir http://www.protonfish.com/random.shtml

+0

C'est tout simplement faux. La somme des variables aléatoires uniformes est juste un 1-d [marche aléatoire] (http://en.wikipedia.org/wiki/Random_walk) en utilisant une distribution d'entrée aléatoire uniforme. –

0

Q Comment puis-je convertir une distribution uniforme (comme la plupart des générateurs de nombres aléatoires produisent, par exemple entre 0.0 et 1.0) dans une distribution normale?

  1. Pour la mise en œuvre du logiciel que je connais les noms de générateur de nombres aléatoires ou deux qui vous donnent une séquence pseudo-aléatoire uniforme dans [0,1] (Mersenne Twister, linéaire Congruate Generator). Appelons-le U (x)

  2. Il existe une zone mathématique appelée théorie de la probabilité. Première chose: si vous voulez modéliser r.v. avec la distribution intégrale F alors vous pouvez essayer juste d'évaluer F^-1 (U (x)). En théorie, il a été prouvé que aura la distribution intégrale F.

  3. L'étape 2 peut être utilisée pour générer r.v. ~ F sans utilisation de méthodes de comptage lorsque F^-1 peut être déduite analytiquement sans problèmes. (par exemple exp.distribution)

  4. Pour modéliser la distribution normale, vous pouvez calculer y1 * cos (y2), où y1 ~ est uniforme dans [0,2pi]. et y2 est la distribution relei.

Q: Que faire si je veux une déviation moyenne et standard de mon choix?

Vous pouvez calculer sigma * N (0,1) + m.

On peut montrer que ce déplacement et mise à l'échelle conduisent à N (m, sigma)

1

Il semble incroyable que je pourrais ajouter quelque chose à cela après huit ans, mais pour le cas de Java je voudrais signaler lecteurs à la méthode Random.nextGaussian(), qui génère une distribution gaussienne avec 0,0 et l'écart type 1,0 pour vous.

Une simple addition et/ou multiplication modifiera la moyenne et l'écart type en fonction de vos besoins.

0

Ceci est une implémentation Matlab sous la forme polaire de la transformation Box-Muller:

Fonction randn_box_muller.m:

function [values] = randn_box_muller(n, mean, std_dev) 
    if nargin == 1 
     mean = 0; 
     std_dev = 1; 
    end 

    r = gaussRandomN(n); 
    values = r.*std_dev - mean; 
end 

function [values] = gaussRandomN(n) 
    [u, v, r] = gaussRandomNValid(n); 

    c = sqrt(-2*log(r)./r); 
    values = u.*c; 
end 

function [u, v, r] = gaussRandomNValid(n) 
    r = zeros(n, 1); 
    u = zeros(n, 1); 
    v = zeros(n, 1); 

    filter = r==0 | r>=1; 

    % if outside interval [0,1] start over 
    while n ~= 0 
     u(filter) = 2*rand(n, 1)-1; 
     v(filter) = 2*rand(n, 1)-1; 
     r(filter) = u(filter).*u(filter) + v(filter).*v(filter); 

     filter = r==0 | r>=1; 
     n = size(r(filter),1); 
    end 
end 

Et l'invocation histfit(randn_box_muller(10000000),100); c'est le résultat: Box-Muller Matlab Histfit

De toute évidence, il est vraiment inefficace par rapport à l'intégré Matlab randn.

Questions connexes