Conversion D'une Distribution uniforme en une Distribution normale

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? Et si je veux une moyenne et un écart-type de mon choix?

89
demandé sur Nick 2008-09-16 22:53:01

14 réponses

l'algorithme Ziggurat est assez efficace pour cela, bien que la Box-Muller transform soit plus facile à mettre en œuvre à partir de zéro (et pas follement lent).

46
répondu Tyler 2008-09-16 18:58:45

il y a beaucoup de méthodes:

  • Faire pas utilisation de la Boîte de Muller. Surtout si vous dessinez beaucoup de nombres gaussiens. Box Muller fournit un résultat fixé 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 très bien, mais a besoin d'une recherche de table (et certains ajustements spécifiques à la plate-forme en raison de problèmes de taille de cache)
  • Ratio de l'uniforme est mon préféré, seulement un peu plus/de multiplications et d'un log 1/50e du temps (par exemple. regardez là-bas ).
  • inverser le CDF est efficace (et négligé, pourquoi ?), vous avez implémentations rapides de it disponibles si vous recherchez google. Il est obligatoire pour les nombres Quasi-Aléatoires.
38
répondu Alexandre C. 2010-07-16 13:21:48

changer la distribution d'une fonction à une autre implique d'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)). Maintenant, utilisez la fonction de probabilité aléatoire(qui ont la distribution uniforme) et mouler la valeur de résultat à travers la fonction Inv(D (x)). Vous devriez obtenir des valeurs aléatoires répartition 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 probabilité ou fonction de distribution que vous avez aussi longtemps qu'il a inverse ou bonne approximation inverse.

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

23
répondu Adi 2015-03-07 01:23:21

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 */
}
20
répondu user5084 2016-06-02 12:44:42

utilisez le théorème de limite centrale entrée Wikipédia entrée mathworld à votre avantage.

générer n des nombres uniformément distribués, les additionner, soustraire n*0.5 et vous avez la sortie d'une distribution approximativement normale avec la moyenne égale à 0 et la variance égale à (1/12) * (1/sqrt(N)) (voir wikipedia sur les distributions uniformes pour ce dernier)

n = 10 vous donne quelque chose de rapide à moitié décent. Si vous voulez quelque chose de plus que la moitié décente aller pour la solution de tylers (comme noté dans l'entrée wikipedia sur les distributions normales )

5
répondu jilles de wit 2008-09-17 23:05:09

j'utiliserais Box-Muller. Deux choses à ce sujet:

  1. vous Vous retrouvez avec deux valeurs par itération

    Typiquement, vous cachez une valeur et vous retournez l'autre. Lors de l'appel suivant pour un échantillon, vous retournez la valeur mise en cache.
  2. Box-Muller donne un Z-score

    Vous devez ensuite mettre à l'échelle le score Z par l'écart-type et ajouter la moyenne pour obtenir la pleine valeur dans la distribution normale.
1
répondu hughdbrown 2008-09-16 19:15:02

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

normalvariate (mu, sigma)

Distribution normale. mu est la moyenne, et sigma est l'écart-type.

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

la entrée manuelle est ici

1
répondu Brent.Longborough 2008-09-16 19:17:32

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!

1
répondu Erik Aronesty 2011-10-14 17:51:24

il semble incroyable que je puisse ajouter quelque chose à cela après huit ans, mais pour le cas de Java, je voudrais attirer les lecteurs sur le aléatoire.nextGaussian () méthode, qui génère une distribution gaussienne avec moyenne 0,0 et écart-type 1,0 pour vous.

un simple ajout et/ou multiplication changera la moyenne et l'écart-type à vos besoins.

1
répondu Pepijn Schmitz 2016-04-03 18:06:47

je chose que vous devriez essayer cela dans EXCEL: =norminv(rand();0;1) . Ceci produira les nombres aléatoires qui devraient normalement être distribués avec la moyenne zéro et la variance unite. "0" peut être fourni avec n'importe quelle valeur, de sorte que le nombre sera de dire, et en changeant "1", vous obtiendrez la variance égale au carré de votre entrée.

par exemple: =norminv(rand();50;3) cédera aux nombres normalement distribués avec une moyenne = 50 VARIANCE = 9.

0
répondu Hippo 2012-01-19 20:49:04

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) en une distribution normale?

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

  2. il existe domaine mathématique qui a appelé probabilité à la théorie. 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)). Dans le pr.théorie il a été prouvé qu'un tel R. v. aura une distribution intégrale F.

  3. Step 2 can be appliable to generate R. v. F sans l'utilisation de n'importe quelle méthode de comptage quand F^-1 peut être dérivé analytiquement sans problèmes. (par exemple, exp.distribution)

  4. au modèle normal distribution vous pouvez calculer y1*cos (y2), où y1~est uniforme dans[0,2 pi]. et y2 est la distribution relei.

Q: Que faire si je veux une moyenne et un écart-type de mon choix?

vous pouvez calculer sigma*N(0,1)+M.

on peut montrer qu'un tel déplacement et une telle mise à l'échelle conduisent à N (m, sigma)

0
répondu bruziuz 2015-12-03 01:17:32

il s'agit d'une implémentation Matlab utilisant la forme polaire du Box-Muller transformation:

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 en invoquant histfit(randn_box_muller(10000000),100); c'est le résultat: Box-Muller Matlab Histfit

évidemment, il est vraiment inefficace par rapport à la Matlab intégré randn .

0
répondu madx 2017-12-02 10:43:10
function distRandom(){
  do{
    x=random(DISTRIBUTION_DOMAIN);
  }while(random(DISTRIBUTION_RANGE)>=distributionFunction(x));
  return x;
}
-1
répondu 2008-09-16 22:33:04

Rapprochement:

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

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

-3
répondu Volodymyr M. Lisivka 2012-10-01 13:03:19