当我想在特定时间间隔内生成一个runif()
的随机数而不包括特定值(例如0.5)时,我可以编写这个函数ex.runif()
来完成这项工作,但它是数百个比正常runif()
慢的时间。有人能指出我更好的解决方案吗?
ex.runif <- function(n, excl, min, max) {
# ex.runif() excludes the specific value 'excl'
q <- excl
while (q == excl) {
q <- runif(n, min = min, max = max)
}
return(q)
}
set.seed(42)
ex.runif(1, .5, .25, .75) # exclude .5, interval [.25, .75]
# [1] 0.707403
library(microbenchmark)
microbenchmark(ex.runif(1, .5, .25, .75), runif(1, min = .25, max = .75))
# Unit: microseconds
# expr min lq mean median uq max neval cld
# ex.runif 692.439 704.685 721.51135 715.2735 722.9275 962.373 100 b
# runif 2.041 2.551 3.49044 2.8070 3.3170 21.176 100 a
答案 0 :(得分:4)
如果要排除的值集是有限的,那么在大多数情况下,不需要像这样的函数。原因是均匀分布是连续的,并且以概率为零采用任何有限数量的值。也就是说,就概率论而言,q == excl
在概率为零时为真。
例如,
set.seed(42)
ex.runif(5, .5, .25, .75)
# [1] 0.7074030 0.7185377 0.3930698 0.6652238 0.5708728
set.seed(42)
runif(5, 0.25, 0.75)
# [1] 0.7074030 0.7185377 0.3930698 0.6652238 0.5708728
同样最有可能在任何其他种子下发生。因此,您可以继续使用runif
。
@duckmayr对数字精度提出了一个很好的观点。事实上,随着区间[min, max]
越来越窄,q == excl
变得越来越高,概率越来越高,在某些应用中,它甚至可能变得相关。
但是,如果从理论上讲,您确实只需要排除一个值0.5
,那么执行q == excl
之类的检查甚至会因排除不必要的抽奖而受到伤害。
例如,在我的情况下,.Machine$double.eps
是2.220446e-16。那么当[0.5 - .Machine$double.eps / 4, 0.5 + .Machine$double.eps / 4]
为[min,max]
并且得出错误结论时从[0.5 - 10^(-k), 0.5 + 10^(-k)]
获得平局的概率是2 *(2.220446e-16/4)/(2 * 10 ^( - k) ))或约0.55 * 10 ^(k-16)。