温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

R语言中Rcpp基础知识点有哪些

发布时间:2021-11-06 17:22:54 来源:亿速云 阅读:169 作者:小新 栏目:开发技术

这篇文章将为大家详细讲解有关R语言中Rcpp基础知识点有哪些,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。

    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 <Rcpp.h>
    using namespace Rcpp;
    //[[Rcpp::export]]

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

    // [[Rcpp::depends(RcppArmadillo)]]
    #include <RcppArmadillo.h>
    #include <Rcpp.h>
    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字符型向量
    ExpressionVectorvectors of expression types
    RawVectorvectors 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_RcppObject>(Some_RObject)转化为转化为Rcpp对象。例如:
    在R中拟合一个线性模型(其为List),并将其传入C++函数中

    >mod=lm(Y~X);
    NumericVector resid = as<NumericVector>(mod["residuals"]);
    NumericVector fitted = as<NumericVector>(mod["fitted.values"]);

    可以通过as<some_STL_vector>(Some_RcppVector),将NumericVector转换为std::vector。例如:

    std::vector<double> vec;
    vec = as<std::vector<double>>(x);

    在函数中,可以用wrap(),将std::vector转换为NumericVector。例如:

    arma::vec long_vec(16,arma::fill::randn);
    vector<double> long_vec2 = conv_to<vector<double>>::from(long_vec);
    NumericVector output = wrap(long_vec2);

    在函数返回时,可以使用wrap(),将C++ STL类型转化为R可识别类型。示例见后面输入和输出示例部分。

    以上数据类型除了Environment之外(Function不确定),大多可直接作为函数返回值,并被自动转化为R对象。

    算数和逻辑运算符号+, -, *, /, ++, --, pow(x,p), <, <=, >, >=, ==, !=。逻辑关系符号&&, ||, !

    3. 常用数据类型的建立

    //1. Vector
    NumericVector 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. Matrix
    NumericMatrix M1(nrow,ncol);//创立了一个nrow*ncol的默认初始化的数值型矩阵。
    //3. Multidimensional Array
    NumericVector out=NumericVector(Dimension(2,2,3));//创立了一个多维数组。然而我不知道有什么卵用。。
    //4. List
    NumericMatrix y1(2,2);
    NumericVector y2(5);
    List L=List::create(Named("y1")=y1,
                        Named("y2")=y2);
    
    //5. DataFrame
    NumericVector a=NumericVector::create(1,2,3);
    CharacterVector b=CharacterVector::create("a","b","c");
    std::vector<std::string> 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 <script type="math/tex" id="MathJax-Element-1">i</script>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 <typename T>
    T square( const T& x){
        return x * x ;
    }
    sapply( seq_len(10), square<int> ) ;

    Alternatively, the function can be a functor whose type has a nested type called result_type

    template <typename T>
    struct square : std::unary_function<T,T> {
        T operator()(const T& x){
        return x * x ;
        }
    }
    sapply( seq_len(10), square<int>() ) ;

    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 <Rcpp.h>
    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. 算法

    头文件<algorithm>中提供了许多的算法(可以和迭代器共用),具体可以参见此处。

    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 <algorithm>
    #include <Rcpp.h>
    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<int>, vector<bool>, vector<double>, vector<String>

    元素访问
    利用标准的[]符号访问元素

    元素增加
    利用.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 <Rcpp.h>
    using namespace Rcpp;
    
    // [[Rcpp::export]]
    List rleC(NumericVector x) {
      std::vector<int> lengths;
      std::vector<double> values;
    
      // Initialise first value
      int 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<int>, unordered_set<bool>, 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<double, int> unordered_map<int, double>.

    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型变量global
    Rcpp::NumericVector tmp = global["x"];//获取x
    tmp=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 <Rcpp.h>
    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<double> long_vec2 = conv_to<vector<double>>::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<double> long_vec2 = conv_to<vector<double>>::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<double> func(NumericVector x){
      vector<double> vec;
      vec = as<vector<double>>(x);
      return vec;
    }
    NumericVector func(NumericVector x){
      vector<double> vec;
      vec = as<vector<double>>(x);
      return wrap(vec);
    }
    RObject func(NumericVector x){
      vector<double> vec;
      vec = as<vector<double>>(x);
      return wrap(vec);
    }

    函数返回二维STL vector

    自动转化为R中的list,list中的每个元素是一个vector。

    vector<vector<double>> func(NumericVector x) {
      vector<vector<double>> mat;
      for (int i=0;i!=3;++i){
        mat.push_back(as<vector<double>>(x));
      }
      return mat;
    }
    RObject func(NumericVector x) {
      vector<vector<double>> mat;
      for (int i=0;i!=3;++i){
        mat.push_back(as<vector<double> >(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::field <arma::cube> F(2,1);
      F(0)=A;
      F(1)=B;
      return wrap(F);
    }

    关于“R语言中Rcpp基础知识点有哪些”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。

    向AI问一下细节

    免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

    AI