2009-07-28 13 views
9

Busqué en el sitio pero no encontré exactamente lo que estaba buscando ... Quería generar un número aleatorio discreto de la distribución normal.Necesita ayuda para generar números aleatorios discretos de la distribución

Por ejemplo, si tengo una gama desde un mínimo de 4 y un máximo de 10 y un promedio de 7. ¿Qué código o llamada de función (C Objetivo preferido) necesitaría para devolver un número en ese rango. Naturalmente, debido a la distribución normal, más números devueltos se centrarían alrededor del promedio de 7.

Como un segundo ejemplo, ¿la curva/distribución de la campana puede estar sesgada hacia un extremo del otro? Digamos que necesito generar un número aleatorio con un rango mínimo de 4 y máximo de 10, y quiero que la mayoría de los números vuelvan a centrarse alrededor del número 8 con una caída natural basada en una curva de campana sesgada.

Cualquier ayuda es muy apreciada ....

Anthony

+2

La distribución normal no tiene puntos finales: tiene soporte infinito. –

+0

Necesita un rango entero donde un solo "tiro" de dos dados tiene una parte superior e inferior. No importa si una tirada individual no tiene colas. La distribución de muchos "tiros" lo hará. – Nosredna

+0

es bastante difícil responder a su pregunta a menos que pueda definir con mayor precisión qué es lo que desea. "basado en una curva de campana sesgada" = ??? –

Respuesta

1

La distribución normal no se describe por sus puntos finales. Normalmente se describe por su media (que ha dado a ser 7) y su desviación estándar. Una característica importante de esto es que es posible obtener un valor muy por fuera del rango esperado de esta distribución, aunque eso será extremadamente raro, cuanto más lejos se obtenga de la media.

Los medios habituales para la obtención de un valor de una distribución es generar un valor aleatorio de una distribución uniforme, que es bastante fácilmente con, por ejemplo, rand(), y luego usar eso como un argumento a una cumulative distribution function, que mapea probabilidades a los límites superiores. Para la distribución estándar, esta función es

F(x) = 0.5 - 0.5*erf((x-μ)/(σ * sqrt(2.0))) 

donde erf() es el error function que puede describirse por una serie de Taylor:

erf (z) = 2.0/sqrt (2,0) * Σ n = 0 ((-1) n z 2n + 1)/(n! (2n + 1))

Lo dejo como un ejercicio para traducir esto en C.

Si prefiere no participar en el ejercicio, puede considerar usar el Gnu Scientific Library, que entre muchas otras características, tiene una técnica para generar números aleatorios en una de muchas distribuciones comunes, de las cuales la Distribución Gaussiana (sugerencia) es una.

Obviamente, todas estas funciones devuelven valores de punto flotante. Deberá usar alguna estrategia de redondeo para convertir a un valor discreto. Un enfoque útil (pero ingenuo) es simplemente downcast to entero.

+1

En realidad, no necesita escribir una implementación de erf (x) en C, ya que está incluida en C99 en math.h. También usar una serie de Taylor para el cálculo es una pesadilla, ya que solo converge * muy * lentamente. El uso de un enfoque de fracción continua aquí es la solución habitual (consulte Recetas numéricas en C o las diversas bibliotecas matemáticas como Cephes o fdlibm). – Joey

+0

eh-heh. Obtuve toda esta información de google. sobre todo wikipedia. ¡También mencioné que la implementación C debía dejarse como un ejercicio! – SingleNegationElimination

+1

Bueno, sería un ejercicio sin sentido ya que el código resultante no tendrá mucho uso. Hay una razón por la que nadie usa una serie de Taylor para calcular erf (x) :-) (tanto en velocidad como en precisión) – Joey

1

Muchos marcos y bibliotecas tienen esto incorporado.

También, al igual TokenMacGuy dicho una distribución normal no se caracteriza por el intervalo dese define en, sino más bien por dos parámetros: media μ y desviación estándar σ . Con estos dos parámetros puede confinar un cierto quantile de la distribución a un cierto intervalo, de modo que el 95% de todos los puntos caen en ese intervalo.Pero restringirlo completamente a cualquier intervalo que no sea (-∞, ∞) es imposible.

Existen varios métodos para generar valores normales distribuido de valores aleatorios uniformes (que es lo que los generadores de números más aleatoria o pseudoaleatoria están generando:

  • El Box-Muller transform es probablemente el más fácil, aunque no exactamente rápido para calcular . Dependiendo de la cantidad de números que necesita, debería ser suficiente, sin embargo y sin duda es muy fácil de escribir.

  • Otra opción es de Polar method Marsaglia que es generalmente más rápido .

  • Un tercer método es el Ziggurat algorithm que es considerablemente más rápido de calcular pero mucho más complejo de programar. En las aplicaciones que realmente usan mucho de números aleatorios, puede ser la mejor opción.

Como consejo general, sin embargo: No escriba usted mismo si tiene acceso a una biblioteca que genera normal distribuidos números al azar para usted ya.


Para sesgar la distribución acabo haría uso de una distribución normal regular, eligiendo μ y σ apropiadamente para un lado de la curva y luego determinar en qué lado de su querido decir un punto cayó, estirándolo apropiadamente para ajustarse a su distribución deseada.


únicamente para generar números enteros le sugeriría a la vuelta hacia el número entero más cercano cuando el número aleatorio pasa a caer dentro de su intervalo deseado y rechazarlo si no lo hace (dibujando un nuevo número aleatorio a continuación). De esta forma, no sesgará artificialmente la distribución (como lo haría si estuviera pinzando los valores a 4 o 10, respectivamente).


En las pruebas con deliberadamente malas generadores de números aleatorios (sí, peor que RANDU) me he dado cuenta de que los resultados del método polares en un bucle sin fin, rechazando todos los muestra. Sin embargo, no sucederá con números aleatorios que cumplan con las expectativas estadísticas habituales para ellos.

4

¿Para qué necesita esto? ¿Puedes hacerlo a la manera del jugador de craps?

Genere dos enteros aleatorios en el rango de 2 a 5 (inclusive, por supuesto) y agréguelos. O voltea una moneda (0,1) seis veces y agrega 4 al resultado.

Summing multiple dice produces a normal distribution (a "bell curve"), while eliminating high or low throws can be used to skew the distribution in various ways.

La clave es que usted va para números discretos (y espero que quiere decir que por números enteros). Múltiples tiradas de dados generan una distribución normal. De hecho, creo que así fue como nos introdujeron por primera vez en la curva de Gauss en la escuela.


Por supuesto, cuanto más tiros, más se aproxima la curva de campana.Al lanzar un solo dado se obtiene una línea plana. Lanzar dos dados solo crea una rampa arriba y abajo que no está muy cerca de una campana. Seis volteos de moneda te acercan.

Así que considere esto ...

Si entiendo bien su pregunta, es suficiente con siete posibles resultados - los números enteros (4,5,6,7,8,9,10). Puede configurar una matriz de siete probabilidades para aproximarse a cualquier distribución que desee.

1

Sí, hay soluciones matemáticas sofisticadas, pero por "simple pero práctico" me gustaría ir con el comentario de Nosredna. Para una sencilla solución de Java:

Random random=new Random(); 
public int bell7() 
{ 
    int n=4; 
    for (int x=0;x<6;++x) 
    n+=random.nextInt(2); 
    return n; 
} 

Si usted no es una persona de Java, Random.nextInt (n) devuelve un número entero aleatorio entre 0 y n-1. Creo que el resto debería ser similar a lo que verías en cualquier lenguaje de programación.

Si el rango era grande, en lugar de nextInt (2) usaría un número mayor allí para que hubiera menos iteraciones a través del ciclo, dependiendo de la frecuencia de llamadas y los requisitos de rendimiento.

1

Dan Dyer y Jay tienen toda la razón. Lo que realmente quieres es una distribución binomial, no una distribución normal. La forma de una distribución binomial se parece mucho a una distribución normal, pero es discreta y limitada, mientras que una distribución normal es continua e ilimitada.

El código de Jay genera una distribución binomial con 6 intentos y un 50% de probabilidad de éxito en cada prueba. Si desea "sesgar" su distribución, simplemente cambie la línea que decide si se agrega 1 a n para que la probabilidad sea diferente al 50%.

Cuestiones relacionadas