Convertir una distribución uniforme a una distribución normal

¿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?

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 tan lenta).

Hay muchos métodos:

  • No use Box Muller. Especialmente si dibujas muchos números gaussianos. Box Muller produce un resultado que se fija entre -6 y 6 (suponiendo una precisión doble. Las cosas empeoran con los flotadores). Y es realmente menos eficiente que otros métodos disponibles.
  • Ziggurat está bien, pero necesita una búsqueda de tabla (y algunos ajustes específicos de plataforma debido a problemas de tamaño de caché)
  • La relación de uniformes es mi favorita, solo unas pocas adiciones / multiplicaciones y un registro 1/50 de las veces (por ejemplo, mira allí ).
  • Invertir el CDF es eficiente (y se pasa por alto, ¿por qué?), Tiene implementaciones rápidas disponibles si busca en google. Es obligatorio para números cuasialeatorios.

Cambiar la distribución de cualquier función a otra implica usar el inverso de la función que desee.

En otras palabras, si apuntas a una función de probabilidad específica p (x) obtienes la distribución integrando sobre ella -> d (x) = integral (p (x)) y usas su inversa: Inv (d (x)) . Ahora usa la función de probabilidad aleatoria (que tiene una distribución uniforme) y emite el valor del resultado a través de la función Inv (d (x)). Debería obtener valores aleatorios con distribución según 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 inversa o buena.

Espero que esto ayude y gracias por el pequeño comentario sobre el uso de la distribución y no la probabilidad en sí misma.

Aquí hay una implementación de javascript que usa 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 del mundo matemático del teorema del límite central wikipedia para su ventaja.

Genera n de los números distribuidos uniformemente, sumándolos, restar n * 0.5 y tienes la salida de una distribución aproximadamente normal con una media igual a 0 y una varianza igual a (1/12) * (1/sqrt(N)) (ver wikipedia en distribuciones uniformes para ese último)

n = 10 te da algo medio decente rápido. Si desea algo más que medio decente, busque la solución tylers (como se indica en la entrada de wikipedia en distribuciones normales )

Yo usaría Box-Muller. Dos cosas sobre esto:

  1. Terminas con dos valores por iteración
    Normalmente, guarda en caché un valor y devuelve el otro. En la siguiente llamada para una muestra, devuelve el valor almacenado en caché.
  2. Box-Muller da un puntaje Z
    A continuación, debe escalar el puntaje Z por la desviación estándar y agregar la media para obtener el valor completo en la distribución normal.

El módulo de biblioteca de Python estándar 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.

La entrada manual está aquí

Donde R1, R2 son números uniformes al azar:

DISTRIBUCIÓN NORMAL, con SD de 1: sqrt (-2 * log (R1)) * cos (2 * pi * R2)

Esto es exacto … ¡no hay necesidad de hacer todos esos bucles lentos!

Parece increíble que pueda agregar algo a esto después de ocho años, pero para el caso de Java me gustaría señalar a los lectores con 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 usted.

Una simple sum y / o multiplicación cambiará la media y la desviación estándar según sus necesidades.

Creo que deberías probar esto en EXCEL: =norminv(rand();0;1) . Esto producirá los números aleatorios que deberían distribuirse normalmente con la media cero y la varianza unida. “0” se puede suministrar con cualquier valor, de modo que los números serán de 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?

  1. Para la implementación del software, conozco un par de nombres de generador aleatorio que le dan una secuencia aleatoria pseudo uniforme en [0,1] (Mersenne Twister, Linear Congruate Generator). Vamos a llamarlo U (x)

  2. Es un área matemática existente que llamó teoría de la probidad. Lo primero: si desea modelar rv con distribución integral F, puede intentar simplemente evaluar F ^ -1 (U (x)). En pr.theory se demostró que tal rv tendrá una distribución integral F.

  3. El paso 2 puede ser apliable para generar rv ~ F sin utilizar ningún método de conteo cuando F ^ -1 puede obtenerse analíticamente sin problemas. (por ejemplo, exp.distribution)

  4. Para modelar la distribución normal, puede calcular y1 * cos (y2), donde y1 ~ es uniforme en [0,2pi]. y y2 es la distribución de relei.

P: ¿Qué sucede si quiero una desviación estándar y media de mi elección?

Puede calcular sigma * N (0,1) + m.

Se puede demostrar que dicho desplazamiento y escalado 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 a histfit(randn_box_muller(10000000),100); este es el resultado: Box-Muller Matlab Histfit

Obviamente, es realmente ineficiente en comparación con el randn incorporado de Matlab.

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

Aproximación:

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

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