R语言Rcpp包

Rcpp扩展包可以很容易地将C++代码连接到R程序中,并且支持在C++中使用类似于R的数据类型。Rcpp包提供了C++类,这些类极大地促进了使用R提供的.Call接口在R包中连接C或C++代码。Rcpp可以很容易地把C++代码与R程序连接在一起,可以从R中直接调用C++代码而不需要用户关心那些繁琐的编译、链接、接口问题。可以在R数据类型和C++数据类型之间容易地转换。Rcpp支持把C++代码写在R源程序文件内, 执行时自动编译连接调用;也支持把C++代码保存在单独的源文件中, 执行R程序时自动编译连接调用;对较复杂的问题, 应制作R扩展包, 利用构建R扩展包的方法实现C++代码的编译连接,这时接口部分也可以借助Rcpp属性功能或模块功能完成。

1. R程序与由Rcpp支持的C++程序之间的数据转换

1.1. R类型转C++类型

template <typename T> T as(SEXP x);

1.2. C++类型转R类型

template <typename T> SEXP wrap(const T& object);

1.3  R类型转C++类型

不需要显示调用as()和wrap()

2. Rccp包中常见的数据类型及创建
2.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.2  Matrix


NumericMatrix M1(nrow,ncol);//创立了一个nrow*ncol的默认初始化的数值型矩阵。

2.3 Multidimensional Array


NumericVector out=NumericVector(Dimension(2,2,3));//创立了一个多维数组。

2.4 List


NumericMatrix y1(2,2);
NumericVector y2(5);
List L=List::create(Named("y1")=y1,
                    Named("y2")=y2);


2.6 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);

3. R代码与Rcpp包支持的C++代码性能比较

#### C++ 代码可以解决的典型瓶颈:
#### 1. 不容易向量化的循环,后面的迭代依赖前面的结果
#### 2. 递归函数
#### 3.需要R中没有的高级数据结构和算法

testRcpp.cpp代码


#include <Rcpp.h>
using namespace Rcpp;


// [[Rcpp::export]]
double newsum(NumericVector x) {
  double total = 0;
  NumericVector::iterator it;
  for(it = x.begin(); it != x.end(); ++it) {
    total += *it;
  }
  return total;
}


// [[Rcpp::export]]
int fibonacci(int x)
{
  if (x == 1 || x == 2) return 1;
  return fibonacci(x - 1) + fibonacci(x - 2);
}


// [[Rcpp::export]]
NumericMatrix gibbs_cpp(int N,int thin){
  NumericMatrix mat(N,2);
  double x = 0, y = 0;
  for (int i = 0; i < N; i++){
    for (int j = 0; j < thin; j++){
      x = rgamma(1, 3, 1 / (y * y + 4))[0];
      y = rnorm(1, 1 / (x + 1), 1 / sqrt(2 * (x + 1)))[0];
    }
    mat(i,0) = x;
    mat(i,1) = y;
  }
  return (mat);
}

## 3.1 向量求和
aa <- sample(0:1000,1000000, replace = TRUE) # 10到1000之间有放回随机抽样10000个
# aa <- runif(10000,10,100) # 10 到100之间均匀分布的10000个数

start <- Sys.time()
#aa_sum <- newsum(aa)
aa_sum <- sum(aa)
end <- Sys.time()
duration <- end - start
duration
## R语言代码运行的更快!

## 3.2. 求斐波那契数列的第 x 项的函数。
# R语言函数
fibonacci_r <- function(n){
  if (n == 1 || n == 2)
    return (1)
  return (fibonacci_r(n - 1) + fibonacci_r(n - 2))
}

start <- Sys.time()
#result <- fibonacci(30) # 调用C++代码
result <- fibonacci_r(30) # R函数代码
end <- Sys.time()
print (c(paste0("运行时间:", end-start)))
### 0.0083 Vs 0.6789

## 3.3 gibbs采样
gibbs_r <- function(N, thin){
  mat <- matrix(nrow = N, ncol = 2)
  x <- y <- 0
  for (i in 1:N){
    for (j in 1:thin){
      x = rgamma(1, 3, y * y + 4)
      y = rnorm(1, 1 / (x + 1), 1 / sqrt(2 * (x + 1)))
    }
    mat[i,] = c(x,y)
  }
  mat
}
## 注意:R代码和C++代码语法的差异:语句结尾,变量,循环,矩阵取赋值等

# install.packages("microbenchmark")
library(microbenchmark)
microbenchmark(gibbs_r(100,10),gibbs_cpp(100,10)) 

4. Rcpp属性

 Rcpp属性的主要组成部分如下:

  • 在C++中,提供Rcpp::export标注要输出到R中的C++函数。
  • 在R中,提供sourceCpp(), 用来自动编译连接保存在文件或R字符串中的C++代码, 并自动生成界面程序把C++函数转换为R函数。
  • 在R中,提供cppFunction()函数, 用来把保存在R字符串中的C++函数自动编译连接并转换成R函数。 提供evalCpp()函数, 用来把保存在R字符串中的C++代码片段自动编译连接并执行。
  • 在C++中,提供Rcpp::depends标注, 为了sourceCpp()说明编译连接C++代码时需要的外部头文件和库的位置。
  • 在构建R扩展包时,提供compileAttributes() R函数, 自动给C++函数生成相应的 extern C声明和.Call接口代码。

5. Rcpp糖(sugar)


在C++中,向量和矩阵的运算通常需要逐个元素进行, 或者调用相应的函数。 
Rcpp通过C++的表达式模板(expression template)功能和懒惰求值(lazy evaluation)功能, 
可以在C++中写出像R中对向量和矩阵运算那样的向量化表达式。 这称为Rcpp糖(sugar)。

参考:

https://www.math.pku.edu.cn/teachers/lidf/docs/Rbook/html/_Rbook/rcpp.html

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值