Processing math: 100%

23 votos

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

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

Conozco la función rnorm(n,mean,sd) generará números aleatorios siguiendo una distribución normal, pero ¿cómo establecer los límites del intervalo dentro de ella? ¿Hay alguna función de R disponible para ello?

0 votos

¿Por qué quieres hacer esto? Si está acotado, entonces no puede ser realmente normal. ¿Qué quieres conseguir?

2 votos

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

3 votos

@Hugh eso es genial... siempre y cuando no te importe la cantidad de valores aleatorios que obtengas.

34voto

AdamSane Puntos 1825

Parece que quieres simular desde un distribución truncada y en su ejemplo concreto, un normal truncada .

Hay varios métodos para hacerlo, algunos sencillos y otros relativamente eficaces.

Voy a ilustrar algunos enfoques sobre su ejemplo normal.

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

    repeat generar xi de N(media,sd) until baja xi superior

    enter image description here

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

    En R se podría evitar el bucle de uno en uno calculando el área dentro de los límites y generando suficientes valores para estar casi seguro de que después de desechar los valores fuera de los límites todavía se tienen tantos valores como se necesitan.

  2. Se podría utilizar la función aceptar-rechazar con alguna función de mayoración adecuada sobre el intervalo (en algunos casos uniforme será suficiente). Si los límites son razonablemente estrechos en relación con la d.s., pero no está muy lejos de la cola, una mayoración uniforme funcionaría bien con la normal, por ejemplo.

    enter image description here

  3. Si se dispone de una CDF y una CDF inversa razonablemente eficientes (como pnorm y qnorm para la distribución normal en R) se puede utilizar el método de la CDF inversa descrito en el primer párrafo de la sección de simulación de la página de Wikipedia sobre la normal truncada . [En efecto, esto es lo mismo que tomar un uniforme (truncado en los cuantiles requeridos, lo que en realidad no requiere ningún rechazo, ya que se trata de otro uniforme) y aplicarle la fdc normal inversa. Tenga en cuenta que esto puede fallar si usted está muy lejos en la cola]

    enter image description here

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

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

El MSM en R tiene una función, rtnorm que calcula las extracciones de una normal truncada. La página web truncnorm en R también tiene funciones para extraer de una normal truncada.


Mirando alrededor, mucho de esto está cubierto en las respuestas de otras preguntas (pero no exactamente duplicadas ya que esta pregunta es más general que sólo la normal truncada) ... ver discusión adicional en

a. Esta respuesta

b. La respuesta de Xi'an aquí que tiene un enlace a su artículo en arXiv (junto con otras respuestas que merecen la pena).

5voto

Aaron Puntos 36

Ninguna de las respuestas da un método eficiente para generar truncado variables normales que no implique el rechazo de un número arbitrariamente grande de valores generados. Si desea generar valores a partir de una distribución normal truncada, con límites inferiores y superiores especificados a<b esto se puede hacer -sin rechazo- generando cuantiles uniformes sobre el rango de cuantiles permitido por el truncamiento, y utilizando muestreo por transformación inversa para obtener los valores normales correspondientes.

Dejemos que Φ denotan la FDA de la distribución normal estándar. Queremos generar X1,...,XN de una distribución normal truncada (con parámetro de media μ y el parámetro de varianza σ2 ) con límites de truncamiento inferior y superior a<b . Esto puede hacerse de la siguiente manera:

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

No hay ninguna función incorporada para generar valores a partir de la distribución truncada, pero es trivial programar este método utilizando las funciones ordinarias para generar variables aleatorias. A continuación se presenta un sencillo R función rtruncnorm que 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á N Variables aleatorias IID de la distribución normal truncada. Sería fácil programar funciones para otras distribuciones truncadas mediante el mismo método. Tampoco sería demasiado difícil programar funciones de densidad y cuantiles asociadas para la distribución truncada.


Obsérvese que el truncamiento altera la media y la varianza de la distribución, por lo que μ y σ2 son no la media y la varianza de la distribución truncada.

2voto

fyrye Puntos 28

El enfoque rápido y sucio es utilizar el Norma 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. Por lo tanto, si establecemos la media en el centro del valor mínimo y el valor máximo deseados, y establecemos la desviación estándar en 1/3 de la media, obtendremos (en su mayoría) valores que caen dentro del intervalo deseado. Luego, sólo hay que 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 prueba. En el código anterior, he utilizado pmax y pmin para sustituir los valores fuera de los límites por el valor mínimo o máximo dentro 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ínimos y máximos. Así que, dependiendo de sus propósitos, puede ser mejor descartar esos valores y reemplazarlos con NA s, o "volver a rodar" hasta que estén dentro de los límites.

0 votos

¿Por qué molestarse en hacer esto? Es tan sencillo generar números aleatorios normales y descartar los que necesitan ser truncados que no es necesario complicarse con ello, a menos que el truncamiento deseado se acerque al 100% del área de la densidad.

2 votos

Quizá esté interpretando mal la pregunta original. Me encontré con esta pregunta mientras trataba de averiguar cómo lograr una tarea de programación no directamente relacionada con las estadísticas en R, y sólo ahora he notado que esta página es un stackexchange de estadísticas, no un stackexchange de programación. :) En mi caso, quería generar una cantidad específica de enteros aleatorios, con valores que van de 0 a 100, y quería que los valores generados cayeran en una bonita curva de campana a través de ese rango. Desde que escribí esto me di cuenta de que sample(x=min:max, prob=dnorm(...)) es quizás una forma más fácil de hacerlo.

0 votos

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

2voto

technogeek1995 Puntos 121

A mí me han funcionado las tres formas:

  1. utilizando sample() con rnorm():

    sample(x=min:max, replace= TRUE, rnorm(n, mean))

  2. utilizando el paquete msm y la función rtnorm:

    rtnorm(n, mean, lower=min, upper=max)

  3. utilizando la función rnorm() y especificando los límites inferior y superior, como Hugh ha publicado anteriormente:

    sample <- rnorm(n, mean=mean); sample <- sample[x > min & x < max]

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X