||
基于Rcpp建立一个整合C++函数的R程序包
张金龙
2014年10月15日
R程序包轻巧简洁, 便于算法上的开发。 但是R函数的运行速度较慢, 在进行迭代计算或者蒙特卡罗马尔科夫链时,常常不能满足要求。 此外, 由于用C或者C++已经有很多算法库, 人们希望将这些库中的函数直接调用。Rcpp正是为了让R开发者更方便地运用C++函数而诞生。 本文简要介绍如何编写一个含有C++函数的R程序包。
创建R程序包, 首先要安装
R软件(http://cran.r-project.org/bin/windows/base/R-3.1.1-win.exe ),
Rtools (http://cran.r-project.org/bin/windows/Rtools/Rtools31.exe ), 以及
Miktex (http://miktex.org/2.9/setup/)之后,
R需要安装 Rcpp (http://cran.r-project.org/web/packages/Rcpp/index.html )程序包。
并配置好启动 路径, 即将所需要的任何exe文件的路径, 拷贝到 电脑>属性>高级系统设置>高级>环境变量>系统变量>路径 中 如:
c:Rtoolsbin;c:Rtoolsgcc-4.6.3bin;C:Program FilesRR-3.1.1bin;C:Program FilesRR-3.1.1binx64;C:Program FilesRR-3.1.1bini386;C:CTEXUserDatamiktexbin;C:CTEXMiKTeXmiktexbin;C:CTEXCTeXctexbin;C:CTEXCTeXcctbin;C:CTEXCTeXtybin;C:CTEXGhostscriptgs9.05bin;
此外, 这里假设读者使用文本编辑器 Notepad++ 。
Rcpp程序包提供了多种C++的类模板, 可以让C++函数返回多种R对象。
假设现有一个C++函数, 名叫Eccentricity,该函数用于天文计算中, 计算某天体的轨道偏心率随时间的变化, 其输入的参数为儒略日(日期的某种记录方法), 在正常的C++语法中, 该函数定义如下:
Double Eccentricity(double JD)
{
double JD3 = JD;
double T = (JD3 - 2451545.0) / 36525.0;
double Tsquared = T*T;
return ((1 - 0.002516*T - 0.0000074*Tsquared));
}
现在我们需要有一个Rcpp形成的包骨架(package skeleton), 名叫 skycalc:
在R中运行如下命令生成基于Rcpp的R包骨架
library(Rcpp)
Rcpp.package.skeleton( "skycalc" )
getwd()
skycalc保存在getwd()所示的文件夹下, 有 man, R, src三个文件夹, 以及DESCRIPTION以及 NAMESPACE 以及 Read-and-delete-me 三个文本文件,这个三个文件没有任何扩展名。
man下面, 保存的是所有R函数以及R程序包的帮助文件文件, 遵循是Latex格式。需要逐项填写
R下面, 保存的是R函数的文件, 每个R函数单独一个文件
src下面, 放的是cpp文件, 即c++的源文件
默认的情况下,
man文件夹下, 会有 rcpp_hello_world.Rd 文件,
R文件夹下, 会有RcppExports.R文件
src 文件夹下, 会有 rcpp_hello_world.cpp 和 RcppExports.cpp两个C++源文件
这些文件在本例中均可以删除。
我们的目标是: 将Eccentricity函数,放在C++源代码中, 假设文件为Eccentricity.cpp的纯文本文件。 为了能够在R中直接调用该函数, 将其参数数据类型, 以及返回值的数据 类型更改为R能够识别的格式。因为R只能识别一种称为SEXP的数据类型, 所以这里做如下更改:
RcppExport SEXP Eccentricity(SEXP JD)
{
double JD3 = Rcpp::as<double>(JD);
double T = (JD3 - 2451545.0) / 36525.0;
double Tsquared = T*T;
return (wrap(1 - 0.002516*T - 0.0000074*Tsquared));
}
在类型前,更加上RcppExport, 返回值则 用wrap函数, 可直接返回为SEXP 数据类型。
加上引用的头文件说明:
#include <Rcpp.h>
using namespace Rcpp;
using namespace std;
此时, Eccentricity.cpp文件内容如下:
///////////////cpp文件开始//////////////////////
#include <Rcpp.h>
using namespace Rcpp;
using namespace std;
RcppExport SEXP Eccentricity(SEXP JD)
{
double JD3 = Rcpp::as<double>(JD);
double T = (JD3 - 2451545.0) / 36525.0;
double Tsquared = T*T;
return (wrap(1 - 0.002516*T - 0.0000074*Tsquared));
}
///////////////cpp文件结束//////////////////////
这样 Eccentricity.cpp 文件就准备好了,放在src文件夹中。
为了能够在R中调用编译后的C++函数,可使用R的.Call()函数, 调用dll库(cpp文件经过编译后, 在Windows下转变为dll文件)。但为了更为 方便地使用这些函数,一般为调用过程写一个类似的R函数, 名称和C++函数相仿,包括参数名等。为此,我们我们可以写一个R函数EccentricityR, 该R函数可定义如下:
EccentricityR <- function(JD) {
.Call('Eccentricity', JD, PACKAGE = 'skycalc')
}
其中JD为该R函数的参数, 直接通过.Call传递给Dll中的Eccentricity。
在Notepad++中,拷贝以上R函数, 并且另存为 EccentricityR.R 文件, 放在 skycalc程序包下的 R文件夹下。
为了生成该EccentricityR函数的帮助文件, 需要将该函数粘贴到R console中, 之后运行R命令 prompt(EccentricityR),所形成的EccentricityR.Rd 文件需要进一步根据 参数的意义填写和编辑。之后放到man文件夹下。
编辑和填写 DESCRIPTION以及NAMESPACE 两个文本文件。删除 Read-and-delete-me文件。这样,程序包的源文件就做好了。
下面准备编译或安装R程序包的命令, 运行以下命令
(1)新建一个纯文本文件,并将扩展名txt更改为.bat
将以下内容拷贝到该文件夹中
Rcmd check skycalc
PAUSE
将该文件命名为 check skycalc package.bat, 双击该bat文件, 可以对skycalc程序包中的错误进行检查。 如果要提交程序包到CRAN, 检查过程中不能有任何错误或者warning。
(2)新建一个纯文本文件,并将扩展名txt更改为.bat
将以下内容拷贝到该文件夹中
Rcmd INSTALL --build skycalc
PAUSE
将该文件命名为 build skycalc package Windows Binary.bat, 双击该文件, 可以建立Windows系统下的R程序包。
(3)新建一个纯文本文件,并将扩展名txt更改为.bat
将以下内容拷贝到该文件夹中
Rcmd build skycalc
pause
将该文件命名为 build skycalc package Linux Source Code.bat, 双击该文件, 可以建立Linux系统下的安装包, 其实是源文件。
(4)新建一个纯文本文件,并将扩展名txt更改为.bat
将以下内容拷贝到该文件夹中
Rcmd INSTALL skycalc
PAUSE
将该文件命名为 install skycalc package.bat, 双击该文件, 可以安装skycalc到当前的R中。
将以上四个.bat文件, 放置到skycalc文件夹所在的文件夹(例如, skycalc所 在的文件夹为study, 则bat文件需要放置在study文件夹下)
双击文件, 即可完成程序包的编译和检查等。
注意: 如果使用的64bit的Windows,源代码 skycalc文件夹下, 每次都会生成 src-x64 和 src-i386两个文件夹, 在编译linux源代码的时候, 需要删除。
参考:
http://cos.name/2013/12/rcpp-introduction/
http://cran.r-project.org/web/packages/Rcpp/
http://adv-r.had.co.nz/Rcpp.html
Archiver|手机版|科学网 ( 京ICP备07017567号-12 )
GMT+8, 2024-12-26 16:14
Powered by ScienceNet.cn
Copyright © 2007- 中国科学报社