¿Cómo puedo convertir una distribución uniforme (como la mayoría de los generadores de números aleatorios producen, por ejemplo, entre 0,0 y 1,0) en una distribución normal? ¿Qué pasa si quiero una desviación estándar y media de mi elección?
¿Cómo puedo convertir una distribución uniforme (como la mayoría de los generadores de números aleatorios producen, por ejemplo, entre 0,0 y 1,0) en una distribución normal? ¿Qué pasa si quiero una desviación estándar y media de mi elección?
Respuestas:
El algoritmo Ziggurat es bastante eficiente para esto, aunque la transformación Box-Muller es más fácil de implementar desde cero (y no muy lento).
Hay muchos métodos:
Cambiar la distribución de cualquier función a otra implica usar la inversa de la función que desea.
En otras palabras, si su objetivo es una función de probabilidad específica p (x), obtiene la distribución integrando sobre ella -> d (x) = integral (p (x)) y usa su inversa: Inv (d (x)) . Ahora use la función de probabilidad aleatoria (que tiene una distribución uniforme) y emita el valor del resultado a través de la función Inv (d (x)). Debería obtener valores aleatorios emitidos con distribución de acuerdo con la función que elija.
Este es el enfoque matemático genérico: al usarlo, ahora puede elegir cualquier función de probabilidad o distribución que tenga siempre que tenga una aproximación inversa o una buena aproximación inversa.
Espero que esto haya ayudado y gracias por el pequeño comentario sobre el uso de la distribución y no la probabilidad en sí.
Aquí hay una implementación de JavaScript que utiliza la forma polar de la transformación 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 */
}
Utilice la entrada mathworld del teorema del límite central de wikipedia para su ventaja.
Genere n de los números distribuidos uniformemente, súmelos, reste n * 0.5 y obtendrá el resultado de una distribución aproximadamente normal con media igual a 0 y varianza igual a (1/12) * (1/sqrt(N))
(consulte wikipedia sobre distribuciones uniformes para la última)
n = 10 te da algo medio decente rápido. Si desea algo más de la mitad decente, opte por la solución de tylers (como se indica en la entrada de wikipedia sobre distribuciones normales )
Usaría Box-Muller. Dos cosas sobre esto:
Donde R1, R2 son números uniformes aleatorios:
DISTRIBUCIÓN NORMAL, con SD de 1: sqrt (-2 * log (R1)) * cos (2 * pi * R2)
Esto es exacto ... ¡no es necesario hacer todos esos bucles lentos!
Parece increíble que pudiera agregar algo a esto después de ocho años, pero para el caso de Java, me gustaría señalar a los lectores el método Random.nextGaussian () , que genera una distribución gaussiana con una media de 0.0 y una desviación estándar de 1.0 para ustedes.
Una simple suma y / o multiplicación cambiará la media y la desviación estándar según sus necesidades.
El módulo de biblioteca estándar de Python al azar tiene lo que desea:
normalvariate (mu, sigma)
Distribución normal. mu es la media y sigma es la desviación estándar.
Para el algoritmo en sí, eche un vistazo a la función en random.py en la biblioteca de Python.
Esta es mi implementación de JavaScript del algoritmo P ( método polar para desviaciones normales ) de la Sección 3.4.1 del libro de Donald Knuth El arte de la programación informática :
function normal_random(mean,stddev)
{
var V1
var V2
var S
do{
var U1 = Math.random() // return uniform distributed in [0,1[
var U2 = Math.random()
V1 = 2*U1-1
V2 = 2*U2-1
S = V1*V1+V2*V2
}while(S >= 1)
if(S===0) return 0
return mean+stddev*(V1*Math.sqrt(-2*Math.log(S)/S))
}
Yo cosa que debe tratar esto en EXCEL: =norminv(rand();0;1)
. Esto producirá los números aleatorios que deberían distribuirse normalmente con la media cero y unir la varianza. Se puede suministrar "0" con cualquier valor, de modo que los números tengan la media deseada, y al cambiar "1", obtendrá la varianza igual al cuadrado de su entrada.
Por ejemplo: =norminv(rand();50;3)
cederá a los números distribuidos normalmente con MEAN = 50 VARIANCE = 9.
P ¿Cómo puedo convertir una distribución uniforme (como la mayoría de los generadores de números aleatorios producen, por ejemplo, entre 0.0 y 1.0) en una distribución normal?
Para la implementación de software, conozco un par de nombres de generadores aleatorios que le dan una secuencia aleatoria pseudo uniforme en [0,1] (Mersenne Twister, Linear Congruate Generator). Llamémoslo U (x)
Existe un área matemática que se llama teoría de la probabilidad. Primero: si desea modelar rv con distribución integral F, puede intentar evaluar F ^ -1 (U (x)). En teoría pr. Se demostró que tal rv tendrá distribución integral F.
El paso 2 puede aplicarse para generar rv ~ F sin el uso de ningún método de conteo cuando F ^ -1 se puede derivar analíticamente sin problemas. (por ejemplo, distribución exp.)
Para modelar la distribución normal, puede calcular y1 * cos (y2), donde y1 ~ es uniforme en [0,2pi]. e y2 es la distribución relevante.
P: ¿Qué pasa si quiero una desviación estándar y media de mi elección?
Puede calcular sigma * N (0,1) + m.
Se puede demostrar que tales cambios y escalas conducen a N (m, sigma)
Esta es una implementación de Matlab que utiliza la forma polar de la transformación Box-Muller :
Función 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
E invocar histfit(randn_box_muller(10000000),100);
este es el resultado:
Obviamente, es realmente ineficiente en comparación con el randn incorporado de Matlab .
Tengo el siguiente código que tal vez podría ayudar:
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)]
También es más fácil usar la función implementada rnorm () ya que es más rápido que escribir un generador de números aleatorios para la distribución normal. Vea el siguiente código como prueba
n <- length(z)
t0 <- Sys.time()
z <- rnorm(n)
t1 <- Sys.time()
t1-t0
function distRandom(){
do{
x=random(DISTRIBUTION_DOMAIN);
}while(random(DISTRIBUTION_RANGE)>=distributionFunction(x));
return x;
}