简体   繁体   中英

Generating a random sample for a given probability distribution

I have a random variable X with pdf f(x)=4xe^-x , where x>0 .

How do i draw a random sample of size, let's say, 1000 from this distribution?

这是形状= a = 2和比例= 1的伽马分布

q <- rgamma(1000, shape = 2, scale = 1)

One easy solution is rejection sampling (though see my comments on Severin Pappadeux's answer below ). A general rejection sampling algorithm is pretty easy to implement in R (and I would be surprised if it were not implemented in several packages, I just didn't look up which packages would have such functionality):

#' Rejection sampling
#' 
#' @param f A function calculating the density of interest
#' @param g A function giving the proposal density
#' @param rg A function providing random samples from g
#' @param M A numeric vector of length one giving a bound on the the ratio
#'   f(x) / g(x). M must be > 1 and greater than or equal to f(x) / g(x) over
#'   the whole support of X.
#' @param n An integer vector of length one giving the number of samples to
#'   draw; the default is ten thousand.
#' @param ... Further arguments to be passed to g and rg
rejection_sampling <- function(f, g, rg, M, n = 10000, ...) {
    result <- numeric(n)
    for ( i in 1:n ) {
        reject <- TRUE
        while ( reject ) {
            y <- rg(n = 1, ...)
            u <- runif(1)
            if ( u < ( f(y) / (M * g(y, ...)) ) ) {
                result[i] <- y
                reject <- FALSE
            }
        }
    }
    return(result)
}

Then we can use that to get a sample from your distribution, and plot the sample's density along with the true probability density to see how well it worked:

x <- seq(0.01, 15, 0.01)
f <- function(x) 4 * x * exp(-x)
y <- f(x)
set.seed(123)
z <- rejection_sampling(f = f, g = dexp, rg = rexp, M = 10, n = 1e3, rate = 1/4)
dens <- density(z, from = 0.01, to = 15)
scaling_constant <- max(y) / max(dens$y)
plot(x, y, type = "l", xlab = "x", ylab = "f(x)", lty = 2, col = "blue")
lines(dens$x, dens$y * scaling_constant, col = "red", lty = 3)
legend("topright", bty = "n", lty = 2:3, col = c("blue", "red"),
       legend = c("True f(x)", "(Re-scaled) density of sample"))

在此处输入图片说明

Rejection sampling works by taking samples from a proposal distribution and rejecting them if a random uniform deviate is greater than the ratio f(x) / M g(x) , where g(x) is your proposal density, and M is a bound on f(x) / g(x) as briefly described in the Roxygen documentation above.

I used above an exponential proposal distribution with a rate parameter of 1/4. You could use others.

This pdf is proportional to a Gamma distribution with a shape of 2 and scale of 1, as mentioned by Severin Pappadeux's answer . (That is, if you plug those parameters into the Gamma pdf, you'll see it differs from yours only by a scaling constant). Depending on what you're doing this for, that could be a better way to go, or this way. I'm not sure if your objective is to generate samples from arbitrary distributions such as this one as an example, or you need samples from this distribution itself, etc.... Usually it's best to recognize if your arbitrary pdf is actually an example of an implemented distribution, but if you're not in that situation, you need something like rejection sampling.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM