it-swarm-es.tech

Convertir una distribución uniforme en 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 media y una desviación estándar de mi elección?

95
Terhorst

El algoritmo Ziggurat es bastante eficiente para esto, aunque la transformada Box-Muller es más fácil de implementar desde cero (y no es una locura lenta).

48
Tyler

Hay un montón de métodos:

  • Hacer no usar 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 en la tabla (y algunos ajustes específicos de la plataforma debido a problemas de tamaño de caché)
  • La relación de uniformes es mi favorita, solo algunas sumas/multiplicaciones y un registro de 1/50 de las veces (p. Ej. mire allí ).
  • Invertir el CDF es eficiente (y pasado por alto, ¿por qué?), Tiene implementaciones rápidas disponibles si busca en Google. Es obligatorio para los números cuasi aleatorios.
40
Alexandre C.

Cambiar la distribución de cualquier función a otra implica el uso de la inversa de la función que desea.

En otras palabras, si apuntas a una función de probabilidad específica p(x) obtienes la distribución al integrarla -> d(x) = integral (p (x)) y usa su inverso: 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)). Debe 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 inversa buena.

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í.

26
Adi

Aquí hay una implementación de javascript utilizando la forma polar de la transformación de 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
user5084

Utilice el teorema del límite central entrada de wikipediaentrada mathworld para su ventaja.

Generar n de los números distribuidos uniformemente, sumarlos, restar n * 0.5 y tiene la salida de una distribución aproximadamente normal con media igual a 0 y varianza igual a (1/12) * (1/sqrt(N)) (vea wikipedia sobre distribuciones uniformes para la última)

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

5
jilles de wit

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 media de 0.0 y desviación estándar. 1.0 para ti.

Una simple adición y/o multiplicación cambiará la media y la desviación estándar de sus necesidades.

1
Pepijn Schmitz

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

  1. Usted termina con dos valores por iteración
    Normalmente, usted almacena 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
    Luego debes escalar el puntaje Z según la desviación estándar y agregar la media para obtener el valor completo en la distribución normal.
1
hughdbrown

El módulo estándar de la biblioteca de Python random 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 mismo, eche un vistazo a la función en random.py en la biblioteca de Python.

La entrada manual está aquí

1
Brent.Longborough

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!

1
Erik Aronesty

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 de software, sé unir dos nombres de generadores aleatorios que le dan una secuencia aleatoria seudo uniforme en [0,1] (Mersenne Twister, Linear Congruate Generator). Llamémoslo U (x)

  2. Existe un área matemática que se llama teoría de la probabilidad. Lo primero: si quieres modelar r.v. con la distribución integral F, entonces puedes intentar evaluar F ^ -1 (U (x)). En la teoría se demostró que tal r.v. Tendrá distribución integral F.

  3. El paso 2 se puede aplicar para generar r.v. ~ F sin el uso de ningún método de conteo cuando F ^ -1 se puede derivar analíticamente sin problemas. (por ejemplo, exp.distribución)

  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 deseo una media y una desviación estándar de mi elección?

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

Se puede mostrar que tal desplazamiento y escalamiento conducen a N (m, sigma)

0
bruziuz

Esta es una implementación de Matlab que usa la forma polar de Box-Muller transformación:

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 invocando histfit(randn_box_muller(10000000),100); este es el resultado:  Box-Muller Matlab Histfit 

Obviamente, es realmente ineficiente en comparación con la función integrada de Matlab randn .

0
madx

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
0
peterweethetbeter

Creo que deberías intentar 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. "0" se puede suministrar 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.

0
Hippo