【问题标题】:How to hand R objects to C++ using Rcpp?如何使用 Rcpp 将 R 对象交给 C++?
【发布时间】:2019-08-01 03:42:45
【问题描述】:

如何使用 Rcpp 将 R 对象交给 C++?

嘿,我是 Rcpp 的新手,遇到以下问题(这可能很简单,但我无法弄清楚)。我首先在 R 中创建了一个列表、向量和一个数据框。我想将这些 R 对象传递给 C++ 以修改列表,然后将修改后的列表再次返回给 R 以进行进一步分析。

我在 Rstudio 中做了一个 cpp 文件的例子:

#include <Rcpp.h>
using namespace Rcpp;

/*** R
mylist <- list(mat1 = data.frame(Col1 = c('id1','id2','id3'), Col2 = c(5,6,7), Col3 = as.factor(c('blue','green','black'))),
               mat2 = data.frame(Col1 = c('id1','id2','id3'), Col2 = c(5,6,7), Col3 = as.factor(c('blue','green','black'))),
               mat3 = data.frame(Col1 = c('id1','id2','id3'), Col2 = c(5,6,7), Col3 = as.factor(c('blue','green','black'))),
               mat4 = data.frame(Col1 = c('id1','id2','id3'), Col2 = c(5,6,7), Col3 = as.factor(c('blue','green','black'))))
myvector1 <- c(seq(8,10,1))
myvector2 <- c(seq(101,103,1))

mydataframe <- data.frame(Col1 = c('id3','id4','id5'), Col2 = seq(21,23,1), Col3 = as.factor(c('blue','green','black')))
*/


// [[Rcpp::export]]

// Some code modifying mylist with myvector1, myvector2 and mydataframe and returning the modified list again to R
// Let's say Col2 of mat1 of mylist shall be multiplied with myvector1 and Col 2 of mat2 with myvector2. 
// Col2 of mat4 shall be divided by Col2 of mydataframe
// And then the modified mylist should be returned
}

/*** R
# Some analysis with the new modified list generated in the C++ code
summary(mylist$mat2$Col2)
*/

我怎样才能使这样的操作通常有效(实际上我的列表要大得多)?还是使用带有 cxxfunction 函数的 Rscript 更好?感谢您的帮助!

【问题讨论】:

    标签: c++ r rcpp


    【解决方案1】:

    看来您的问题是如何实际使用 Rcpp 结合 R 和 C++。我看到了几种方法。选择哪一个取决于代码量、您进行类似分析的频率、您将来必须返回此特定分析的可能性等。最好自己尝试一下,这样您就可以形成你自己的启发式何时选择哪个。

    单个文件

    C++ 加 R

    如果 C++ 比 R 多,则使用带有特殊 R 注释的单个 cpp 很有用。一般结构:

    #include <Rcpp.h>
    
    // [[Rcpp::export]]
    void foo(Rcpp::List l, Rcpp::NumericVector v1, Rcpp::NumericVector v2, Rcpp::DataFrame df) {
        Rcpp::List mat2 = l["mat2"];
        Rcpp::NumericVector Col2 = mat2["Col2"];
        Col2(0) = 10;
    }
    
    /*** R
    mylist <- list(mat1 = data.frame(Col1 = c('id1','id2','id3'), Col2 = c(5,6,7), Col3 = as.factor(c('blue','green','black'))),
                   mat2 = data.frame(Col1 = c('id1','id2','id3'), Col2 = c(5,6,7), Col3 = as.factor(c('blue','green','black'))),
                   mat3 = data.frame(Col1 = c('id1','id2','id3'), Col2 = c(5,6,7), Col3 = as.factor(c('blue','green','black'))),
                   mat4 = data.frame(Col1 = c('id1','id2','id3'), Col2 = c(5,6,7), Col3 = as.factor(c('blue','green','black'))))
    myvector1 <- c(seq(8,10,1))
    myvector2 <- c(seq(101,103,1))
    
    mydataframe <- data.frame(Col1 = c('id3','id4','id5'), Col2 = seq(21,23,1), Col3 = as.factor(c('blue','green','black')))
    
    foo(mylist, myvector1, myvector2, mydataframe)
    
    summary(mylist$mat2$Col2)
    */
    

    这与您所拥有的类似,但只有一个 R 注释。您需要调用 Rcpp::sourceCpp("&lt;file&gt;") 来编译并执行 R 注释中的代码。在 RStudio 中,您可以为此使用“Source”。

    请注意,在上面的示例中,列表是通过引用更改的,这可能很危险,因为 R 遵循写入时复制策略。对于大型列表,这当然很昂贵,这可能就是您寻找 C++ 解决方案的原因。

    R 加 C++

    如果 C++ 代码很少,您可以使用Rcpp:cppFunction("&lt;C++ code&gt;")。我不会再使用inline::cxxfunction。我很少使用这种方法,因为 C++ 代码没有编辑器支持。

    R 降价

    R Markdown 允许您使用 rrcpp 块在平等的基础上组合 R 和 C++。如果您想在分析中添加一些散文,这非常有用。在 RStudio 中,您可以获得对这两种类型的块的编辑器支持。但是,有时来自 C++ 编译器的错误消息会被弄乱,使它们更难解释。

    多个文件

    项目

    如果代码量增加或输入数据文件,您可能会考虑某种项目结构,例如目录 dataRsrc 用于数据文件、带有函数定义的 R 脚本和 C++ 文件。然后驱动程序文件(R 或 Rmd)将加载数据,source R 脚本和sourceCpp C++ 文件,然后再进行实际分析。

    R 包

    一旦你使用了项目结构,你也可以选择一个包。只需一点额外的工作,您就会获得以下几个优势:

    • C++ 代码只需编译一次
    • R 函数立即进行字节编译
    • C++ 函数可轻松用于并行处理
    • 清晰的结构以集成文档和测试
    • ...

    请注意,您可以从一个空包和一个 Rmd 文件开始。一开始,您只使用 Rmd 文件。您可以不时重构代码,将其中的一部分作为 R 或 C++ 函数移动到包中。

    【讨论】:

    • 非常感谢您的详细回答 - 从您提到的内容中,我有很多事情要考虑。曾经普遍存在的问题是它如何将我的 R 对象(列表、数据帧等)放入我的 C++ 代码部分?还是“仅”可以编写一个 C++ 函数,然后在 R 环境中使用 R 对象调用该函数?或者是否有可能有一个直接的“接口”将 R 对象交给 C++ 环境,然后在 C++ 中使用它们,反之亦然?
    • @sh_student 我让第一个例子更加具体。 HTH。
    猜你喜欢
    • 2022-10-14
    • 2022-01-05
    • 2013-10-04
    • 1970-01-01
    • 1970-01-01
    • 2021-09-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多