Efficiently removing n random entries from a vector, where n may be 0

Viewed 40

I want to remove n elements chosen randomly from a vector, where n is greater than or equal to 0. n is sampled from a binomial, and small, possibly 0. I want to do this as efficiently as possible, so the code can be run many times. The issue is that using vec[-sample(vec,n)] may give a null vector, if n = 0.

I had a couple of ideas, I was wondering if anyone knows of a nicer or faster way to get around the problem.

  1. Using a minus sign, and an if function before.
# y is a vector of length 10000
n <- rbinom(n = 1, size = 10000, p = 0.0001)
if (length(n) != 0){
   y <- y[-sample((1:10000), size = n)]
}
  1. Selecting all other elements.
# y is a vector of length 10000
n <- rbinom(n = 1, size = 10000, p = 0.0001)
n <- 10000 - n
y <- sample(y, size = n)
1 Answers

Create a boolean vector indicating TRUE or FALSE for whether each column is kept:

p = 0.0001
keep = sample(c(TRUE, FALSE), size = length(y), prob = c(1 - p, p), replace = TRUE)
y[keep]

You can do the same thing with runif, which will might be a tiny bit faster:

y[runif(length(y)) > p]

Actually, turns out sample is faster by about 2x - though since we're measuring microseconds this hardly matters.

n = 10000
p = 0.0001
y = rnorm(n)

microbenchmark::microbenchmark(
  sample = y[sample(c(TRUE, FALSE), size = n, prob = c(1 - p, p), replace = TRUE)],
  runif = y[runif(n) > p]
)
# Unit: microseconds
#    expr   min     lq    mean median     uq     max neval
#  sample 128.9 195.05 463.591  297.9 346.65 15319.9   100
#   runif 349.0 565.80 876.925  674.3 800.55  6990.6   100
Related