Gerando amostras aleatórias a partir de uma distribuição customizada

16

Estou tentando gerar amostras aleatórias de um pdf personalizado usando R. Meu pdf é:

fX(x)=32(1-x2),0 0x1

Gerei amostras uniformes e tentei transformá-lo em minha distribuição personalizada. Eu fiz isso encontrando o cdf da minha distribuição ( FX(x) ) e configurando-o para a amostra uniforme ( você ) e resolvendo para x .

FX(x)=Pr[Xx]=0 0x32(1-y2)dy=32(x-x33)

Para gerar uma amostra aleatória com a distribuição acima, obtenha uma amostra uniforme e resolvavocê[0 0,1]x em

32(x-x33)=você

Eu o implementei Re não recebo a distribuição esperada. Alguém pode apontar a falha no meu entendimento?

nsamples <- 1000;
x <- runif(nsamples);

f <- function(x, u) { 
  return(3/2*(x-x^3/3) - u);
}

z <- c();
for (i in 1:nsamples) {
  # find the root within (0,1) 
  r <- uniroot(f, c(0,1), tol = 0.0001, u = x[i])$root;
  z <- c(z, r);
}
Anand
fonte
1
Deve ser um erro de codificação. Como não uso R, não posso dizer exatamente qual é o erro - mas apenas codifiquei sua solução (tomando o cuidado de criar a raiz do meio do polinômio cúbico, que sempre fica entre 0 e 1) e Eu obtenho um bom acordo entre as amostras e a distribuição esperada. Poderia ser um problema com o seu localizador de raiz? O que há de errado com as amostras que você está recebendo?
jpillow
Eu tentei o seu código (que não é muito eficiente, a propósito) e recebo a distribuição esperada.
Aniko
@jpillow e @Aniko Meu erro. Quando eu usei nsamples <- 1e6, foi uma boa partida.
Anand
2
@Anand Uma maneira é observar que , permitindo o cálculo direto de x em termos de u . x=2pecado(arcsin(você)/3)xvocê
whuber
1
@Anand en.wikipedia.org/wiki/…
whuber

Respostas:

11

Parece que você descobriu que seu código funciona, mas a @Aniko apontou que você poderia melhorar sua eficiência. Seu maior ganho de velocidade provavelmente viria da pré-alocação de memória para zque você não a cresça dentro de um loop. Algo como z <- rep(NA, nsamples)deve fazer o truque. Você pode obter um pequeno ganho de velocidade usando vapply()(que especifica o tipo de variável retornado) em vez de um loop explícito (há uma ótima pergunta SO na família de aplicativos).

> nsamples <- 1E5
> x <- runif(nsamples)
> f <- function(x, u) 1.5 * (x - (x^3) / 3) - u
> z <- c()
> 
> # original version
> system.time({
+ for (i in 1:nsamples) {
+   # find the root within (0,1) 
+   r <- uniroot(f, c(0,1), tol = 0.0001, u = x[i])$root
+   z <- c(z, r)
+ }
+ })
   user  system elapsed 
  49.88    0.00   50.54 
> 
> # original version with pre-allocation
> z.pre <- rep(NA, nsamples)
> system.time({
+ for (i in 1:nsamples) {
+   # find the root within (0,1) 
+   z.pre[i] <- uniroot(f, c(0,1), tol = 0.0001, u = x[i])$root
+   }
+ })
   user  system elapsed 
   7.55    0.01    7.78 
> 
> 
> 
> # my version with sapply
> my.uniroot <- function(x) uniroot(f, c(0, 1), tol = 0.0001, u = x)$root
> system.time({
+   r <- vapply(x, my.uniroot, numeric(1))
+ })
   user  system elapsed 
   6.61    0.02    6.74 
> 
> # same results
> head(z)
[1] 0.7803198 0.2860108 0.5153724 0.2479611 0.3451658 0.4682738
> head(z.pre)
[1] 0.7803198 0.2860108 0.5153724 0.2479611 0.3451658 0.4682738
> head(r)
[1] 0.7803198 0.2860108 0.5153724 0.2479611 0.3451658 0.4682738

E você não precisa do ;final de cada linha (você é um convertido do MATLAB?).

Richard Herron
fonte
Obrigado pela sua resposta detalhada e por apontar vapply. Eu tenho codificado C/C++há muito tempo e essa é a razão da ;aflição!
Anand
1
uniroot107