提升R代码运算效率的11个实用方法

R 是一款优秀的开源统计应用语言,它直观、易用、低成本,而且还有庞大的社区支持。但是当我们利用R语言处理大型数据集时,for循环语句的运算效率总是非常低。本文将介绍几种方法,帮助你以轻松地处理1亿行以上的数据集。 2016-02-15 09:25:00 R语言运算效率大数据 【专题】可视化技术 展现大数据之美 原创 想要理解大数据,使之更贴近大多数人,最重要的手段的之一就是数据可视化。数据可视化标识导向系统,包括文字的,如街头的路标指引你到高速公路,还有象征的,如颜色、大小或位置的抽象元素传达的信息等。 2016-02-02 16:07:32 可视化大数据数据可视化 Cloudera:2016年Hadoop的三大预测 众所周知,2015年又是Apache Hadoop标志性的一年。就在我们认为2015年就这样过去了,真正的Hadoop时代却来临了,我们有很多事情需要继续做下去。我们看到Apache Spark已经成为主流 ,Kudu(孵化中)的全新储存能力也加入进来,安全也更加卓越。难以想像后面还会有什么,但这正是Hadoop的美妙之处:永不止步、无限可能。至于结果,我们总是惊奇地拭目以待。 2016-02-01 15:32:03 HadoopCloudera 数据挖掘领域十大经典算法 本文介绍了ICDM早前评选出的数据挖掘领域的十大经典算法。便拿出一种来都可以说,它在数据挖掘领域都产生了极为深远的影响。让我们通过本文了解一下。 2016-01-29 11:00:55 数据挖掘算法大数据 美团是如何通过优化搜索排序提升转化效果的 和传统网页搜索问题相比,美团的搜索排序有自身的特点——90%的交易发生在移动端。一方面,这对排序的个性化提出了更高的要求;另一方面,我们由此积累了用户在客户端上丰富准确的行为,经分析获得用户的地理位置、品类和价格等偏好,进而指导个性化排序。

R 是一款优秀的开源统计应用语言,它直观、易用、低成本,而且还有庞大的社区支持。但是当我们利用R语言处理大型数据集时,for循环语句的运算效率总是非常低。本文将介绍几种方法,帮助你以轻松地处理1亿行以上的数据集。

众所周知,当我们利用R语言处理大型数据集时,for循环语句的运算效率非常低。有许多种方法可以提升你的代码运算效率,但或许你更想了解运算效率能得到多大的提升。本文将介绍几种适用于大数据领域的方法,包括简单的逻辑调整设计、并行处理和Rcpp的运用,利用这些方法你可以轻松地处理1亿行以上的数据集。

[[162790]]

让我们尝试提升往数据框中添加一个新变量过程(该过程中包含循环和判断语句)的运算效率。下面的代码输出原始数据框:

# Create the data frame
col1 <- runif (12^5, 0, 2)
col2 <- rnorm (12^5, 0, 2)
col3 <- rpois (12^5, 3)
col4 <- rchisq (12^5, 2)
df <- data.frame (col1, col2, col3, col4)

逐行判断该数据框(df)的总和是否大于4,如果该条件满足,则对应的新变量数值为’greaterthan4’,否则赋值为’lesserthan4’。

# Original R code: Before vectorization and pre-allocation
system.time({
for (i in 1:nrow(df)) { # for every row
if ((df[i, 'col1'] + df[i, 'col2'] + df[i, 'col3'] + df[i, 'col4']) > 4) { # check if > 4
df[i, 5] <- "greater_than_4" # assign 5th column
} else {
df[i, 5] <- "lesser_than_4" # assign 5th column
}
}
})

本文中所有的计算都在配置了2.6Ghz处理器和8GB内存的MAC OS X中运行。

1.向量化处理和预设数据库结构

循环运算前,记得预先设置好数据结构和输出变量的长度和类型,千万别在循环过程中渐进性地增加数据长度。接下来,我们将探究向量化处理是如何提高处理数据的运算速度。

# after vectorization and pre-allocation
output <- character (nrow(df)) # initialize output vector
system.time({
for (i in 1:nrow(df)) {
if ((df[i, 'col1'] + df[i, 'col2'] + df[i, 'col3'] + df[i, 'col4']) > 4) {
output[i] <- "greater_than_4"
} else {
output[i] <- "lesser_than_4"
}
}
df$output})

2.将条件语句的判断条件移至循环外

将条件判断语句移至循环外可以提升代码的运算速度,接下来本文将利用包含100,000行数据至1,000,000行数据的数据集进行测试:

# after vectorization and pre-allocation, taking the condition checking outside the loop.
output <- character (nrow(df))
condition <- (df$col1 + df$col2 + df$col3 + df$col4) > 4  # condition check outside the loop
system.time({
for (i in 1:nrow(df)) {
if (condition[i]) {
output[i] <- "greater_than_4"
} else {
output[i] <- "lesser_than_4"
}
}
df$output <- output
})

3.只在条件语句为真时执行循环过程

另一种优化方法是预先将输出变量赋值为条件语句不满足时的取值,然后只在条件语句为真时执行循环过程。此时,运算速度的提升程度取决于条件状态中真值的比例。

本部分的测试将和case(2)部分进行比较,和预想的结果一致,该方法确实提升了运算效率。

output <- c(rep("lesser_than_4", nrow(df)))
condition <- (df$col1 + df$col2 + df$col3 + df$col4) > 4
system.time({
for (i in (1:nrow(df))[condition]) {  # run loop only for true conditions
if (condition[i]) {
output[i] <- "greater_than_4"
}
}
df$output
})

4.尽可能地使用 ifelse()语句

利用ifelse()语句可以使你的代码更加简便。ifelse()的句法格式类似于if()函数,但其运算速度却有了巨大的提升。即使是在没有预设数据结构且没有简化条件语句的情况下,其运算效率仍高于上述的两种方法。

system.time({
output <- ifelse ((df$col1 + df$col2 + df$col3 + df$col4) > 4, "greater_than_4", "lesser_than_4")
df$output <- output
})

5.使用 which()语句

利用which()语句来筛选数据集,我们可以达到Rcpp三分之一的运算速率。

# Thanks to Gabe Becker
system.time({
want = which(rowSums(df) > 4)
output = rep("less than 4", times = nrow(df))
output[want] = "greater than 4"
})
# nrow = 3 Million rows (approx)
user  system elapsed
0.396   0.074   0.481

6.利用apply族函数来替代for循环语句

本部分将利用apply()函数来计算上文所提到的案例,并将其与向量化的循环语句进行对比。该方法的运算效率优于原始方法,但劣于ifelse()和将条件语句置于循环外端的方法。该方法非常有用,但是当你面对复杂的情形时,你需要灵活运用该函数。

# apply family
system.time({
myfunc <- function(x) {
if ((x['col1'] + x['col2'] + x['col3'] + x['col4']) > 4) {
"greater_than_4"
} else {
"lesser_than_4"
}
}
output <- apply(df[, c(1:4)], 1, FUN=myfunc)  # apply 'myfunc' on every row
df$output <- output
})

7.利用compiler包中的字节码编译函数cmpfun()

这可能不是说明字节码编译有效性的***例子,但是对于更复杂的函数而言,字节码编译将会表现地十分优异,因此我们应当了解下该函数。

# byte code compilation
library(compiler)
myFuncCmp <- cmpfun(myfunc)
system.time({
output <- apply(df[, c (1:4)], 1, FUN=myFuncCmp)
})

8.利用Rcpp

截至目前,我们已经测试了好几种提升运算效率的方法,其中***的方法是利用ifelse()函数。如果我们将数据量增大十倍,运算效率将会变成啥样的呢?接下来我们将利用Rcpp来实现该运算过程,并将其与ifelse()进行比较。

library(Rcpp)
sourceCpp("MyFunc.cpp")
system.time (output <- myFunc(df)) # see Rcpp function below

下面是利用C++语言编写的函数代码,将其保存为“MyFunc.cpp”并利用sourceCpp进行调用。

  1. //SourceforMyFunc.cpp
  2. #include
  3. usingnamespaceRcpp;
  4. //[[Rcpp::export]]
  5. CharacterVectormyFunc(DataFramex){
  6. NumericVectorcol1=as(x["col1"]);
  7. NumericVectorcol2=as(x["col2"]);
  8. NumericVectorcol3=as(x["col3"]);
  9. NumericVectorcol4=as(x["col4"]);
  10. intn=col1.size();
  11. CharacterVectorout(n);
  12. for(inti=0;i4){
  13. out[i]="greater_than_4";
  14. }else{
  15. out[i]="lesser_than_4";
  16. }
  17. }
  18. returnout;
  19. }

9.利用并行运算

并行运算的代码:

# parallel processing
library(foreach)
library(doSNOW)
cl <- makeCluster(4, type="SOCK") # for 4 cores machine
registerDoSNOW (cl)
condition <- (df$col1 + df$col2 + df$col3 + df$col4) > 4
# parallelization with vectorization
system.time({
output <- foreach(i = 1:nrow(df), .combine=c) %dopar% {
if (condition[i]) {
return("greater_than_4")
} else {
return("lesser_than_4")
}
}
})
df$output <- output

10.尽早地移除变量并恢复内存容量

在进行冗长的循环计算前,尽早地将不需要的变量移除掉。在每次循环迭代运算结束时利用gc()函数恢复内存也可以提升运算速率。

11.利用内存较小的数据结构

data.table()是一个很好的例子,因为它可以减少数据的内存,这有助于加快运算速率。

dt <- data.table(df)  # create the data.table
system.time({
for (i in 1:nrow (dt)) {
if ((dt[i, col1] + dt[i, col2] + dt[i, col3] + dt[i, col4]) > 4) {
dt[i, col5:="greater_than_4"]  # assign the output as 5th column
} else {
dt[i, col5:="lesser_than_4"]  # assign the output as 5th column
}
}
})

总结

方法:速度, nrow(df)/time_taken = n 行每秒

1.原始方法:1X, 856.2255行每秒(正则化为1)

2.向量化方法:738X, 631578行每秒

3.只考虑真值情况:1002X,857142.9行每秒

4.ifelse:1752X,1500000行每秒

5.which:8806X,7540364行每秒

6.Rcpp:13476X,11538462行每秒

©本文为清一色官方代发,观点仅代表作者本人,与清一色无关。清一色对文中陈述、观点判断保持中立,不对所包含内容的准确性、可靠性或完整性提供任何明示或暗示的保证。本文不作为投资理财建议,请读者仅作参考,并请自行承担全部责任。文中部分文字/图片/视频/音频等来源于网络,如侵犯到著作权人的权利,请与我们联系(微信/QQ:1074760229)。转载请注明出处:清一色财经

(0)
打赏 微信扫码打赏 微信扫码打赏 支付宝扫码打赏 支付宝扫码打赏
清一色的头像清一色管理团队
上一篇 2023年5月7日 00:13
下一篇 2023年5月7日 00:13

相关推荐

发表评论

登录后才能评论

联系我们

在线咨询:1643011589-QQbutton

手机:13798586780

QQ/微信:1074760229

QQ群:551893940

工作时间:工作日9:00-18:00,节假日休息

关注微信