Rcpp实战

来源:互联网 发布:淘宝购物券在哪里设置 编辑:程序博客网 时间:2024/06/13 08:36

        Rcpp比传统的R API简洁易用,更加类似C++了。Rcpp采用的Robject管理R传来的对象,如: cpp::NumericVector ab = Rcpp::NumericVector::create(123.45, 67.89);创建一个2个值的数值型向量,可以直接用下标操作[]取到元素值。

        Rcpp类型和R类型对照表:左边是Rcpp对象,右边是R对象,比如Rcpp::IntegerVecto在R中可以对应1:10

                                Rcpp class                                                                         R 类型
                        Integer(Vector|Matrix)                                            integer vectors and matrices
                        Numeric(Vector|Matrix)                                         numeric ...
                        Logical(Vector|Matrix)                                           logical ...
                        Character(Vector|Matrix)                                      character ...
                        Complex(Vector|Matrix)                                        complex ...
                        List                                                                            list (aka generic vectors) ...
                        Expression(Vector|Matrix)                                    expression ...
                        Environment                                                            environment
                        Function                                                                   function
                        XPtr                                                                           externalptr
                        Language                                                                language
                        S4                                                                              S4

        Rcpp对象转为R对象:template <typename T> SEXP wrap(const T& object);    //将Rcpp中对象转换为R对象,如将Rcpp中的int转为R中的numeric通常用于Rcpp返回值如return Rcpp:wrap(10)。wrap 的作用是将 C++ 的数据类型转换成 R 的数据类型,方便将C++ 的运算结果返回到 R 中

        R的对象转换为Rcpp对象:template <typename T> T as(SEXP m_sexp);     //as 的作用将 R 中的数据类型转换成 C++ 中的数据类型

        Rcpp::Function

        Rcpp::Environment

        Rcpp::Formula

        Rcpp::Language

例如:

#include <Rcpp.h>#include<iostream>#include <boost/array.hpp>//这里没有使用boost,只是想说明可以直接使用boostusing namespace Rcpp;using namespace std;// [[Rcpp::export]]SEXP traverse(NumericMatrix x) {//NumericVector traverse(NumericMatrix x)  cout<<"矩阵操作"<<endl;  int nrow=x.nrow();//行数  int ncol=x.ncol();//列数  for(int i=0;i<nrow;i++){    for(int j=0;j<ncol;j++){      cout<<x(i,j)<<" ";//矩阵下标操作x(i,j)    }    cout<<endl;  }  cout<<"调用R内置函数"<<endl;  Environment stats("package:stats");  Function rnorm=stats["rnorm"];  //If you don't know in advance what the output will be,   //store it in an RObject or in components of a List.  //特别是tapply这样的函数返回类型是list  NumericVector a=as<NumericVector>(rnorm(3));//as的用法  for(NumericVector::iterator it=a.begin();it!=a.end();it++){    *it+=10;  }  a.names() = CharacterVector::create("a", "b", "c");//修改a的属性  a.attr("my-attr") = "my-value";  a.attr("class") = "my-class";  return Rcpp::wrap(a);//可以是return a相当于定义返回值为NumericVector//wrap的用法}//下面是R脚本/*** R#格式非得这样:/*** R  x=matrix(1:16,4,4)traverse(x)*/

Rcpp中的缺失值:

  int int_s = NA_INTEGER;  String chr_s = NA_STRING;  bool lgl_s = NA_LOGICAL;  double num_s = NA_REAL;

比较好的几个Rcpp教程:

http://adv-r.had.co.nz/Rcpp.html

http://cran.rstudio.com/web/packages/Rcpp/vignettes/Rcpp-quickref.pdf

http://www.jstatsoft.org/v40/i08/paper

http://cos.name/wp-content/uploads/2012/05/13-huangjinshan-Rcpp.pdf

一个例子,当然这个可以直接在C++中做,但是我数据在R里处理能直接通过Rcpp做的话当然方便。

文件数据部分大致是这样的:

 row.namesV1V2V3V4V5V6 1201311NeituiAngelInnovation Works||4.00e-01 2201311Analyze ReSeedBDC Venture Capital||1.40e+00 3201311Garantia DataSeries ABain Capital Ventures||Carmel Ventures||9.00e+00 4201311BugBusterSeries APolytech Ventures||1.10e+00

        现在的目标是将列V5中||分隔开的数据分割成不同的行,其它部分保留。

        开始我在R里面采用for循环的方式运行大概4万多条花了整整一晚上(一个中下配置的笔记本),现在我采用Rcpp运行大概其中26000多条数据,十几秒就能完成,突然感觉还是C++才是王道啊!

      其中data01就是上面表格中的V1~V6的数据,是个DataFrame。

#include<Rcpp.h>#include<vector>  #include<string>  #include<fstream>#include<boost/algorithm/string/classification.hpp>  #include<boost/algorithm/string/split.hpp> using namespace Rcpp;using namespace std;using namespace boost;// [[Rcpp::export]]void split(CharacterVector Year,CharacterVector Month,CharacterVector Com,CharacterVector Round,CharacterVector Investor,NumericVector Size){//这里有点缺憾就是直接传DataFrame进去无法索引下标(C++的矩阵是各列属性相同,但是DataFrame各列可以异构),所以只好选择每列作为一个向量参数  int len=Investor.size();  ofstream out("result.txt",ios::out);  for(int i=0;i<len;i++){    vector<string> vec;    string temp=as<string>(Investor[i]);    boost::split(vec,temp,is_any_of("|"));//boost的字符串分割函数    for(vector<string>::iterator it=vec.begin();it!=vec.end();it++){      if(*it!=""){        out<<Year[i]<<"\t"<<Month[i]<<"\t"<<Com[i]<<"\t"<<Round[i]<<"\t"<<*it<<"\t"<<Size[i]<<endl;      }    }  }}/*** Rsplit(as.character(data01[,1]),      as.character(data01[,2]),      as.character(data01[,3]),      as.character(data01[,4]),      as.character(data01[,5]),      as.numeric(data01[,6]))*/

输出的结果数据部分:

2013 11 Neitui Angel Innovation Works 0.4
2013 11 Analyze Re SeedBDC Venture Capital1.4
2013 11 Garantia Data Series ABain Capital Ventures9
2013 11 Garantia Data Series ACarmel Ventures9
2013 11 BugBuster Series APolytech Ventures1.1
2013 11 Hinge Series AGreat Oaks Venture Capital4
2013 11 Hinge Series AThe Social+Capital Partnership4