Amostra de uma distribuição Normal, mas ignore todos os valores aleatórios que estão fora do intervalo especificado antes das simulações.
Esse método está correto, mas, como mencionado por @ Xi'an em sua resposta, levaria muito tempo quando o intervalo é pequeno (mais precisamente, quando sua medida é pequena na distribuição normal).
F−1(U)FU∼Unif(0,1)FG(a,b)G−1(U)U∼Unif(G(a),G(b))
G−1G−1GG−1abG
Simule uma distribuição truncada usando amostragem de importância
N(0,1)GGG(q)=arctan(q)π+12G−1(q)=tan(π(q−12)). Therefore, the truncated Cauchy distribution is easy to sample by the inversion method and it is a good choice of the instrumental variable for importance sampling of the truncated normal distribution.
After a bit of simplifications, sampling U∼Unif(G(a),G(b)) and taking G−1(U) is equivalent to take tan(U′) with U′∼Unif(arctan(a),arctan(b)):
a <- 1
b <- 5
nsims <- 10^5
sims <- tan(runif(nsims, atan(a), atan(b)))
Now one has to calculate the weight for each sampled value xi, defined as the ratio ϕ(x)/g(x) of the two densities up to normalization, hence we can take
w(x)=exp(−x2/ 2)(1+ x2) ,
mas poderia ser mais seguro usar os pesos do log:
log_w <- -sims^2/2 + log1p(sims^2)
w <- exp(log_w) # unnormalized weights
w <- w/sum(w)
A amostra ponderada ( xEu, w ( xEu) )) permite estimar a medida de cada intervalo [ u , v ] na distribuição de destino, somando os pesos de cada valor amostrado dentro do intervalo:
u <- 2; v<- 4
sum(w[sims>u & sims<v])
## [1] 0.1418
Isso fornece uma estimativa da função cumulativa de destino. Podemos rapidamente obtê-lo e plotá-lo com o spatsat
pacote:
F <- spatstat::ewcdf(sims,w)
# estimated F:
curve(F(x), from=a-0.1, to=b+0.1)
# true F:
curve((pnorm(x)-pnorm(a))/(pnorm(b)-pnorm(a)), add=TRUE, col="red")
# approximate probability of u<x<v:
F(v)-F(u)
## [1] 0.1418
Claro, a amostra ( xEu)definitivamente não é uma amostra da distribuição de destino, mas da distribuição instrumental de Cauchy, e obtém-se uma amostra da distribuição de destino realizando uma reamostragem ponderada , por exemplo, usando a amostra multinomial:
msample <- rmultinom(1, nsims, w)[,1]
resims <- rep(sims, times=msample)
hist(resims)
mean(resims>u & resims<v)
## [1] 0.1446
Outro método: amostragem por transformação inversa rápida
Olver e Townsend desenvolveram um método de amostragem para uma ampla classe de distribuição contínua. Ele é implementado na biblioteca chebfun2 para Matlab , bem como na biblioteca ApproxFun para Julia . Eu descobri recentemente essa biblioteca e parece muito promissora (não apenas para amostragem aleatória). Basicamente, este é o método de inversão, mas usando aproximações poderosas do cdf e do cdf inverso. A entrada é a função de densidade de destino até a normalização.
A amostra é simplesmente gerada pelo seguinte código:
using ApproxFun
f = Fun(x -> exp(-x.^2./2), [1,5]);
nsims = 10^5;
x = sample(f,nsims);
Como verificado abaixo, ele produz uma medida estimada do intervalo [ 2 , 4 ] próximo ao obtido anteriormente por amostragem por importância:
sum((x.>2) & (x.<4))/nsims
## 0.14191