R ++函数在C ++循环中

时间:2018-01-03 12:29:17

标签: c++ r

我在R中有一个双循环。它运行良好,但问题是它在大数据帧时运行缓慢。所以我想通过Rcpp包在C ++中进行循环,但在循环中使用R函数。 R循环是:

> output2=list()
> for (j in r){
+   for (i in 1:nrow(DF)){
+     output2[[j]][i]=nrow(subset(DF,eval(parse(text=j))))
+   }
+ }

输出将成为一个列表。 DF和r的一个例子是:

 > r
 [1] "A==A[i] & B==B[i] "           "A==A[i] & C==C[i] "          
 [3] "B==B[i] & C==C[i] "           "A==A[i] & B==B[i] & C==C[i] "
 > DF
    A  B  C
 1 11 22 88
 2 11 22 47
 3  2 30 21
 4  3 30 21

我的问题是如何将表达式放在C ++代码中。另一个问题是这种方式是否比使用C ++编写整个代码更好。 如果有人能帮我解决这个问题,我将不胜感激。 的问候,

2 个答案:

答案 0 :(得分:1)

对于循环在R中不一定很慢。它调用一组函数非常多次,这可能很慢(使用更新版本的R,即使它没有那么慢) )。但是,通过使用速度快很多倍的矢量化代码,通常可以完全避免for循环。

通常不需要使用evalparse,并且通常表示使用了次优解决方案。在这种情况下(不知道完整的问题),我不完全确定如何避免这种情况。然而,通过更有效地写入循环,可以在不使用Rcpp的情况下获得超过20倍的速度增益。

生成数据

r <- c("A==A[i] & B==B[i]", "A==A[i] & C==C[i] ", "B==B[i] & C==C[i] ",
  "A==A[i] & B==B[i] & C==C[i] ")

DF <- read.table(textConnection(" A  B  C
1 11 22 88
2 11 22 47
3  2 30 21
4  3 30 21"))
DF <- DF[sample(nrow(DF), 1E3, replace=TRUE), ]

测量初始实施的时间

> system.time({
+   output2=list()
+   for (j in r){
+    for (i in 1:nrow(DF)){
+      output2[[j]][i]=nrow(subset(DF,eval(parse(text=j))))
+    }
+   }
+ })
   user  system elapsed 
  1.120   0.007   1.127 

预分配结果;在这种情况下没有多大帮助

> system.time({
+   output2=vector(length(r), mode = "list")
+   names(output2) <- r
+   for (j in r){
+     output2[[i]] <- numeric(nrow(DF))
+      for (i in 1:nrow(DF)){
+        output2[[j]][i]=nrow(subset(DF,eval(parse(text=j))))
+      }
+   }
+ })
   user  system elapsed 
  1.116   0.000   1.116 
不需要

子集,因为我们只需要行数。子集终止一个全新的data.frame,它会产生开销

> system.time({
+   output2=vector(length(r), mode = "list")
+   names(output2) <- r
+   for (j in r){
+     output2[[i]] <- numeric(nrow(DF))
+      for (i in 1:nrow(DF)){
+        output2[[j]][i]=sum(eval(parse(text=j), envir = DF))
+      }
+   }
+ })
   user  system elapsed 
  0.622   0.003   0.626 

解析r需要时间并且重复nrow(DF)次,删除形式内循环

> system.time({
+   output2=vector(length(r), mode = "list")
+   names(output2) <- r
+   for (j in r){
+     output2[[i]] <- numeric(nrow(DF))
+     expr <- parse(text=j)
+      for (i in 1:nrow(DF)){
+        output2[[j]][i]=sum(eval(expr, envir = DF))
+      }
+   }
+ })
   user  system elapsed 
  0.054   0.000   0.054 

使用dplyr

实现更可读,更快速的实现
> library(dplyr)
> system.time({
+ output3 <- DF %>% group_by(A,B) %>% mutate(a = n()) %>%
+   group_by(A,C) %>% mutate(b = n()) %>%
+   group_by(B,C) %>% mutate(c = n()) %>%
+   group_by(A,B,C) %>% mutate(d = n()) 
+ })
   user  system elapsed 
  0.010   0.000   0.009 

答案 1 :(得分:0)

我本来希望发表评论,因为它没有完全回答这个问题,但我没有足够的声誉这样做。

R是解释性语言,而C是编译语言。 R中的循环速度很慢,但表达式output2[[j]][i]=nrow(subset(DF,eval(parse(text=j))))至少占执行时间的99%。因此,它不会帮助找到混合两种语言的方法。我建议你保留R并找到加速过程的方法(也许只有一个表达式不同的循环?)或找到一种方法将表达式转换为C表达式。我知道R的许多基本函数都是用C(as you can see here)编码的,也许已经是nrow,subset和parse的情况。

您还可以使用LAPACK / BLAS库来加速某些R功能:

  

LAPACK / BLAS处理R中的矩阵数学。如果你需要的话,你可以找到比R中的vanilla快得多的库(你也可以在R中使用它们来提高性能! )。

stated from this topic from stack overflow