Gere números aleatórios após uma distribuição dentro de um intervalo

17

Preciso gerar números aleatórios seguindo a distribuição Normal dentro do intervalo . (Eu estou trabalhando na R.)(a,b)

Eu sei que a função rnorm(n,mean,sd)irá gerar números aleatórios após a distribuição normal, mas como definir os limites de intervalo dentro disso? Existe alguma função R específica disponível para isso?

dvs
fonte
Por que você quer fazer isso? Se for limitado, não pode ser realmente normal. O que você está tentando alcançar?
gung - Restabelece Monica
x <- rnorm(n, mean, sd); x <- x[x > lower.limit & x < upper.limit]
Hugh
3
@ Hugh, isso é ótimo ... desde que você não se importe com quantos valores aleatórios você obtém.
Glen_b -Reinstala Monica

Respostas:

31

Parece que você deseja simular a partir de uma distribuição truncada e, no seu exemplo específico, uma normal truncada .

Existem vários métodos para fazê-lo, alguns simples, outros relativamente eficientes.

Ilustrarei algumas abordagens no seu exemplo normal.

  1. Aqui está um método muito simples para gerar um de cada vez (em algum tipo de pseudocódigo):

    repeat gerexEu partir de N (média, sd)until inferiorxi upper

    insira a descrição da imagem aqui

    Se a maior parte da distribuição estiver dentro dos limites, isso é bastante razoável, mas pode ficar bem lento se você quase sempre gerar fora dos limites.

    Em R, você pode evitar o loop de uma vez calculando a área dentro dos limites e gerar valores suficientes para ter quase certeza de que, depois de lançar os valores fora dos limites, você ainda terá os valores necessários.

  2. Você pode usar accept-rejeitar com alguma função de atualização adequada durante o intervalo (em alguns casos, uniforme será bom o suficiente). Se os limites fossem razoavelmente estreitos em relação ao sd, mas você não estivesse muito longe, uma majoração uniforme funcionaria bem com o normal, por exemplo.

    insira a descrição da imagem aqui

  3. Se você tem um cdf razoavelmente eficiente e cdf inversa (como pnorme qnormpara a distribuição normal em R), você pode usar o método inverso do CDF descrito no primeiro parágrafo da seção simulação da página da Wikipedia sobre normal truncada . [Na verdade, é o mesmo que pegar um uniforme truncado (truncado nos quantis necessários, o que na verdade não exige nenhuma rejeição, já que isso é apenas mais um uniforme) e aplicar o cdf normal inverso a ele. Observe que isso pode falhar se você estiver muito longe]

    insira a descrição da imagem aqui

  4. Existem outras abordagens; a mesma página da Wikipedia menciona a adaptação do método zigurate , que deve funcionar para uma variedade de distribuições.

O mesmo link da Wikipedia menciona dois pacotes específicos (ambos no CRAN) com funções para gerar normais truncados:

O MSMpacote em R tem uma função rtnorm,, que calcula os desenhos de um normal truncado. O truncnormpacote em R também possui funções para extrair de um normal truncado.


Olhando em volta, muito disso é abordado nas respostas de outras perguntas (mas não exatamente duplicadas, já que essa pergunta é mais geral do que apenas a normal truncada) ... consulte discussão adicional em

uma. Esta resposta

b. A resposta de Xi'an aqui , que tem um link para seu artigo sobre o arXiv (junto com algumas outras respostas que valem a pena).

Glen_b -Reinstate Monica
fonte
2

A abordagem rápida e suja é usar a regra 68-95-99.7 .

Em uma distribuição normal, 99,7% dos valores estão dentro de 3 desvios padrão da média. Portanto, se você definir sua média como o meio do valor mínimo e do valor máximo desejados e definir o desvio padrão para 1/3 da média, obtém (principalmente) valores que se enquadram no intervalo desejado. Então você pode apenas limpar o 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)

Recentemente, enfrentei esse mesmo problema, tentando gerar notas aleatórias dos alunos para os dados dos testes. No código acima, usei pmaxe pminsubstituí valores fora dos limites pelo valor mínimo ou máximo dentro dos limites. Isso funciona para o meu objetivo, porque estou gerando quantidades razoavelmente pequenas de dados, mas para quantidades maiores ele fornecerá saliências visíveis nos valores mínimo e máximo. Portanto, dependendo de seus propósitos, pode ser melhor descartar esses valores, substituí-los por NAs ou "rolá-los novamente" até que estejam dentro dos limites.

Aaron Wells
fonte
Por que se preocupar em fazer isso? É tão simples gerar números aleatórios normais e eliminar aqueles que precisam de truncamento que não é necessário ser complicado a menos que o truncamento desejado seja próximo a 100% da área da densidade.
Carl
2
Talvez eu esteja interpretando mal a pergunta original. Eu me deparei com essa pergunta enquanto tentava descobrir como realizar uma tarefa de programação não diretamente relacionada a estatísticas no R, e só agora notei que esta página é uma troca de pilha de estatísticas, não uma troca de pilha de programação. :) No meu caso, eu queria gerar uma quantidade específica de números inteiros aleatórios, com valores variando de 0 a 100, e queria que os valores gerados caíssem em uma bela curva de sino nesse intervalo. Desde que escrevi isso, percebi que sample(x=min:max, prob=dnorm(...))talvez seja uma maneira mais fácil de fazer isso.
Aaron Wells #
@Glen_b Aaron Wells menciona o sample(x=min:max, prob=dnorm(...))que parece um pouco mais curto que sua resposta.
Carl
Mas observe que o sample()truque só será útil se você estiver tentando escolher números inteiros aleatórios ou algum outro conjunto de valores discretos e predefinidos.
Aaron Wells #
1

uma<b

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

XEu=μ+σΦ-1(vocêEu)você1,...,vocêNIID U[Φ(uma-μσ),Φ(b-μσ)].

Não há função incorporada para valores gerados a partir da distribuição truncada, mas é trivial programar esse método usando as funções comuns para gerar variáveis ​​aleatórias. Aqui está uma Rfunção simples rtruncnormque implementa esse método em algumas linhas 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); }

Essa é uma função vetorizada que irá gerar Nvariáveis ​​aleatórias de IID a partir da distribuição normal truncada. Seria fácil programar funções para outras distribuições truncadas pelo mesmo método. Também não seria muito difícil programar funções associadas de densidade e quantil para a distribuição truncada.


μσ2

Restabelecer Monica
fonte