我一直在努力通过Dirk Eddelbuettel的Rcpp
教程:
http://www.rinfinance.com/agenda/
我已经学会了如何在目录中保存C ++文件并调用它并从R中运行它。我运行的C ++文件名为' logabs2.ccp'其内容直接来自Dirk的幻灯片之一:
#include <Rcpp.h>
using namespace Rcpp;
inline double f(double x) { return ::log(::fabs(x)); }
// [[Rcpp::export]]
std::vector<double> logabs2(std::vector<double> x) {
std::transform(x.begin(), x.end(), x.begin(), f);
return x;
}
我用这个R代码运行它:
library(Rcpp)
sourceCpp("c:/users/mmiller21/simple r programs/logabs2.cpp")
logabs2(seq(-5, 5, by=2))
# [1] 1.609438 1.098612 0.000000 0.000000 1.098612 1.609438
我在R GUI中运行Windows 7计算机上的代码,默认情况下似乎是安装的。我还安装了最新版本的Rtools
。上面的R代码似乎需要相对较长的时间才能运行。我怀疑大部分时间都用于编译C ++代码,而且一旦编译C ++代码,它就会非常快速地运行。 Microbenchmark
肯定表明Rcpp
会缩短计算时间。
我从来没有使用过C ++,但我知道当我编译C代码时,我会得到一个* .exe文件。我从名为logabs2.exe
的文件中搜索了我的硬盘驱动器,但找不到一个。我想知道如果创建logabs2.exe
文件,上述C ++代码是否可能运行得更快。是否可以创建一个logabs2.exe
文件并将其存储在某个文件夹中,然后每当我想使用它时让Rcpp调用该文件?我不知道这是否合理。如果我可以在* .exe文件中存储C ++函数,那么每次我想用Rcpp时我都不需要编译该函数,那么Rcpp代码可能会更快。
很抱歉,如果这个问题没有意义或是重复的话。如果可以将C ++函数存储为* .exe文件,我希望有人会告诉我如何修改上面的R代码来运行它。感谢您对此提供任何帮助,或直接告诉我为什么我的建议不可行或不推荐。
我期待看到Dirk的新书。
答案 0 :(得分:6)
感谢user1981275,Dirk Eddelbuettel和Romain Francois的回复。下面是我编译C ++文件并创建* .dll的方法,然后在R
内调用并使用该* .dll文件。
步骤1.我创建了一个名为“c:\ users \ mmiller21 \ myrpackages”的新文件夹,并将文件“logabs2.cpp”粘贴到该新文件夹中。文件'logabs2.cpp'是按我原帖中所述创建的。
步骤2.在新文件夹中,我使用我编写的名为“new package creation.r”的R
文件创建了一个名为“logabs2”的新R
包。 'new package creation.r'的内容是:
setwd('c:/users/mmiller21/myrpackages/')
library(Rcpp)
Rcpp.package.skeleton("logabs2", example_code = FALSE, cpp_files = c("logabs2.cpp"))
我在Hadley Wickham的一个网站上找到了Rcpp.package.skeleton
的上述语法:https://github.com/hadley/devtools/wiki/Rcpp
步骤3.我在DOS命令窗口中使用以下行在R
中安装了新的R
包“logabs2”:
C:\Program Files\R\R-3.0.1\bin\x64>R CMD INSTALL -l c:\users\mmiller21\documents\r\win-library\3.0\ c:\users\mmiller21\myrpackages\logabs2
其中:
rcmd.exe文件的位置是:
C:\Program Files\R\R-3.0.1\bin\x64>
我计算机上安装的R
软件包的位置是:
c:\users\mmiller21\documents\r\win-library\3.0\
以及我的新R
软件包在安装之前的位置是:
c:\users\mmiller21\myrpackages\
DOS命令窗口中使用的语法是通过反复试验找到的,可能并不理想。在某些时候,我在'C:\ Program Files \ R \ R-3.0.1 \ bin \ x64&gt;'中粘贴了'logabs2.cpp'的副本。但我认为这不重要。
步骤4.安装新的R
软件包后,我使用{c> / users / mmiller21 / myrpackages /'文件夹中命名为'new package usage.r'的R
文件运行它(虽然我不认为该文件夹很重要)。 'new package usage.r'的内容是:
library(logabs2)
logabs2(seq(-5, 5, by=2))
输出结果为:
# [1] 1.609438 1.098612 0.000000 0.000000 1.098612 1.609438
此文件在没有我询问的情况下加载了包Rcpp
。
在这种情况下,假设我做得正确,基础R
会更快。
#> microbenchmark(logabs2(seq(-5, 5, by=2)), times = 100)
#Unit: microseconds
# expr min lq median uq max neval
# logabs2(seq(-5, 5, by = 2)) 43.086 44.453 50.6075 69.756 190.803 100
#> microbenchmark(log(abs(seq(-5, 5, by=2))), times=100)
#Unit: microseconds
# expr min lq median uq max neval
# log(abs(seq(-5, 5, by = 2))) 38.298 38.982 39.666 40.35 173.023 100
但是,使用dll文件比调用外部cpp文件更快:
system.time(
cppFunction("
NumericVector logabs(NumericVector x) {
return log(abs(x));
}
")
)
# user system elapsed
# 0.06 0.08 5.85
虽然在这种情况下,基本R看起来比* .dll文件更快或更快,但我毫不怀疑在大多数情况下使用带有Rcpp
的* .dll文件会比基本R
更快案例。
这是我第一次尝试创建R包或使用Rcpp,毫无疑问我没有使用最有效的方法。另外,我为这篇文章中的任何印刷错误道歉。
修改
在下面的评论中,我认为Romain Francois建议我将* .cpp文件修改为以下内容:
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
NumericVector logabs(NumericVector x) {
return log(abs(x));
}
并重新创建我的R
包,我现在已经完成了。然后我使用以下代码将基础R
与我的新包进行比较:
library(logabs)
logabs(seq(-5, 5, by=2))
log(abs(seq(-5, 5, by=2)))
library(microbenchmark)
microbenchmark(logabs(seq(-5, 5, by=2)), log(abs(seq(-5, 5, by=2))), times = 100000)
基础R
仍然快一点或没有差别:
Unit: microseconds
expr min lq median uq max neval
logabs(seq(-5, 5, by = 2)) 42.401 45.137 46.505 69.073 39754.598 1e+05
log(abs(seq(-5, 5, by = 2))) 37.614 40.350 41.718 62.234 3422.133 1e+05
也许这是因为基础R
已经被矢量化了。我怀疑更复杂的函数base R
会慢得多。或许我仍然没有使用最有效的方法,或者我只是在某个地方犯了错误。
答案 1 :(得分:4)
你说
到目前为止我从未使用过C ++,但我知道编译C代码时 我得到一个* .exe文件
如果且仅构建可执行文件,则为真。在这里,我们构建动态可加载库,并根据操作系统构建不同的扩展名:.dll用于Windoze,.so用于Linux,.dynlib用于OS X.
这里没有错,你只是做了错误的假设。
答案 2 :(得分:1)
如果你想获得一些可以保留的实体,那么你需要的是一个R
包。网上有很多资源可以学习如何制作它们(例如Hadley's slides)。
我们可能会发现Rcpp.package.skeleton
有用。
因此,在安装软件包时,该函数会被编译一次,然后您只需使用它。