在此之前,再次感谢Iris2126同学,是他的《【R】提升R代码运算效率的11个实用方法》让我得以展开今天的讨论,现在我还经常看会该篇文章,每每都有些收获。
今天我们延续该文的讨论,但比较的是三种最有效率的方法:C++(Rcpp)、最简向量化、和data.table格式,这三种上面文章中都有提到过,但是都不是最优化的,我根据英文原帖的跟帖高手中一些思路照搬过来了(代码非原创,荣誉归于这两位外国高手)。
1、问题的提出,假设有这么一个data.frame:
- df <- data.frame (col1 = runif (12^6, 0, 2),
- col2 = rnorm (12^6, 0, 2),
- col3 = rpois (12^6, 3),
- col4 = rchisq (12^6, 2))
2、a)Rcpp包加载C++函数:(原帖中的C++代码无法运行,且判断语句不知所云,很可能有错漏,我恶补了Rcpp的知识后稍微改动过,可能是比较低效率的代码,请大神指正)
- // myfunc.cpp
- #include <Rcpp.h>
- using namespace Rcpp;
- //[[Rcpp::export]]
- CharacterVector myFunc(DataFrame x) {
- NumericVector a = x["col1"];
- NumericVector b = x["col2"];
- NumericVector c = x["col3"];
- NumericVector d = x["col4"];
- int nrow = a.size();
- CharacterVector out(nrow);
- for (int i = 0; i < nrow; i++) {
- if (a[i] + b[i] + c[i] + d[i] > 4) {
- out[i] = "greater_than_4";
- } else {
- out[i] = "lesser_than_4";
- }
- }
- return out;
- }
- library(Rcpp)
- sourceCpp("myfunc.cpp")
b)将向量化做到极致:
- myFunR <- function(df) {
- c("greater_than_4", "lesser_than_4")[1L + (df[[1]] + df[[2]] + df[[3]] + df[[4]] <= 4)]
- }
c)用大名鼎鼎的data.table数据结构(返回的是增加了一列的data.table,而非上两种方式中的向量)
- myFundt <- function(df) {
- setDT(df)
- df[, output := "greater_than_4"]
- df[(col1 + col2 + col3 + col4) <= 4, output :="lesser_than_4"]
- }
3、OK,万事俱备,开始测试:
- library(microbenchmark)
- library(data.table)
- dt <- copy(df) # data.table会改变外部环境,所以要单独拷贝一份出来。
- microbenchmark(myFunc(df), myFunR(df), myFundt(dt), times = 30)
4、结果。在揭晓之前,我们来猜猜谁最快?C++?
当然,反正都很快就是了,不过,强中自有强中手,想不到极致向量化的方法比C++更快,而data.table又比极致向量化更快。
具体耗时可能因电脑不同而异,我在两台32位的老电脑上测试过,均是相同的快慢顺序。
5、结论——R语言的潜力我们还根本没有挖掘彻底!静下心来,好好学习吧。


雷达卡




京公网安备 11010802022788号







