我在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 ++编写整个代码更好。 如果有人能帮我解决这个问题,我将不胜感激。 的问候,
答案 0 :(得分:1)
对于循环在R中不一定很慢。它调用一组函数非常多次,这可能很慢(使用更新版本的R,即使它没有那么慢) )。但是,通过使用速度快很多倍的矢量化代码,通常可以完全避免for循环。
通常不需要使用eval
和parse
,并且通常表示使用了次优解决方案。在这种情况下(不知道完整的问题),我不完全确定如何避免这种情况。然而,通过更有效地写入循环,可以在不使用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
> 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中使用它们来提高性能! )。