r -从间隔中有间隙的均匀分布中抽取随机样本

bpsygsoo  于 2023-02-14  发布在  其他
关注(0)|答案(4)|浏览(172)

我对从分布于2个区间的均匀分布中抽取随机样本感兴趣:从-2到-1和从1到2。属于这些区间的任何值都应该具有相等的被采样概率,而其它值(例如从-1到1)应该具有0被采样概率。
runif函数只接受单个数字作为上限和下限的参数,因此,不可能使该函数从两个区间采样。
另一种选择是运行两个runif函数,一个在-2到-1的区间上,另一个在1到2的区间上。但是,在本例中,我明确地使它在每次绘制中从每个区间中绘制的数字数量相等。
我想允许这个变化,虽然平均来说,将有大约相同数量的正数和负数,我仍然需要看到一些随机变化,例如,从正区间抽取更多的数字,反之亦然。

rqqzpn5f

rqqzpn5f1#

编辑:由于我的第一个答案导致了数量完全相等的正值和负值,下面是另一种执行runif 3次的方法:

ifelse(runif(1000)>0.5, runif(1000,-2,-1), runif(1000,1,2))

似乎没有记录,但实验使我:

runif(1000, min=c(-2, 1), max=c(-1, 2))

示例:

hist(runif(1000000, min=c(-2, 1), max=c(-1, 2)))

91zkwejq

91zkwejq2#

因为它是关于0对称的,所以你可以模拟一个随机符号,并将它赋给[1,2]中的一个统一值:

nsims <- 1e6L
random_sign <- 2L * sample.int(2L, size=nsims, replace = TRUE) - 3L
sims <- random_sign * runif(nsims, 1, 2)

hist(sims)
rm5edbpk

rm5edbpk3#

可能会在之后添加差距,如:

n <- 10
x <- runif(n, -2, 0)
i <- x > -1
x[i] <- x[i] + 2

作为功能:

runifGap <- function(n, xMin, xMax, gapMin, gapMax) {
  dGap <- gapMax- gapMin
  x <- runif(n, xMin, xMax - dGap)
  i <- x>gapMin
  x[i] <- x[i] + dGap
  x
}
runifGap(10, -2, 2, -1, 1)

或者,如果存在多个间隙:

runifGaps <- function(n, r) {
  d <- diff(r)
  dj <- d[c(FALSE, TRUE)]
  x <- runif(n, r[1], r[1] + sum(d[c(TRUE, FALSE)]))
  cd <- head(r[c(FALSE, TRUE)], -1)
  for(i in seq_along(cd)) {
    j <- which(x > cd[i])
    x[j] <- x[j] + dj[i]
  }
  x
}
runifGaps(10, c(-2, -1, 1, 2))
runifGaps(10, c(-2, -1, 1, 2, 4, 6)) #for ranges -2:-1, 1:2 and 4:6

基准

n <- 1e7

bench::mark(check = FALSE,
shs = runif_multiinterval(n = n, intervals = tribble(~min, ~max, -2, -1,  1, 2)),
"M.Viking" = ifelse(runif(n)>0.5, runif(n,-2,-1), runif(n,1,2)),
"Stéphane Laurent" = (2L * sample.int(2L, size=n, replace = TRUE) - 3L) * runif(n, 1, 2),
LaurentGKi = sample(c(-1, 1), n, TRUE) * runif(n, 1, 2),
LaurentGKi2 = c(-1L, 1L)[sample.int(2L, n, TRUE)] * runif(n, 1, 2),
GKi = {x <- runif(n, -2, 0); i <- x>-1; `[<-`(x, i, x[i] + 2)}, 
GKi2 = {x <- runif(n, -2, 0); i <- which(x>-1); `[<-`(x, i, x[i] + 2)},
GKi3 = runifGaps(n, c(-2, -1, 1, 2))
)
#  expression            min   median `itr/sec` mem_alloc `gc/sec` n_itr  n_gc
#  <bch:expr>       <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl> <int> <dbl>
#1 shs                 1.12s    1.12s     0.891     305MB     1.78     1     2
#2 M.Viking         519.98ms 519.98ms     1.92      763MB     5.77     1     3
#3 Stéphane Laurent 274.15ms  276.7ms     3.61      114MB     1.81     2     1
#4 LaurentGKi       270.67ms 270.76ms     3.69      191MB     1.85     2     1
#5 LaurentGKi2      263.47ms 266.96ms     3.75      153MB     1.87     2     1
#6 GKi              214.68ms 218.12ms     4.25      343MB     7.08     3     5
#7 GKi2             191.72ms 200.83ms     5.05      286MB     6.73     3     4
#8 GKi3             168.85ms 170.49ms     5.36      210MB     5.36     3     3

在这个例子中,GKi的方法是最快的,而Stéphane Laurent的方法使用的内存最少。

4szc88ey

4szc88ey4#

我编写了一个小函数来概括多个区间的均匀抽样。它使用两阶段抽样。首先,从多项式分布中提取每个区间的单位数,并根据相应的区间宽度进行加权。其次,将runif应用于具有指定区间参数的那些提取。

library(dplyr)
library(purrr)

#' Draw uniformly across multiple intervals.
#' @param n number of output elements
#' @param intervals data frame of intervals. Must have 2 columns: min, max
runif_multiinterval <- \(n, intervals) {
  intervals |>
    mutate(n = rmultinom(1, n, prob = max - min)) |> # 1st stage: draw group sizes
    pmap(runif) |> # 2nd stage: draw within intervals
    unlist() |>
    sample() # randomize order
}

适用于您的案例:

runif_multiinterval(
  n = 1e5,
  intervals = tribble(
    ~min, ~max,
      -2,   -1,
       1,    2
  )) |>
  hist()

适用于多个不同大小的间隔:

runif_multiinterval(
  n = 1e5,
  intervals = tribble(
    ~min, ~max,
      -2,   -1,
       1,    2,
       4,    6
  )) |>
  hist()

创建于2023年2月13日,使用reprex v2.0.2

相关问题