我在哪里可以学习如何编写C代码以加快慢速R功能? [关闭

StackOverflow https://stackoverflow.com/questions/4106174

  •  29-09-2019
  •  | 
  •  

学习如何与R一起使用C代码的最佳资源是什么?我知道 系统和外语界面 r扩展部分,但我发现很难进行。什么是为R编写C代码的良好资源(在线和离线)是什么?

为了澄清,我不想学习如何编写C代码,我想学习如何更好地整合R和C。还是从C标量到R向量?

有帮助吗?

解决方案

好老了 使用来源,卢克! --- R本身具有很多(非常有效的)C代码可以研究的(非常有效),Cran有数百个包裹,其中一些来自您信任的作者。这提供了真实的,经过测试的例子来研究和适应。

但是正如乔什所怀疑的那样,我更倾向于C ++,因此 RCPP. 。它也有很多例子。

编辑: 我发现有两本书有帮助:

  • 第一个是Venables和Ripley的“S编程“即使牙齿持续很长时间(并且有多年的第二版有传言称)。当时没有其他东西。
  • 钱伯斯的第二个数据分析软件“这是最近要多得多的,具有更好的R中心 - 以及有关扩展R的两章。C和C ++都被提及了。另外,John为我所做的工作丝毫 消化 因此,仅此而已。

也就是说,约翰越来越喜欢 RCPP (并贡献)当他找到R对象和C ++对象之间的匹配时(通过 RCPP)很自然 - 参考年份在那里有所帮助。

编辑2: 有了哈德利的重组问题,我 非常强烈 敦促您考虑C ++。您与C-非常乏味和 非常避免. 。看看 RCPP引入小插图. 。另一个简单的例子是 这篇博客文章 我表明,而不是担心约10%的差异(在一个Radford Neal示例中),我们可以得到 八倍 随着C ++的增加(当然是一个人为的例子)。

编辑3: 有复杂性,您可能会遇到C ++错误,这些错误很难抓住。但是只是 使用RCPP 您几乎不需要扩展它。而这个 成本 不可否认,它被 益处 在更简单的代码,较少的样板,没有保护/毫无保护的情况下,没有内存管理等,pp。DougBates昨天说,他发现C ++和RCPP更像写R,而不是写C ++。 YMMV等等。

其他提示

哈德利,

您绝对可以编写类似于C代码的C ++代码。

我了解您对C ++的评价比C更复杂。对此。 RCPP的实施非常复杂,但仅仅因为您不知道冰箱的工作原理,这并不意味着您不能打开门并拿起新鲜的牛奶...

从您对R的许多贡献中,令我震惊的是,您发现R有些乏味(数据操纵,图形,字符串manipulatio等...)。通过R的内部C API做好准备,这是非常乏味的。

我不时阅读R-Exts或R-Ints手册。这有帮助。但是在大多数情况下,当我真的想了解某些东西时,我进入了R来源,也进入了EG Simon编写的软件包的来源(通常有很多东西可以学习)。

RCPP旨在使API的这些乏味的方面消失。

您可以根据一些例子自己判断自己发现更复杂,混淆等的内容。此函数使用C API创建字符向量:

SEXP foobar(){
  SEXP ab;
  PROTECT(ab = allocVector(STRSXP, 2));
  SET_STRING_ELT( ab, 0, mkChar("foo") );
  SET_STRING_ELT( ab, 1, mkChar("bar") );
  UNPROTECT(1);
}

使用RCPP,您可以编写与:

SEXP foobar(){
   return Rcpp::CharacterVector::create( "foo", "bar" ) ;
}

或者:

SEXP foobar(){
   Rcpp::CharacterVector res(2) ;
   res[0] = "foo" ;
   res[1] = "bar" ;
   return res ;
}

正如德克所说,几个小插曲还有其他例子。我们通常还将人们指向我们的单位测试,因为每个人都测试了代码的非常特定的部分,并且有些自我解释。

我显然在这里有偏见,但是我建议您熟悉RCPP,而不是学习R的C API,然后如果某些内容不清楚或对RCPP似乎不可能,然后进入邮件列表。

无论如何,销售的结束。

我想这完全取决于您最终要编写的代码。

罗曼

@hadley:不幸的是,我没有特定的资源来帮助您开始使用C ++。我从斯科特·迈耶斯(Scott Meyers)的书籍(有效的C ++,更有效的C ++等)中挑选了它,但是这些并不是人们所说的介绍性。

我们几乎专门使用.call接口来调用C ++代码。规则很容易:

  • C ++功能必须返回R对象。所有R对象都是SEXP。
  • C ++函数将0到65 R对象作为输入(再次SEXP)
  • 它必须(不是真的,但是我们可以保存以供以后保存),以c链接声明,要么 外部“ C” 或者 rcppexport RCPP定义的别名。

因此

#include <Rcpp.h>

RcppExport SEXP foo( SEXP x1, SEXP x2 ) ;

并在.cpp文件中这样实现:

SEXP foo( SEXP x1, SEXP x2 ){
   ...
}

关于使用RCPP的R API并没有更多的了解。

大多数人只想与RCPP中的数字向量打交道。您可以使用NemericVector类来完成此操作。创建数字向量有几种方法:

从您从r传递的现有对象:

 SEXP foo( SEXP x_) {
    Rcpp::NumericVector x( x_ ) ;
    ...
 }

使用::创建静态函数的给定值:

 Rcpp::NumericVector x = Rcpp::NumericVector::create( 1.0, 2.0, 3.0 ) ;
 Rcpp::NumericVector x = Rcpp::NumericVector::create( 
    _["a"] = 1.0, 
    _["b"] = 2.0, 
    _["c"] = 3
 ) ;

给定的大小:

 Rcpp::NumericVector x( 10 ) ;      // filled with 0.0
 Rcpp::NumericVector x( 10, 2.0 ) ; // filled with 2.0

然后,一旦您拥有矢量,最有用的是从中提取一个元素。这是使用运算符[]进行的,并具有0个基于0的索引,因此例如,数字向量的值将其类似:

SEXP sum( SEXP x_ ){
   Rcpp::NumericVector x(x_) ;
   double res = 0.0 ;
   for( int i=0; i<x.size(), i++){
      res += x[i] ;
   }
   return Rcpp::wrap( res ) ;
}

但是,使用RCPP糖,我们现在可以做得更好:

using namespace Rcpp ;
SEXP sum( SEXP x_ ){
   NumericVector x(x_) ;
   double res = sum( x ) ;
   return wrap( res ) ;
}

正如我之前说的,这完全取决于您要编写哪种代码。查看人们在依赖RCPP的包装中所做的事情,检查小插图,单位测试,在邮件列表中回到我们身边。我们总是很乐意提供帮助。

@jbremnant:是的。 RCPP类实施接近RAII模式的东西。创建RCPP对象时,构造函数采取适当的措施来确保底层R对象(SEXP)受到保护免受垃圾收集器的保护。驱动器撤回保护。这在 RCPP内部 小插图。基础实现依赖于R API功能 r_preserveObjectr_releaseObject

确实由于C ++封装而受到绩效处罚。我们试图将其与内在等相关等等。

来自RCPP类函数的调用R函数比使用C API直接调用评估要慢。这是因为我们采取预防措施并将函数调用包装到TryCatch块中,以便捕获R错误并将其促进C ++异常,以便可以使用C ++中的标准try/Catch处理它们。

大多数人都想使用向量(特别是数字向量),并且该课程的惩罚非常小。示例/CornvelveBenchmarks目录包含R-Exts臭名昭著的卷积函数的几种变体,而Vignette具有基准结果。事实证明,RCPP使其比使用R API的基准代码快。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top