algorithm - resueltos - Convertir una distribución uniforme a una distribución normal
distribucion uniforme excel (14)
¿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?
Aproximación:
function rnd_snd() {
return (Math.random()*2-1)+(Math.random()*2-1)+(Math.random()*2-1);
}
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 */
}
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.
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.
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!
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).
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.
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:
Obviamente, es realmente ineficiente en comparación con el randn incorporado de Matlab.
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.
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 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)
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.
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)
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)
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 suma y / o multiplicación cambiará la media y la desviación estándar según sus necesidades.
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:
- 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é. - 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.
function distRandom(){
do{
x=random(DISTRIBUTION_DOMAIN);
}while(random(DISTRIBUTION_RANGE)>=distributionFunction(x));
return x;
}