【问题标题】:Rcpp subsetting contiguous StringVectorRcpp 子集连续 StringVector
【发布时间】:2018-03-21 22:48:39
【问题描述】:

下午好,

在使用 Rcpp 时,我一直在尝试使用类似的方法来对 R 中的 x[200:300] 进行子集化。 (注意,这不是我要解决的问题,但我需要在我尝试用 C++ 编写的函数中对许多范围进行子集化,我发现这是我的性能瓶颈)

然而,虽然我尝试过使用 rcpp 中的方法、使用迭代器或其他东西,但我似乎没有找到一个最低限度“快速”的解决方案。我发现的大多数解决方案都很慢。

并且查看 Rcpp 的参考,我似乎找不到任何东西,我在 StackExchange 中找不到它。

我知道这段代码现在很丑……但我只是一无所知

// [[Rcpp::export]]
StringVector range_test_( StringVector& x, int i, int j){
    StringVector vect(x.begin()+i, x.begin()+j);
    return vect;
}

然后,它慢了 800 倍。我一直在尝试在 rcpp 基础中找到与 R 相同的 x[i:j] 函数,它非常快......但我找不到它。

 tests_range <- rbenchmark::benchmark(
    x[200:3000],
    range_test_(x, 200, 3000),
    order = NULL,
    replications = 80
)[,1:4]

作为结果给出

                             test replications elapsed relative
1                     x[200:3000]           80   0.001        1
3       range_test_(x, 200, 3000)           80   0.822      822

如果有人知道如何访问子集函数x[i:j] 或在 Rcpp 中以同样快的速度访问,我将不胜感激。我似乎无法找到我缺少的工具。

【问题讨论】:

    标签: subset rcpp contiguous


    【解决方案1】:

    问题在于迭代器构造函数进行了复制。见this page

    将迭代器 first 和 last 之间的数据复制到创建的向量中

    不过,你可以试试这个

    #include <Rcpp.h>
    
    // [[Rcpp::export]]
    Rcpp::StringVector in_range(Rcpp::StringVector &x, int i, int j) {
      return x[Rcpp::Range(i - 1, j - 1)]; // zero indexed
    }
    

    所花的时间更近了

    > set.seed(20597458)
    > x <- replicate(1e3, paste0(sample(LETTERS, 5), collapse = ""))
    > head(x)
    [1] "NHVFQ" "XMEOF" "DABUT" "XKTAZ" "NQXZL" "NPJLM"
    > 
    > stopifnot(all.equal(in_range(x, 100, 200), x[100:200]))
    > 
    > library(microbenchmark)
    > microbenchmark(in_range(x, 100, 200), x[100:200], times = 1e4)
    Unit: nanoseconds
                      expr  min   lq     mean median   uq     max neval
     in_range(x, 100, 200) 1185 1580 3669.780   1581 1976 3263205 10000
                x[100:200]  790  790 1658.571   1185 1186 2331256 10000
    

    请注意,有一个page here 支持投注。我在那里找不到相关的例子。

    【讨论】:

    • 哦,该死的,我才注意到它为什么这么慢。我在输入数字向量,而 Rcpp 在进行测试时必须转换它们并输出字符串向量。
    • 使用指针比 range 方法快 10%。我对 30000 个长向量进行了适当的测试,并选择了其中的 20000 个。而且它们比 R 子集更好。
    • 查看源代码我认为最好使用R_xlen_t 而不是int 作为ij 参数:github.com/RcppCore/Rcpp/blob/master/inst/include/Rcpp/sugar/…
    • 是的,根据 R 的构建方式 (github.com/wch/r-source/blob/…),使用 R_xlen_t 是更好的选择。不,没有边界检查。如果您想要绑定检查 (yixuan.cos.name/rcpp-note/api/…),请使用 operator() 成员函数。看起来 OP 想要一些快速的东西,所以我改用 operator[] 成员函数。
    • @BenjaminChristoffersen 我只是想“警告”代码 sn-p 的用户注意风险。是的,括号和括号运算符确实支持边界检查,但它们不在使它们“更慢”的范围内运行。顺便说一句,我喜欢你的答案,这似乎是我能找到的唯一一个关于如何使用索引范围对向量进行子集化的方法!我建议使用您的脚本来扩展 Rcpp 库...
    猜你喜欢
    • 2017-08-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-29
    • 2016-04-30
    相关资源
    最近更新 更多