Trouver un moyen de simuler des nombres aléatoires pour cette distribution

20

J'essaie d'écrire un programme en R qui simule des nombres pseudo aléatoires à partir d'une distribution avec la fonction de distribution cumulative:

F(x)=1exp(axbp+1xp+1),x0

a,b>0,p(0,1)

J'ai essayé l'échantillonnage par transformée inverse mais l'inverse ne semble pas résoluble analytiquement. Je serais heureux si vous pouviez suggérer une solution à ce problème

Sébastien
la source
1
Pas assez de temps pour une réponse complète, mais vous pouvez vérifier les algorithmes d'échantillonnage d'importance, comme alternative.
chuse
1
ce n'est pas un exercice de manuel, j'ai seulement stipulé la contrainte car c'est une hypothèse raisonnable pour mes données
Sebastian
6
Je suis alors surpris de la normalisation "miraculeuse" de (p+1)1 qui transforme la distribution en une puissance parfaite d'exponentielle, mais des miracles se produisent (avec une faible probabilité).
Xi'an

Réponses:

49

Il existe une solution simple (et si je peux ajouter, élégante) à cet exercice: puisque apparaît comme le produit de deux distributions de survie: la distribution est la distribution de Dans ce cas, est la distribution exponentielle et est la -ième puissance d'une distribution exponentielle .1F(x)

(1F(x))=exp{axbp+1xp+1}=exp{ax}1F1(x)exp{bp+1xp+1}1F2(x)
F
X=min{X1,X2}X1F1,X2F2
F1E(a)F21/(p+1)E(b/(p+1))

Le code R associé est aussi simple que possible

x=pmin(rexp(n,a),rexp(n,b/(p+1))^(1/(p+1))) #simulating an n-sample

et il est nettement plus rapide que les résolutions PDF inverses et acceptation-rejet:

> n=1e6
> system.time(results <- Vectorize(simulate,"prob")(runif(n)))
utilisateur     système      écoulé 
    89.060       0.072      89.124 
> system.time(x <- simuF(n,1,2,3))
utilisateur     système      écoulé 
     1.080       0.020       1.103 
> system.time(x <- pmin(rexp(n,a),rexp(n,b/(p+1))^(1/(p+1))))
utilisateur     système      écoulé 
     0.160       0.000       0.163 

avec un ajustement parfait sans surprise:

entrez la description de l'image ici

Xi'an
la source
5
solution vraiment cool!
Sebastian
14

Vous pouvez toujours résoudre numériquement la transformation inverse.

Ci-dessous, je fais une recherche de bissection très simple. Pour une probabilité d'entrée donnée (j'utilise puisque vous avez déjà un dans votre formule), je commence par et . Ensuite, je double jusqu'à . Enfin, je bissecte itérativement l'intervalle jusqu'à ce que sa longueur soit plus courte que et que son point milieu satisfasse .qqpxL=0xR=1xRF(xR)>q[xL,xR]ϵxMF(xM)q

L'ECDF s'adapte assez bien à votre pour mes choix de et , et c'est assez rapide. Vous pourriez probablement accélérer cela en utilisant une optimisation de type Newton au lieu de la recherche de bissection simple.Fab

aa <- 2
bb <- 1
pp <- 0.1

cdf <- function(x) 1-exp(-aa*x-bb*x^(pp+1)/(pp+1))

simulate <- function(prob,epsilon=1e-5) {
    left <- 0
    right <- 1
    while ( cdf(right) < prob ) right <- 2*right

    while ( right-left>epsilon ) {
        middle <- mean(c(left,right))
        value_middle <- cdf(middle)
        if ( value_middle < prob ) left <- middle else right <- middle
    }

    mean(c(left,right))
}

set.seed(1)
results <- Vectorize(simulate,"prob")(runif(10000))
hist(results)

xx <- seq(0,max(results),by=.01)
plot(ecdf(results))
lines(xx,cdf(xx),col="red")

ECDF

S. Kolassa - Réintégrer Monica
la source
10

Il y a une résolution quelque peu compliquée si directe par acceptation-rejet. Tout d'abord, une différenciation simple montre que le pdf de la distribution est Deuxièmement, puisque nous avons la borne supérieure Troisièmement, considérant le deuxième terme en , prendre le changement de variable , c'est-à-dire . Alors est le jacobien du changement de variable. Si

f(x)=(a+bxp)exp{axbp+1xp+1}
f(x)=aeaxebxp+1/(p+1)1+bxpebxp+1/(p+1)eax1
f(x)g(x)=aeax+bxpebxp+1/(p+1)
gξ=xp+1x=ξ1/(p+1)
dxdξ=1p+1ξ1p+11=1p+1ξpp+1
Xa une densité de la forme où est la constante de normalisation, alors a la densité ce qui signifie que (i) est distribué comme une variable exponentielle et (ii) la constante est égale à un. Par conséquent, finit par être égal au mélange également pondéré d'une distribution exponentielle et de la puissance -ième d'une puissance exponentielleκbxpebxp+1/(p+1)κΞ=X1/(p+1)
κbξpp+1ebξ/(p+1)1p+1ξpp+1=κbp+1ebξ/(p+1)
ΞE(b/(p+1))κg(x)E(a)1/(p+1)E(b/(p+1))distribution, modulo une constante multiplicative manquante de pour tenir compte des poids: Et est simple à simuler comme un mélange.2
f(x)g(x)=2(12aeax+12bxpebxp+1/(p+1))
g

Un rendu R de l'algorithme d'acceptation-rejet est donc

simuF <- function(a,b,p){
  reepeat=TRUE
  while (reepeat){
   if (runif(1)<.5) x=rexp(1,a) else
      x=rexp(1,b/(p+1))^(1/(p+1))
   reepeat=(runif(1)>(a+b*x^p)*exp(-a*x-b*x^(p+1)/(p+1))/
      (a*exp(-a*x)+b*x^p*exp(-b*x^(p+1)/(p+1))))}
  return(x)}

et pour un n-échantillon:

simuF <- function(n,a,b,p){
  sampl=NULL
  while (length(sampl)<n){
   x=u=sample(0:1,n,rep=TRUE)
   x[u==0]=rexp(sum(u==0),b/(p+1))^(1/(p+1))
   x[u==1]=rexp(sum(u==1),a)
   sampl=c(sampl,x[runif(n)<(a+b*x^p)*exp(-a*x-b*x^(p+1)/(p+1))/
      (a*exp(-a*x)+b*x^p*exp(-b*x^(p+1)/(p+1)))])
   }
  return(sampl[1:n])}

Voici une illustration pour a = 1, b = 2, p = 3:

entrez la description de l'image ici

Xi'an
la source