R语言学习Rcpp基础知识全面整理

目录

  • 1. 相关配置和说明
  • 2. 常用数据类型
  • 3. 常用数据类型的建立
  • 4. 常用数据类型元素访问
  • 5. 成员函数
  • 6. 语法糖
    • 6.1 算术和逻辑运算符
    • 6.2. 常用函数
  • 7. STL
    • 7.1. 迭代器
    • 7.2. 算法
    • 7.3. 数据结构
      • 7.3.1. Vectors
      • 7.3.2. Sets
      • 7.3.3. Maps
  • 8. 与R环境的互动
    • 9. 用Rcpp创建R包
      • 10. 输入和输出示例
        • 如何传递数组
          • 通过.attr("dim")设置维数
        • 函数返回一维STL vector
          • 函数返回二维STL vector
            • 返回Armadillo matrix, Cube 或 field
            • 参考文献:

              1. 相关配置和说明 由于Dirk的书Seamless R and C++ Integration with Rcpp是13年出版的,当时Rcpp Attributes这一特性还没有被CRAN批准,所以当时调用和编写Rcpp函数还比较繁琐。Rcpp Attributes(2016)极大简化了这一过程(“provides an even more direct connection between C++ and R”),保留了内联函数,并提供了sourceCpp函数用于调用外部的.cpp文件。换句话说,我们可以将某C++函数存在某个.cpp文件中,再从R脚本文件中,像使用source一样,通过sourceCpp来调用此C++函数。
              例如,在R脚本文件中,我们希望调用名叫test.cpp文件中的函数,我们可以采用如下操作:
              library(Rcpp)Sys.setenv("PKG_CXXFLAGS"="-std=c++11")sourceCpp("test.cpp")

              其中第二行的意思是使用C++11的标准来编译文件。
              test.cpp文件中, 头文件使用Rcpp.h,需要输出到R中的函数放置在//[[Rcpp::export]]之后。如果要输出到R中的函数需要调用其他C++函数,可以将这些需要调用的函数放在//[[Rcpp::export]]之前。
              #include using namespace Rcpp; //[[Rcpp::export]]

              为进行代数计算,Rcpp提供了RcppArmadillo和RcppEigen。如果要使用此包,需要在函数文件开头注明依赖关系,例如// [[Rcpp::depends(RcppArmadillo)]],并载入相关头文件:
              // [[Rcpp::depends(RcppArmadillo)]]#include #include using namespace Rcpp; using namespace arma; // [[Rcpp::export]]

              C++的基本知识可以参见此处。

              2. 常用数据类型
              关键字 描述
              int/double/bool/String/auto 整数型/数值型/布尔值/字符型/自动识别(C++11)
              IntegerVector 整型向量
              NumericVector 数值型向量(元素的类型为double)
              ComplexVector 复数向量 Not Sure
              LogicalVector 逻辑型向量; R的逻辑型变量可以取三种值:TRUE, FALSE, NA; 而C++布尔值只有两个,true or false。如果将R的NA转化为C++中的布尔值,则会返回true。
              CharacterVector 字符型向量
              ExpressionVector vectors of expression types
              RawVector vectors of type raw
              IntegerMatrix 整型矩阵
              NumericMatrix 数值型矩阵(元素的类型为double)
              LogicalMatrix 逻辑型矩阵
              CharacterMatrix 字符矩阵
              List aka GenericVector 列表;lists; 类似于R中列表,其元素可以使任何数据类型
              DataFrame 数据框;data frames;在Rcpp内部,数据框其实是通过列表实现的
              Function 函数型
              Environment 环境型;可用于引用R环境中的函数、其他R包中的函数、操作R环境中的变量
              RObject 可以被R识别的类型
              注释:
              某些R对象可以通过as(Some_RObject)转化为转化为Rcpp对象。例如:
              在R中拟合一个线性模型(其为List),并将其传入C++函数中
              >mod=lm(Y~X);

              NumericVector resid = as(mod["residuals"]); NumericVector fitted = as(mod["fitted.values"]);

              可以通过as(Some_RcppVector),将NumericVector转换为std::vector。例如:
              std::vector vec; vec = as>(x);

              在函数中,可以用wrap(),将std::vector转换为NumericVector。例如:
              arma::vec long_vec(16,arma::fill::randn); vector long_vec2 = conv_to>::from(long_vec); NumericVector output = wrap(long_vec2);

              在函数返回时,可以使用wrap(),将C++ STL类型转化为R可识别类型。示例见后面输入和输出示例部分。
              以上数据类型除了Environment之外(Function不确定),大多可直接作为函数返回值,并被自动转化为R对象。
              算数和逻辑运算符号+, -, *, /, ++, --, pow(x,p), <, <=, >, >=, ==, !=。逻辑关系符号&&, ||, !

              3. 常用数据类型的建立
              //1. VectorNumericVector V1(n); //创立了一个长度为n的默认初始化的数值型向量V1。NumericVector V2=NumericVector::create(1, 2, 3); //创立了一个数值型向量V2,并初始化使其含有三个数1,2,3。LogicalVector V3=LogicalVector::create(true,false,R_NaN); //创立了一个逻辑型变量V3。如果将其转化为R Object,则其含有三个值TRUE, FALSE, NA。//2. MatrixNumericMatrix M1(nrow,ncol); //创立了一个nrow*ncol的默认初始化的数值型矩阵。//3. Multidimensional ArrayNumericVector out=NumericVector(Dimension(2,2,3)); //创立了一个多维数组。然而我不知道有什么卵用。。//4. ListNumericMatrix y1(2,2); NumericVector y2(5); List L=List::create(Named("y1")=y1,Named("y2")=y2); //5. DataFrameNumericVector a=NumericVector::create(1,2,3); CharacterVector b=CharacterVector::create("a","b","c"); std::vector c(3); c[0]="A"; c[1]="B"; c[2]="C"; DataFrame DF=DataFrame::create(Named("col1")=a,Named("col2")=b,Named("col3")=c);


              4. 常用数据类型元素访问
              元素访问 描述
              [n] 对于向量类型或者列表,访问第n个元素。对于矩阵类型,首先把矩阵的下一列接到上一列之下,从而构成一个长列向量,并访问第n个元素。不同于R,n从0开始。
              (i,j) 对于矩阵类型,访问第(i,j)个元素。不同于R,i和j从0开始。不同于向量,此处用圆括号。
              List["name1"]/DataFrame["name2"] 访问List中名为name1的元素/访问DataFrame中,名为name2的列。

              5. 成员函数
              成员函数 描述
              X.size() 返回X的长度;适用于向量或者矩阵,如果是矩阵,则先向量化
              X.push_back(a) 将a添加进X的末尾;适用于向量
              X.push_front(b) 将b添加进X的开头;适用于向量
              X.ncol() 返回X的列数
              X.nrow() 返回X的行数

              6. 语法糖
              6.1 算术和逻辑运算符
              +, -, *, /, pow(x,p), <, <=, >, >=, ==, !=, !
              以上运算符均可向量化。

              6.2. 常用函数
              is.na()
              Produces a logical sugar expression of the same length. Each element of the result expression evaluates to TRUE if the corresponding input is a missing value, or FALSE otherwise.
              seq_len()
              seq_len( 10 ) will generate an integer vector from 1 to 10 (Note: not from 0 to 9), which is very useful in conjugation withsapply() and lapply().
              pmin(a,b) and pmax(a,b)
              a and b are two vectors. pmin()(or pmax()) compares the i th elements of a and b and return the smaller (larger) one.
              ifelse()
              ifelse( x > y, x+y, x-y ) means if x>y is true, then do the addition; otherwise do the subtraction.
              sapply()
              sapply applies a C++ function to each element of the given expression to create a new expression. The type of the resulting expression is deduced by the compiler from the result type of the function.
              The function can be a free C++ function such as the overload generated by the template function below:
              template T square( const T& x){return x * x ; }sapply( seq_len(10), square ) ;

              Alternatively, the function can be a functor whose type has a nested type called result_type
              template struct square : std::unary_function {T operator()(const T& x){return x * x ; }}sapply( seq_len(10), square() ) ;

              lappy()
              lapply is similar to sapply except that the result is allways an list expression (an expression of type VECSXP).
              sign()
              其他函数
              • 数学函数: abs(), acos(), asin(), atan(), beta(), ceil(), ceiling(), choose(), cos(), cosh(), digamma(), exp(), expm1(), factorial(), floor(), gamma(), lbeta(), lchoose(), lfactorial(), lgamma(), log(), log10(), log1p(), pentagamma(), psigamma(), round(), signif(), sin(), sinh(), sqrt(), tan(), tanh(), tetragamma(), trigamma(), trunc().
              • 汇总函数: mean(), min(), max(), sum(), sd(), and (for vectors) var()
              • 返回向量的汇总函数: cumsum(), diff(), pmin(), and pmax()
              • 查找函数: match(), self_match(), which_max(), which_min()
              • 重复值处理函数: duplicated(), unique()

              7. STL Rcpp可以使用C++的标准模板库STL中的数据结构和算法。Rcpp也可以使用Boost中的数据结构和算法。

              7.1. 迭代器
              此处仅仅以一个例子代替,详细参见C++ Primer,或者此处。
              #include using namespace Rcpp; // [[Rcpp::export]]double sum3(NumericVector x) {double total = 0; NumericVector::iterator it; for(it = x.begin(); it != x.end(); ++it) {total += *it; }return total; }


              7.2. 算法
              头文件中提供了许多的算法(可以和迭代器共用),具体可以参见此处。
              For example, we could write a basic Rcpp version of findInterval() that takes two arguments a vector of values and a vector of breaks, and locates the bin that each x falls into.
              #include #include using namespace Rcpp; // [[Rcpp::export]]IntegerVector findInterval2(NumericVector x, NumericVector breaks) {IntegerVector out(x.size()); NumericVector::iterator it, pos; IntegerVector::iterator out_it; for(it = x.begin(), out_it = out.begin(); it != x.end(); ++it, ++out_it) {pos = std::upper_bound(breaks.begin(), breaks.end(), *it); *out_it = std::distance(breaks.begin(), pos); }return out; }


              7.3. 数据结构
              STL所提供的数据结构也是可以使用的,Rcpp知道如何将STL的数据结构转换成R的数据结构,所以可以从函数中直接返回他们,而不需要自己进行转换。
              具体请参考此处。

              7.3.1. Vectors 详细信息请参见处此
              创建
              vector, vector, vector, vector
              元素访问
              利用标准的[]符号访问元素
              元素增加
              利用.push_back()增加元素。
              存储空间分配
              如果事先知道向量长度,可用.reserve()分配足够的存储空间。
              例子:
              The following code implements run length encoding (rle()). It produces two vectors of output: a vector of values, and a vector lengths giving how many times each element is repeated. It works by looping through the input vector x comparing each value to the previous: if it's the same, then it increments the last value in lengths; if it's different, it adds the value to the end of values, and sets the corresponding length to 1.
              #include using namespace Rcpp; // [[Rcpp::export]]List rleC(NumericVector x) {std::vector lengths; std::vector values; // Initialise first valueint i = 0; double prev = x[0]; values.push_back(prev); lengths.push_back(1); NumericVector::iterator it; for(it = x.begin() + 1; it != x.end(); ++it) {if (prev == *it) {lengths[i]++; } else {values.push_back(*it); lengths.push_back(1); i++; prev = *it; }}return List::create(_["lengths"] = lengths, _["values"] = values); }


              7.3.2. Sets 参见链接1,链接2和链接3。
              STL中的集合std::set不允许元素重复,而std::multiset允许元素重复。集合对于检测重复和确定不重复的元素具有重要意义((like unique, duplicated, or in))。
              Ordered set: std::setstd::multiset
              Unordered set: std::unordered_set
              一般而言unordered set比较快,因为它们使用的是hash table而不是tree的方法。
              unordered_set, unordered_set, etc

              7.3.3. Maps 与table()match()关系密切。
              Ordered map: std::map
              Unordered map: std::unordered_map
              Since maps have a value and a key, you need to specify both types when initialising a map:
              map, unordered_map.

              8. 与R环境的互动 通过EnvironmentRcpp可以获取当前R全局环境(Global Environment)中的变量和载入的函数,并可以对全局环境中的变量进行修改。我们也可以通过Environment获取其他R包中的函数,并在Rcpp中使用。
              获取其他R包中的函数
              Rcpp::Environment stats("package:stats"); Rcpp::Function rnorm = stats["rnorm"]; return rnorm(10, Rcpp::Named("sd", 100.0));

              获取R全局环境中的变量并进行更改
              假设R全局环境中有一个向量x=c(1,2,3),我们希望在Rcpp中改变它的值。
              Rcpp::Environment global = Rcpp::Environment::global_env(); //获取全局环境并赋值给Environment型变量globalRcpp::NumericVector tmp = global["x"]; //获取xtmp=pow(tmp,2); //平方global["x"]=tmp; //将新的值赋予到全局环境中的x

              获取R全局环境中的载入的函数
              假设全局环境中有R函数funR,其定义为:
              x=c(1,2,3); funR<-function(x){return (-x); }

              并有R变量x=c(1,2,3)。我们希望在Rcpp中调用此函数并应用在向量x上。
              #include using namespace Rcpp; // [[Rcpp::export]]NumericVector funC() {Rcpp::Environment global =Rcpp::Environment::global_env(); Rcpp::Function funRinC = global["funR"]; Rcpp::NumericVector tmp = global["x"]; return funRinC(tmp); }


              9. 用Rcpp创建R包 见此文
              利用Rcpp和RcppArmadillo创建R包

              10. 输入和输出示例
              如何传递数组
              如果要传递高维数组,可以将其存为向量,并附上维数信息。有两种方式:

              通过.attr("dim")设置维数 NumericVector可以包含维数信息。数组可以用过NumericVector输出到R中。此NumericVector可以通过.attr(“dim”)设置其维数信息。
              // Dimension最多设置三个维数output.attr("dim") = Dimension(3,4,2); // 可以给.attr(“dim”)赋予一个向量,则可以设置超过三个维数NumericVector dim = NumericVector::create(2,2,2,2); output.attr("dim") = dim;

              示例:
              // 返回一个3*3*2数组RObject func(){arma::vec long_vec(18,arma::fill::randn); vector long_vec2 = conv_to>::from(long_vec); NumericVector output = wrap(long_vec2); output.attr("dim")=Dimension(3,3,2); return wrap(output); }// 返回一个2*2*2*2数组 // 注意con_to<>::from()RObject func(){arma::vec long_vec(16,arma::fill::randn); vector long_vec2 = conv_to>::from(long_vec); NumericVector output = wrap(long_vec2); NumericVector dim = NumericVector::create(2,2,2,2); output.attr("dim")=dim; return wrap(output); }

              另外建立一个向量存维数,在R中再通过.attr("dim")设置维数

              函数返回一维STL vector
              自动转化为R中的向量
              vector func(NumericVector x){vector vec; vec = as>(x); return vec; }NumericVector func(NumericVector x){vector vec; vec = as>(x); return wrap(vec); }RObject func(NumericVector x){vector vec; vec = as>(x); return wrap(vec); }


              函数返回二维STL vector
              自动转化为R中的list,list中的每个元素是一个vector。
              vector> func(NumericVector x) {vector> mat; for (int i=0; i!=3; ++i){mat.push_back(as>(x)); }return mat; }RObject func(NumericVector x) {vector> mat; for (int i=0; i!=3; ++i){mat.push_back(as >(x)); }return wrap(mat); }


              返回Armadillo matrix, Cube 或 field
              自动转化为R中的matrix
              NumericMatrix func(){arma::mat A(3,4,arma::fill::randu); return wrap(A); }arma::mat func(){arma::mat A(3,4,arma::fill::randu); return A; }

              自动转化为R中的三维array
              arma::cube func(){arma::cube A(3,4,5,arma::fill::randu); return A; }RObject func(){arma::cube A(3,4,5,arma::fill::randu); return wrap(A); }

              自动转化为R list,每个元素存储一个R向量,但此向量有维数信息(通过.Internal(inspect())查询)。
              RObject func() {arma::cube A(3,4,2,arma::fill::randu); arma::cube B(3,4,2,arma::fill::randu); arma::fieldF(2,1); F(0)=A; F(1)=B; return wrap(F); }


              参考文献: Eddelbuettel, D. (2013). Seamless R and C++ Integration with Rcpp. Springer Publishing Company, Incorporated. ·
              Allaire, J.J. (2016). Rcpp Attributes.
              Eddelbuettel, D. (2016). Rcpp syntactic sugar.
              http://adv-r.had.co.nz/Rcpp.html
              http://www.rcpp.org/
              http://blog.csdn.net/a358463121
              http://www.runoob.com/cplusplus/cpp-operators.html
              如需引用,请注明出处。
              【R语言学习Rcpp基础知识全面整理】以上就是R语言学习Rcpp知识全面整理的详细内容,更多关于Rcpp知识全面整理的资料请关注脚本之家其它相关文章!

                推荐阅读