Échantillonner à partir d'une distribution normale mais ignorer toutes les valeurs aléatoires tombant en dehors de la plage spécifiée avant les simulations.
Cette méthode est correcte, mais, comme l'a mentionné @ Xi'an dans sa réponse, cela prendrait beaucoup de temps lorsque la plage est petite (plus précisément, lorsque sa mesure est petite sous la distribution normale).
F−1(U)FU∼Unif(0,1)FG(a,b)G−1(U)U∼Unif(G(a),G(b))
G−1G−1GG−1abG
Simuler une distribution tronquée à l'aide d'un échantillonnage d'importance
N(0,1)GGG(q)=arctan(q)π+12G−1(q)=tan(π(q−12))
U∼Unif(G(a),G(b))G−1(U)tan(U′)U′∼Unif(arctan(a),arctan(b))
a <- 1
b <- 5
nsims <- 10^5
sims <- tan(runif(nsims, atan(a), atan(b)))
xiϕ(x)/g(x)
w ( x ) = exp( - x2/ 2)(1+ x2) ,
log_w <- -sims^2/2 + log1p(sims^2)
w <- exp(log_w) # unnormalized weights
w <- w/sum(w)
( xje, w ( xje) )[ u , v ]
u <- 2; v<- 4
sum(w[sims>u & sims<v])
## [1] 0.1418
Cela fournit une estimation de la fonction cumulative cible. Nous pouvons rapidement l'obtenir et le tracer avec le spatsat
package:
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
( xje)
msample <- rmultinom(1, nsims, w)[,1]
resims <- rep(sims, times=msample)
hist(resims)
mean(resims>u & resims<v)
## [1] 0.1446
Une autre méthode: l'échantillonnage à transformée inverse rapide
Olver et Townsend ont développé une méthode d'échantillonnage pour une large classe de distribution continue. Il est implémenté dans la bibliothèque chebfun2 pour Matlab ainsi que dans la bibliothèque ApproxFun pour Julia . J'ai récemment découvert cette bibliothèque et elle semble très prometteuse (pas seulement pour un échantillonnage aléatoire). Fondamentalement, c'est la méthode d'inversion, mais en utilisant des approximations puissantes du cdf et du cdf inverse. L'entrée est la fonction de densité cible jusqu'à la normalisation.
L'exemple est simplement généré par le code suivant:
using ApproxFun
f = Fun(x -> exp(-x.^2./2), [1,5]);
nsims = 10^5;
x = sample(f,nsims);
[ 2 , 4 ]
sum((x.>2) & (x.<4))/nsims
## 0.14191