基本上,我想做sort(sample(n, replace = TRUE))
次n = 1e6
,并且要进行多次(例如1e4次)。
有什么方法可以在R(cpp)中更快地完成它?
答案 0 :(得分:4)
在Rcpp中实现@Frank的想法:
=TEXTJOIN(",", 1, SPLIT(REGEXREPLACE(B$1, SUBSTITUTE(B4, ",", "|"), ), ","))
基准:
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
IntegerVector sort_sample(int n) {
IntegerVector tab(n);
for (int i = 0; i < n; i++) {
int k = n * unif_rand();
tab[k]++;
}
return tab;
}
对于n = 1e5:
microbenchmark::microbenchmark(
sort(sample(n, replace = TRUE)),
tabulate(sample(n, replace = TRUE), n),
sort_sample(n)
)
对于n = 1e6:
Unit: microseconds
expr min lq mean median uq max neval
sort(sample(n, replace = TRUE)) 3214.726 3393.606 3667.1001 3507.0525 3716.3560 7007.411 100
tabulate(sample(n, replace = TRUE), n) 1087.543 1104.215 1245.0722 1136.9085 1218.5865 4265.075 100
sort_sample(n) 789.403 812.780 870.2723 837.3445 924.4395 1188.432 100
答案 1 :(得分:1)
正如@Frank在评论中所提到的,使用tabulate
代替sort
是有意义的。一旦使用了它,就应该考虑我的faster sampling methods软件包所提供的dqrng了:
library(dqrng)
m <- 1e6
bm <- bench::mark(sort(sample.int(m, replace = TRUE)),
tabulate(sample.int(m, replace = TRUE)),
sort(dqsample.int(m, replace = TRUE)),
tabulate(dqsample.int(m, replace = TRUE)),
check = FALSE)
bm[, 1:4]
#> # A tibble: 4 x 4
#> expression min median `itr/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl>
#> 1 sort(sample.int(m, replace = TRUE)) 72.3ms 75.5ms 13.2
#> 2 tabulate(sample.int(m, replace = TRUE)) 22.8ms 27.7ms 34.6
#> 3 sort(dqsample.int(m, replace = TRUE)) 59.5ms 64ms 15.3
#> 4 tabulate(dqsample.int(m, replace = TRUE)) 14.4ms 16.3ms 57.0
由reprex package(v0.3.0)于2019-06-27创建
请注意,我仍在此计算机上使用R 3.5。使用R 3.6时,sample.int
和dqsample.int
之间的差异会更大。还请注意,不再需要开发版本的dqrng来获取快速采样方法。
一个人也可以通过C ++使用来自dqrng的RNG,但这与tabulate(dqsample.int(...))
相比并没有太大区别:
#include <Rcpp.h>
// [[Rcpp::depends(dqrng, sitmo)]]
#include <dqrng_generator.h>
#include <convert_seed.h>
#include <R_randgen.h>
// [[Rcpp::plugins(cpp11)]]
// [[Rcpp::export]]
Rcpp::IntegerVector sort_sample(uint32_t n) {
Rcpp::IntegerVector seed(2, dqrng::R_random_int);
auto rng = dqrng::generator(dqrng::convert_seed<uint64_t>(seed));
Rcpp::IntegerVector tab(n);
for (uint32_t i = 0; i < n; i++) {
uint32_t k = (*rng)(n);
tab[k]++;
}
return tab;
}