Comment puis-je convertir une distribution uniforme (comme le produisent la plupart des générateurs de nombres aléatoires, par exemple entre 0,0 et 1,0) en une distribution normale? Et si je veux un écart moyen et standard de mon choix?
L'algorithme Ziggurat est assez efficace pour cela, bien que la transformation Box-Muller soit plus facile à implémenter à partir de zéro (et pas trop lente).
Il y a beaucoup de méthodes:
Changer la distribution d'une fonction à une autre implique l'utilisation de l'inverse de la fonction souhaitée.
En d’autres termes, si vous visez une fonction de probabilité spécifique p(x), vous obtenez la distribution en intégrant dessus -> d(x) = intégrale (p (x)) et utilisez son inverse : Inv (d (x)). Maintenant, utilisez la fonction de probabilité aléatoire (qui a une distribution uniforme) et convertissez la valeur du résultat par la fonction Inv (d (x)). Vous devriez obtenir des valeurs aléatoires avec une distribution en fonction de 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 tant qu'elle a une approximation inverse ou bonne.
J'espère que cela vous a aidé et merci pour la petite remarque sur l'utilisation de la distribution et non de la probabilité elle-même.
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 */
}
Utilisez le théorème central limite entrée wikipediaentrée mathworld à votre avantage.
Générez n des nombres uniformément répartis, additionnez-les, soustrayez n * 0.5 et vous obtenez le résultat d’une distribution approximativement normale avec une moyenne égale à 0 et une 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écent, optez pour la solution tylers (comme indiqué dans l'entrée de wikipedia sur les distributions normales )
Il semble incroyable que je puisse ajouter quelque chose à cela après huit ans, mais pour Java, je voudrais indiquer aux lecteurs la méthode Random.nextGaussian () , qui génère une distribution gaussienne avec une moyenne de 0.0 et un écart type 1,0 pour vous.
Une simple addition et/ou multiplication modifiera l'écart moyen et l'écart type en fonction de vos besoins.
Je voudrais utiliser Box-Muller. Deux choses à ce sujet:
Le module de bibliothèque Python standard random a ce que vous voulez:
variable normale (mu, sigma)
Distribution normale. mu est la moyenne et sigma est la déviation standard.
Pour l'algorithme lui-même, jetez un oeil à la fonction random.py dans la bibliothèque Python.
Où R1, R2 sont des nombres uniformes aléatoires:
DISTRIBUTION NORMALE, avec écart type de 1: sqrt (-2 * log (R1)) * cos
C'est exact ... pas besoin de faire toutes ces boucles lentes!
Q Comment puis-je convertir une distribution uniforme (comme le produisent la plupart des générateurs de nombres aléatoires, par exemple entre 0,0 et 1,0) en une distribution normale?
Pour l’implémentation logicielle, je connais quelques noms de générateurs aléatoires qui vous donnent une séquence aléatoire pseudo uniforme dans [0,1] (Mersenne Twister, Générateur de congruence linéaire). Appelons cela U (x)
Il existe un domaine mathématique appelé théorie de la probabilité. Première chose: Si vous voulez modéliser r.v. avec la distribution intégrale F, vous pouvez simplement évaluer F ^ -1 (U (x)). Dans la théorie, il a été prouvé que de telles lois aura une distribution intégrale F.
L'étape 2 peut être applicable pour générer r.v. ~ F sans utiliser de méthodes de comptage lorsque F ^ -1 peut être dérivé analytiquement sans problèmes. (par exemple, exp.distribution)
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: Et si je veux un écart moyen et standard de mon choix?
Vous pouvez calculer sigma * N (0,1) + m.
On peut montrer que ce décalage et cette mise à l'échelle mènent à N (m, sigma)
Ceci est une implémentation de Matlab utilisant la forme polaire de 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);
, voici le résultat:
Évidemment, il est vraiment inefficace par rapport au Matlab intégré randn .
J'ai le code suivant qui pourrait peut-être aider:
set.seed(123)
n <- 1000
u <- runif(n) #creates U
x <- -log(u)
y <- runif(n, max=u*sqrt((2*exp(1))/pi)) #create Y
z <- ifelse (y < dnorm(x)/2, -x, NA)
z <- ifelse ((y > dnorm(x)/2) & (y < dnorm(x)), x, z)
z <- z[!is.na(z)]
Il est également plus facile d’utiliser la fonction implémentée rnorm () car elle est plus rapide que l’écriture d’un générateur de nombres aléatoires pour la distribution normale. Voir le code suivant comme preuve
n <- length(z)
t0 <- Sys.time()
z <- rnorm(n)
t1 <- Sys.time()
t1-t0
Je pense que vous devriez essayer ceci dans Excel: =norminv(Rand();0;1)
. Cela produira les nombres aléatoires qui devraient normalement être distribués avec la moyenne nulle et la variance unifiée. "0" peut être fourni avec n'importe quelle valeur, de sorte que les nombres soient de la moyenne souhaitée, et en modifiant "1", vous obtiendrez la variance égale au carré de votre entrée.
Par exemple: =norminv(Rand();50;3)
donnera les nombres normalement distribués avec MEAN = 50 VARIANCE = 9.