更有效的方式在R中进行有条件的运行总计

时间:2014-03-07 19:17:19

标签: r loops running-total

由于这是我第一次在SO上提问,我提前为任何不正确的格式化道歉。

我是R的新手,我正在尝试创建一个函数,一旦另一列中的运行总计达到或超过给定值(运行总和开始的行),它将返回数据框列的行值也是一个论点。

例如,给定以下数据框,如果给定起始参数x = 3且停止参数y = 17,则该函数应返回5(行的x值,其中y>的总和= 17 )。

X   Y
1   5
2   10
3   5
4   10
5   5
6   10
7   5
8   10

我目前编写的函数返回正确的答案,但我必须相信有更多的“R-ish”方法来实现这一点,而不是使用循环和递增临时变量,并希望学会正确的方法,而不是形成我以后必须纠正的坏习惯。

该功能的一个非常简化的版本:

myFunction<-function(DataFrame,StartRow,Total){
    df<-DataFrame[DataFrame[[1]] >= StartRow,]
    i<-0
    j<-0

    while (j < Total) {
        i<-i+1
        j<-sum(df[[2]][1:i])
    }

    x<-df[[1]][i]
    return(x)
}

5 个答案:

答案 0 :(得分:4)

到目前为止发布的所有解决方案都计算整个Y变量的累积和,在数据帧非常大但索引接近开头的情况下,这可能是低效的。在这种情况下,使用Rcpp的解决方案可能更有效:

library(Rcpp)
get_min_cum2 = cppFunction("
int gmc2(NumericVector X, NumericVector Y, int start, int total) {
    double running = 0.0;
    for (int idx=0; idx < Y.size(); ++idx) {
        if (X[idx] >= start) {
            running += Y[idx];
            if (running >= total) {
                return X[idx];
            }
        }
    }
    return -1;  // Running total never exceeds limit
}")

与microbenchmark的比较:

get_min_cum <- 
 function(start,total) 
   with(dat[dat$X>=start,],X[min(which(cumsum(Y)>total))])
get_min_dt <- function(start, total)
   dt[X >= start, X[cumsum(Y) >= total][1]]

set.seed(144)
dat = data.frame(X=1:1000000, Y=abs(rnorm(1000000)))
dt = data.table(dat)
get_min_cum(3, 17)
# [1] 29
get_min_dt(3, 17)
# [1] 29
get_min_cum2(dat$X, dat$Y, 3, 17)
# [1] 29

library(microbenchmark)
microbenchmark(get_min_cum(3, 17), get_min_dt(3, 17),
               get_min_cum2(dat$X, dat$Y, 3, 17))
# Unit: milliseconds
#                               expr        min         lq    median         uq      max neval
#                 get_min_cum(3, 17) 125.324976 170.052885 180.72279 193.986953 418.9554   100
#                  get_min_dt(3, 17) 100.990098 149.593250 162.24523 176.661079 399.7531   100
#  get_min_cum2(dat$X, dat$Y, 3, 17)   1.157059   1.646184   2.30323   4.628371 256.2487   100

在这种情况下,使用Rcpp解决方案比其他方法快约100倍。

答案 1 :(得分:1)

试试这个例子,我正在使用cumsum和矢量化逻辑子集:

 get_min_cum <- 
 function(start,total) 
   with(dat[dat$X>=start,],X[min(which(cumsum(Y)>total))])

 get_min_cum(3,17) 
 5

答案 2 :(得分:1)

在这里(由于语法简单,使用data.table):

library(data.table)
dt = data.table(df)

dt[X >= 3, X[cumsum(Y) >= 17][1]]
#[1] 5

答案 3 :(得分:1)

嗯,这是一种方式:

i <- 3
j <- 17
min(df[i:nrow(df),]$X[cumsum(df$Y[i:nrow(df)])>j])
# [1] 5

df$Xi:nrow(df)和基于cumsum(df$Y) > j的索引,从第i行开始。这将返回df$X的所有cumsum > jmin(...)然后返回最小值。

答案 4 :(得分:1)

with(df, which( cumsum( (x>=3)*y) >= 17)[1] )