让你的R代码更快——Rcpp入门

当我们使用R进行论文模拟时,通常会涉及到许多的循环。一般比较容易的提速方法是将我们的for循环改写为apply族的方法进行向量化运算,但这个方法速度提升的有限,在真实模拟时,如果要与其他算法进行速度的比较,除非自己的算法非常出色,否则还是很难与一些成熟包中的算法相庭抗礼。

这时想要再次进行提速,有多种方法,常见的几种是将代码改写为Fortran代码,改写为C++代码抑或改写为C代码。由于Rcpp包的存在,改写为C++代码相对简单,所以后面将介绍几种常用的方法进行改写,并在R中进行调用。


在RStudio中创建C++文件

这里默认大家都安装了RStudio,我们都从里面创建一个C++文件,从这里创建有个好处,就是它直接会显示一段示例代码,我们只需在上面稍作改动即可。

首先我们在RStudio中选择:文件——新文件——C++文件,创建完一个新文件,里面是如下的内容(这里要在R中安装Rcpp包,没安装的话,点到这里RStudio会自动帮忙进行安装):

#include 
using namespace Rcpp;

// This is a simple example of exporting a C++ function to R. You can
// source this function into an R session using the Rcpp::sourceCpp 
// function (or via the Source button on the editor toolbar). Learn
// more about Rcpp at:
//
//   http://www.rcpp.org/
//   http://adv-r.had.co.nz/Rcpp.html
//   http://gallery.rcpp.org/
//

// [[Rcpp::export]]
NumericVector timesTwo(NumericVector x) {
  return x * 2;
}


// You can include R code blocks in C++ files processed with sourceCpp
// (useful for testing and development). The R code will be automatically 
// run after the compilation.
//

/*** R
timesTwo(42)
*/

我们按照上面的英文说明一行一行来进行理解。


详细说明

#include 
using namespace Rcpp;

这个是头文件,以及使用Rcpp命名空间。正常的一个C++代码开头两行其实也是这样,这其实非常像我们R中的library以及Python中的import,有了这个,我们就可以在代码中命名向量、矩阵、数据框等一些R中才有的对象形式,以便于R与C++中的一些内容的相互传递。

示例文件中的代码其实就是命名了一个输入与输出对象均为数值向量的函数。这个函数也非常简单:一个将向量乘以2的运算

如果我们想在R中使用在C++文件中定义好的函数,需要在C++里面函数的上方加上// [[Rcpp::export]]。需要注意的是,一个cpp文件可以在里面定义多个函数,但只能传出一个函数。

然后我们再点击文件右上方的Source,即可将我们的函数载入进变量空间,或直接在另一个R脚本文件中运行下述命令:

Rcpp::sourceCpp('Desktop/myfun.cpp')

在示例文件中还有另一个trick,就是直接在我们的cpp文件中加上了下面这句命令:

/*** R
timesTwo(42)
*/

加上这句之后,我们Source这个文件后,可以直接测试刚刚定义的函数,看看timesTwo(42)的运行结果,平时在测试的时候可以多多使用。


更多内容

关于Rcpp里面的一些常用数据类型与常用函数,可以参考博客:Rcpp相关知识整理,里面讲的很好。这里搬运一些内容过来:

数据类型 描述
int 整数型
double 数值型
bool 布尔型(TRUE, FALSE)
String 字符型
IntegerVector 整型向量
NumericVector 数值型向量(元素的类型为double)
ComplexVector 复数向量
LogicalVector 逻辑型向量; R的逻辑型变量可以取三种值:TRUE, FALSE, NA; 而C++布尔值只有两个,true or false。如果将R的NA转化为C++中的布尔值,则会返回true。
CharacterVector 字符型向量
IntegerMatrix 整型矩阵
NumericMatrix 数值型矩阵(元素的类型为double)
LogicalMatrix 逻辑型矩阵
CharacterMatrix 字符矩阵
List 列表;lists;类似于R中列表,其元素可以使任何数据类型
DataFrame 数据框;data frames;在Rcpp内部,数据框其实是通过列表实现的
Function 函数型
Environment 环境型;可用于引用R环境中的函数、其他R包中的函数、操作R环境中的变量
RObject 可以被R识别的类型

关于对矩阵以及数据框的一些基础操作与常用函数:

操作 描述
[n] 对于向量类型或者列表,访问第n个元素。对于矩阵类型,首先把矩阵的下一列接到上一列之下,从而构成一个长列向量,并访问第n个元素。不同于R,n从0开始。
(i,j) 对于矩阵类型,访问第(i,j)个元素。不同于R,i和j从0开始。不同于向量,此处用圆括号。
List[“name1”] 访问List中名为name1的元素。
DataFrame[“name2”] 访问DataFrame中,名为name2的列。
X.size() 返回X的长度;适用于向量或者矩阵,如果是矩阵,则先向量化
X.push_back(a) 将a添加进X的末尾;适用于向量
X.push_front(b) 将b添加进X的开头;适用于向量
X.ncol() 返回X的列数
X.nrow() 返回X的行数

总结

到这里,一些关于Rcpp基础使用的相关内容就介绍的差不多了。

还有另外两个网址也非常推荐:

  1. http://adv-r.had.co.nz/Rcpp.html
  2. http://gallery.rcpp.org

前者里面有很多基础操作的代码,包括:向量->向量向量->矩阵标量->矩阵等等,里面都有示例函数及相关代码,复制到自己的cpp文件中运行并理解就很容易上手。

后者相当于一个搜索库,要使用Rcpp进行矩阵运算、并行计算、常用算法等操作,直接在里面进行搜索,就可以看到大神写的一些相应代码,同时知道该调用哪些库中的函数。

后面的博客中我们将介绍:利用RcppEigen进行矩阵运算

你可能感兴趣的:(R)