Pregunta Número aleatorio dentro de un rango basado en una distribución normal


Quiero generar números aleatorios con un rango (n a m, por ejemplo, de 100 a 150), pero en lugar de ser puramente aleatorios, quiero que los resultados se basen en la distribución normal.

Con esto quiero decir que en general quiero los números "agrupados" alrededor de 125.

Encontré este paquete de números aleatorios que parece tener mucho de lo que necesito: http://codeproject.com/KB/recipes/Random.aspx

Es compatible con una variedad de generadores aleatorios (incluido mersiene twister) y puede aplicar el generador a una distribución.

Pero estoy confundido, si uso un generador de distribución normal los números aleatorios son de aproximadamente -6 a +8 (aparentemente el verdadero rango es float.min a float.max).

¿Cómo hacer una escala de mi rango requerido?


32
2018-05-01 23:37


origen


Respuestas:


Una distribución normal estándar tiene una media de 0 y una desviación estándar de 1; si quieres hacer una distribución con media m y desviación s, simplemente multiplique por s y luego agregar m. Dado que la distribución normal es teóricamente infinita, no puede tener un límite máximo en su rango, p. (100 a 150) sin rechazar explícitamente los números que caen fuera de él, pero con una opción de desviación apropiada puede estar seguro de que (por ejemplo) el 99% de sus números estarán dentro del rango.

Aproximadamente el 99.7% de una población está dentro de las +/- 3 desviaciones estándar, por lo que si eliges el tuyo será sobre (25/3), debería funcionar bien.

Entonces quieres algo como: (normal * 8.333) + 125


26
2018-05-01 23:43



En aras del interés, es bastante sencillo generar números aleatorios distribuidos normalmente a partir de un RNG uniforme (aunque debe hacerse en pares):

Random rng = new Random();
double r = Math.Sqrt(-2 * Math.Log(rng.NextDouble()));
double θ = 2 * Math.Pi * rng.NextDouble();
double x = r * Math.Cos(θ);
double y = r * Math.Sin(θ);

x y y ahora contiene dos números aleatorios distribuidos normalmente independientes con media 0 y varianza 1. Puede escalar y traducirlos según sea necesario para obtener el rango que desea (como explica interjay).


Explicación:

Este método se llama Transformada Box-Muller. Utiliza la propiedad de la unidad bidimensional gaussiana que el valor de densidad en sí mismo, p = exp(-r^2/2), se distribuye uniformemente entre 0 y 1 (constante de normalización eliminada por simplicidad).

Como puedes generar ese valor fácilmente usando un RNG uniforme, terminas con un contorno circular de radio r = sqrt(-2 * log(p)). A continuación, puede generar una segunda variante aleatoria uniforme entre 0 y 2*pi para darte un ángulo θ que define un punto único en su contorno circular. Finalmente, puedes generar dos i.i.d. Variables aleatorias normales mediante la transformación de coordenadas polares (r, θ) volver a las coordenadas cartesianas (x, y).

Esta propiedad - eso p está distribuido uniformemente - no es válido para otras dimensionalidades, por lo que debes generar exactamente dos variables normales a la vez.


14
2018-05-02 00:00



La respuesta de tzaman es correcta, pero cuando utilizas la biblioteca que has vinculado hay una manera más simple que realizar el cálculo tú mismo: NormalDistribution objeto tiene propiedades de escritura Mu (es decir, la media) y Sigma(desviación estándar). Entonces, yendo por los números de tzaman, establece Mu a 125 y Sigma a 8.333.


4
2018-05-01 23:55



Esto puede ser demasiado simplista para sus necesidades, pero una forma rápida y económica de obtener un número aleatorio con una distribución que se base en el centro es simplemente agregar 2 (o más) números aleatorios.

Piensa cuando lanzas dos dados de 6 caras y los agregas. La suma suele ser 7, luego 6 y 8, luego 5 y 9, etc. y solo raramente 2 o 12.


2
2018-05-01 23:44



Aquí hay otro algoritmo que no necesita calcular Sin / Cos, ni necesita saber Pi. No me preguntes sobre los antecedentes teóricos. Lo encontré en algún lugar una vez y es lo que he estado usando desde entonces. Sospecho que es una especie de normalización de la misma transformación de Box-Muller que @Will Vousden menciona. También produce resultados en pares.

El ejemplo es VBscript; lo suficientemente fácil de convertir a cualquier otro idioma.

Sub calcRandomGauss (byref y1, byref y2)
    Dim x1, x2, w
    Do
        x1 = 2.0 * Rnd() - 1.0
        x2 = 2.0 * Rnd() - 1.0
        w = x1 * x1 + x2 * x2
    Loop While w >= 1.0 Or w = 0  'edited this line, thanks Richard

    w = Sqr((-2.0 * Log(w)) / w )
    y1 = x1 * w
    y2 = x2 * w
End Sub

0
2017-10-09 09:58



Un enfoque diferente a este problema usa el distribución beta (que tiene un rango difícil, a diferencia de la distribución normal) e implica elegir los parámetros apropiados de manera que la distribución tenga la media y la desviación estándar dadas (raíz cuadrada de la varianza). Ver esta pregunta.


0
2017-07-30 23:41