Pro*_*ino 3 r function sampling
我想编写一个函数,对n 个彩票进行抽样,每个彩票有6 个号码,从1 到 45,每个号码都没有替换。但是,我需要有效地执行此操作,这意味着没有循环或类似循环的函数。(我想 Rcpp 也可以工作,但我更喜欢基 R 中的矢量化解决方案)
无限制求解:
lottery_inef <- function(n){
t(replicate(n,
sample(1:45, 6)))
}
Run Code Online (Sandbox Code Playgroud)
所以在这里我得到一个矩阵,其中每一行对应一张彩票。现在,如果我想模拟数百万张彩票,这会变得非常慢,因此我对矢量化解决方案感兴趣。
我的想法是:
lottery_ef <- function(n){
m <- matrix(sample(1:45, n*6, replace = TRUE), ncol = 6)
# somehow subset the matrix without a loop to remove all the
# rows that have non-unique values as in the lottery we can only draw each number once
}
Run Code Online (Sandbox Code Playgroud)
对于高效版本,我在没有循环或 apply() 的子集点上有点迷失。如果有人可以解决这个子集问题,或者为我指出一个完全不同的方向,这将引导我找到解决方案,我将不胜感激。
replicate在这个规模上实际上并没有那么好。通过即时编译(现在在 R 中使用了几年),for循环可以更快,尤其是当我们可以精确地预分配数据结构时。我们还可以避免t():
lottery_inef <- function(n){
t(replicate(n,
sample(1:45, 6)))
}
lottery_preall <- function(n){
m = matrix(NA_integer_, nrow = n, ncol = 6)
for(i in 1:n) {
m[i, ] = sample.int(45L, size = 6)
}
m
}
nn = 1e6
microbenchmark::microbenchmark(
lottery_inef(nn),
lottery_preall(nn),
times = 2
)
# Unit: seconds
# expr min lq mean median uq max neval
# lottery_inef(nn) 9.400862 9.400862 9.571756 9.571756 9.742649 9.742649 2
# lottery_preall(nn) 4.948216 4.948216 5.454482 5.454482 5.960749 5.960749 2
Run Code Online (Sandbox Code Playgroud)
replicate在 a 中累积结果,list然后需要检查每个维度的维度,然后再决定可以将其简化为矩阵,并且必须进行转换。使用预先分配的整数矩阵跳过所有这些开销,以获得大约 2 倍的加速。
我们也可以比较,比如说vapply(快速测试显示vapply比循环慢一点),但我认为要获得更高的速度,你需要并行运行 - 这在这里是一个不错的选择,并且可以可能会让您获得几乎等于您使用的内核数量的加速。
sample.int 几乎只是调用 C 代码,因此使用 Rcpp 可能不会做得更好 - 我认为并行化是提高速度的最佳选择。