Generar números aleatorios siguiendo una distribución dentro de un intervalo.


17

Necesito generar números aleatorios siguiendo la distribución Normal dentro del intervalo . (Estoy trabajando en R.)(a,b)

Sé que la función rnorm(n,mean,sd)generará números aleatorios siguiendo la distribución normal, pero ¿cómo establecer los límites de intervalo dentro de eso? ¿Hay alguna función R particular disponible para eso?


¿Por qué quieres hacer esto? Si está limitado, entonces no puede ser normal. ¿Qué estás intentando lograr?
gung - Restablecer Monica

x <- rnorm(n, mean, sd); x <- x[x > lower.limit & x < upper.limit]
Hugh

3
@Hugh, eso es genial ... siempre y cuando no te importe cuántos valores aleatorios obtienes.
Glen_b -Reinstate a Monica el

Respuestas:


31

Parece que desea simular a partir de una distribución truncada y, en su ejemplo específico, una normal truncada .

Hay una variedad de métodos para hacerlo, algunos simples, otros relativamente eficientes.

Ilustraré algunos enfoques en su ejemplo normal.

  1. Aquí hay un método muy simple para generar uno a la vez (en algún tipo de pseudocódigo):

    repeat generarXyo partir de N (media, sd)tunortetyol inferiorXyo superior

    ingrese la descripción de la imagen aquí

    Si la mayor parte de la distribución está dentro de los límites, esto es bastante razonable, pero puede ser bastante lento si casi siempre genera fuera de los límites.

    En R, puede evitar el bucle uno a la vez calculando el área dentro de los límites y generar suficientes valores para que pueda estar casi seguro de que después de arrojar los valores fuera de los límites aún tiene tantos valores como sea necesario.

  2. Puede utilizar aceptar-rechazar con alguna función de especialización adecuada durante el intervalo (en algunos casos, el uniforme será lo suficientemente bueno). Si los límites fueran razonablemente estrechos en relación con el SD pero no estuvieras muy lejos de la cola, una mayorización uniforme funcionaría bien con lo normal, por ejemplo.

    ingrese la descripción de la imagen aquí

  3. Si tiene un cdf razonablemente eficiente y un cdf inverso (como pnormy qnormpara la distribución normal en R), puede usar el método cdf inverso descrito en el primer párrafo de la sección de simulación de la página de Wikipedia en la normal truncada . [En efecto, esto es lo mismo que tomar un uniforme truncado (truncado en los cuantiles requeridos, que en realidad no requiere ningún rechazo, ya que es solo otro uniforme) y aplicar el cdf normal inverso a eso. Tenga en cuenta que esto puede fallar si está muy lejos de la cola]

    ingrese la descripción de la imagen aquí

  4. Hay otros enfoques; la misma página de Wikipedia menciona la adaptación del método de zigurat , que debería funcionar para una variedad de distribuciones.

El mismo enlace de Wikipedia menciona dos paquetes específicos (ambos en CRAN) con funciones para generar normales truncadas:

El MSMpaquete en R tiene una función rtnorm, que calcula los sorteos de una normal truncada. El truncnormpaquete en R también tiene funciones para extraer de una normal truncada.


Mirando a su alrededor, mucho de esto está cubierto en respuestas a otras preguntas (pero no exactamente duplicados ya que esta pregunta es más general que solo la normal truncada) ... vea una discusión adicional en

a. Esta respuesta

si. La respuesta de Xi'an aquí , que tiene un enlace a su artículo arXiv (junto con algunas otras respuestas valiosas).


2

El enfoque rápido y sucio es usar la regla 68-95-99.7 .

En una distribución normal, el 99.7% de los valores caen dentro de 3 desviaciones estándar de la media. Entonces, si establece su media en el medio de su valor mínimo y valor máximo deseados, y establece su desviación estándar en 1/3 de su media, obtendrá (en su mayoría) valores que se encuentran dentro del intervalo deseado. Entonces puedes limpiar el resto.

minVal <- 0
maxVal <- 100
mn <- (maxVal - minVal)/2
# Generate numbers (mostly) from min to max
x <- rnorm(count, mean = mn, sd = mn/3)
# Do something about the out-of-bounds generated values
x <- pmax(minVal, x)
x <- pmin(maxVal, x)

Recientemente me enfrenté a este mismo problema, tratando de generar calificaciones aleatorias de los estudiantes para los datos de las pruebas. En el código anterior, he usado pmaxy pminpara reemplazar los valores fuera de los límites con el valor mínimo o máximo de los límites. Esto funciona para mi propósito, porque estoy generando cantidades bastante pequeñas de datos, pero para cantidades más grandes le dará golpes notables en los valores mínimo y máximo. Por lo tanto, dependiendo de sus propósitos, puede ser mejor descartar esos valores, reemplazarlos con NAs o "volver a tirarlos" hasta que estén dentro de los límites.


¿Por qué molestarse en hacer esto? Es tan simple generar números aleatorios normales y descartar aquellos que necesitan truncamiento que no es necesario complicarse, a menos que el truncamiento deseado esté cerca del 100% del área de la densidad.
Carl

2
Quizás estoy malinterpretando la pregunta original. Me encontré con esta pregunta al intentar descubrir cómo lograr una tarea de programación no relacionada directamente con las estadísticas en R, y solo he notado que esta página es un intercambio de pila de estadísticas, no un intercambio de pila de programación. :) En mi caso, quería generar una cantidad específica de enteros aleatorios, con valores que oscilaran entre 0 y 100, y quería que los valores generados cayeran en una bonita curva de campana en ese rango. Desde que escribí esto, me di cuenta de que sample(x=min:max, prob=dnorm(...))tal vez sea una forma más fácil de hacerlo.
Aaron Wells el

@Glen_b Aaron Wells menciona sample(x=min:max, prob=dnorm(...))que parece un poco más corto que tu respuesta.
Carl

Pero tenga en cuenta que el sample() truco solo es útil si está tratando de elegir enteros aleatorios, o algún otro conjunto de valores discretos y predefinidos.
Aaron Wells

1

a<b

ΦX1,...,XNμσ2a<b

Xi=μ+σΦ1(Ui)U1,...,UNIID U[Φ(aμσ),Φ(bμσ)].

No hay una función incorporada para los valores generados a partir de la distribución truncada, pero es trivial programar este método utilizando las funciones ordinarias para generar variables aleatorias. Aquí hay una Rfunción simple rtruncnormque implementa este método en unas pocas líneas de código.

rtruncnorm <- function(N, mean = 0, sd = 1, a = -Inf, b = Inf) {
  if (a > b) stop('Error: Truncation range is empty');
  U <- runif(N, pnorm(a, mean, sd), pnorm(b, mean, sd));
  qnorm(U, mean, sd); }

Esta es una función vectorizada que generará Nvariables aleatorias IID a partir de la distribución normal truncada. Sería fácil programar funciones para otras distribuciones truncadas a través del mismo método. Tampoco sería demasiado difícil programar las funciones asociadas de densidad y cuantil para la distribución truncada.


μσ2

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.