【问题标题】:R diff function on large dataset大型数据集上的 R diff 函数
【发布时间】:2013-04-27 21:58:28
【问题描述】:

我想在一个非常大的 data.frame 上使用 diff 函数:1.4 亿行和两列。

目标是为每个 user_id 计算两个连续日期活动之间的差距。 对于每个用户,第一个活动没有前一个活动,所以我需要一个 NA 值。

我使用了这个功能,它适用于小数据集,但对于大数据集,它真的很慢。我从昨天开始就在等待,它还在运行。

df2 <- as.vector(unlist(tapply(df$DATE,df$user_id, FUN=function(x){ return (c(NA,diff(x)))})))

我有很多内存 (24GO) 和一个 4 核 CPU,但只有一个在工作。

我们该如何解决这个问题?如果我将数据帧转换为矩阵会更好吗?

【问题讨论】:

  • 我会考虑使用data.table 来解决涉及这种规模的数据集的问题。您将看到将 df 转换为 data.table (DT &lt;- data.table(df)) 的速度显着提高。
  • 将小数据集所花费的时间乘以小数据集与大数据集的比率。已经过去这么多时间了吗?要回答您的其他问题,通常矩阵对象的处理速度比数据框对象快。
  • @CarlWitthoft 矩阵会快得多,但 R 仍会制作数据的后台副本,对吗?这将是一个在如此大的数据集上减慢它的事情。
  • 你能确认你可以在 4 秒内完成(在相同大小的简单向量上)吗?因为这不是我的情况。
  • @SimonO101 确实如此。我的计算至少提供了处理时间的下限。

标签: r dataframe multicore subset


【解决方案1】:

如果您同时避免tapply,这会快很多,这相当容易,因为您的tapply 调用假定数据已经按user_idDATE 排序。

set.seed(21)
N <- 1e6
Data <- data.frame(DATE=Sys.Date()-sample(365,N,TRUE),
                   USER=sample(1e3,N,TRUE))
Data <- Data[order(Data$USER,Data$DATE),]
system.time({
  Data$DIFF <- unlist(tapply(Data$DATE,Data$USER, function(x) c(NA,diff(x))))
})
#   user  system elapsed 
#   1.58    0.00    1.59
Data2 <- Data
system.time({
  Data2$DIFF <- c(NA,diff(Data2$DATE))
  is.na(Data2$DIFF) <- which(c(NA,diff(Data2$USER))==1)
})
#   user  system elapsed 
#   0.12    0.00    0.12
identical(Data,Data2)
# [1] TRUE

【讨论】:

    【解决方案2】:

    这是一个使用示例数据的示例,该数据集最初有 1000 万行,有 100 个用户,diffing 每个有 100,000 个时间点,然后是 1.4 亿行,有 1,400 个用户,所以时间点数相同。这会将时间点转置到列。我应该想象,如果您将用户转移到列中,它会更快。我使用@Arun 's answer here 作为模板。基本上它表明,在一张非常大的桌子上,您可以在

    require(data.table)
    
    ## Smaller sample dataset - 10 million row, 100 users, 100,000 time points each
    DT <- data.table( Date = sample(100,1e7,repl=TRUE) , User = rep(1:100,each=1e5) )
    
    ## Size of table in memory
    tables()
    #    NAME       NROW MB COLS      KEY
    #[1,] DT   10,000,000 77 Date,User    
    #Total: 77MB
    
    
    ## Diff by user
    dt.test <- quote({
        DT2 <- DT[ , list(Diff=diff(c(0,Date))) , by=list(User) ]
        DT2 <- DT2[, as.list(setattr(Diff, 'names', 1:length(Diff))) , by = list(User)]
        })
    
    
    ## Benchmark it
    require(microbenchmark)
    microbenchmark( eval(dt.test) , times = 5L )
    #Unit: seconds
    #         expr      min       lq median       uq      max neval
    # eval(dt.test) 5.788364 5.825788 5.9295 5.942959 6.109157     5
    
    ## And with 140 million rows...
    DT <- data.table( Date = sample(100,1.4e8,repl=TRUE) , User = rep(1:1400,each=1e5) )
    #tables()
    #    NAME        NROW   MB
    #[1,] DT   140,000,000 1069
    
    microbenchmark( eval(dt.test) , times = 1L )
    #Unit: seconds
    #         expr     min      lq  median      uq     max neval
    # eval(dt.test) 84.3689 84.3689 84.3689 84.3689 84.3689     1
    

    【讨论】:

      猜你喜欢
      • 2019-05-25
      • 2017-04-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-15
      • 1970-01-01
      • 2016-08-01
      相关资源
      最近更新 更多