【问题标题】:Speeding up For loop for large dataframe为大型数据帧加速 For 循环
【发布时间】:2013-07-26 14:39:07
【问题描述】:

我有一个非常大的数据框,我的目标是按用户 ID 列出累积的美元。数据框看起来像这样,但要大得多:

dt<-sample(seq(as.Date("2013-01-01"),as.Date("2013-05-01"),by="days"),10)
s<-c(rep(5252525,5),rep(1313131,5))
usd<-round(rnorm(10,100),2)
money<-data.frame(dt,s,usd)
money<-money[order(money$dt),]
money$Cumulative<-NA
users<-unique(money$s)

我从 for 循环开始,但速度很慢:

for (i in 1:length(users)){
    temp=which(money$s==users[i])
    money$Cumulative[temp]=cumsum(money$usd[temp])
}

我在 StackOverflow 上读到我可以使用 data.table 来提高整体速度,这在一定程度上有所帮助:

money<-data.table(money)
setkey(money,s)

for (i in 1:length(users)){
    temp=which(money$s==users[i])
    money$Cumulative[temp]=cumsum(money$usd[temp])
}

我想让这个计算更快。接下来我该怎么做?

【问题讨论】:

    标签: r performance for-loop data.table


    【解决方案1】:

    由于money 已经被dt 列排序,您可以直接使用ave:

    money$Cumulative <- ave(money$usd, money$s, FUN=cumsum)
    

    或者你可以使用data.table:

    moneyDT <- as.data.table(money[,1:3])
    moneyDT[,cumulative := cumsum(usd), by=s]
    

    【讨论】:

    • ave() 函数为我节省了大量的计算机时间。谢谢!
    【解决方案2】:

    听起来您正在寻找data.table 选项。

    使用 Joshua 提出的方法并指出使用玩具数据可能会产生误导(即类似的方法对最小数据集 lil_money 的性能相似,但对于更现实的数据集 money 则不然):

    结果

    Unit: microseconds
                  expr     min      lq  median      uq       max neval
     useAve(lil_money) 694.269 730.491 741.358 756.753 13687.951  1000
      useBy(lil_money) 709.664 748.603 759.470 775.770  5341.338  1000
    
    Unit: milliseconds
              expr       min        lq    median        uq       max neval
     useAve(money) 3940.8970 3966.0950 4002.4319 4090.3967 4145.2672    10
      useBy(money)  105.7129  106.5789  109.6566  117.2939  122.1414    10
    
    Identical output: TRUE
    

    代码

    require(microbenchmark)
    require(data.table)
    
    start <- as.Date("2001-01-01")
    money <- CJ(s=1:1e4, dt=start + 0:1e3)[, usd := runif(.N)]
    
    lil_money <- money[s < 10 & dt < start + 10]
    
    useAve <- function(DT) { DT[, cum_ave := ave(usd, s, FUN=cumsum)] }
    useBy <- function(DT) { DT[, cum_by := cumsum(usd), by=s] }
    
    print(microbenchmark(useAve(lil_money), useBy(lil_money),  times=1000))
    print(microbenchmark(useAve(money), useBy(money),  times=10))
    
    cat("Identical output:", identical(money$cum_ave, money$cum_by))
    

    【讨论】:

      猜你喜欢
      • 2021-06-29
      • 1970-01-01
      • 2016-12-19
      • 1970-01-01
      • 1970-01-01
      • 2021-09-03
      • 2021-09-26
      • 2021-03-04
      • 1970-01-01
      相关资源
      最近更新 更多