我想在一个非常大的data.frame上使用diff函数:140万行和两列。
目标是为每个user_id计算两个连续日期活动之间的差距。 对于每个用户,第一个活动没有前一个活动,因此我需要一个NA值。
我使用了这个函数,它适用于小数据集,但是对于大数据集,它确实很慢。我从昨天开始等待,现在还在运行。
df2 <- as.vector(unlist(tapply(df$DATE,df$user_id, FUN=function(x){ return (c(NA,diff(x)))})))
我有很多内存(24GO)和4核CPU,但只有一个正在运行。
我们如何才能解决这个问题?如果我将数据帧转换为矩阵会更好吗?
答案 0 :(得分:4)
这是一个使用数据集的示例数据的示例,该数据集最初为1000万行,有100个用户,每个diff
100,000个时间点,然后是1.4亿行,有1,400个用户,所以时间点数相同。这会将时间点转换为列。我应该想象如果你将用户转换为列,它会更快。我使用@Arun 's answer here作为模板。基本上它表明,在一个非常大的桌子上,你可以在单个核心(i7 2.6 GhZ)上进行&lt; 90秒(这是使用可能没有完全失效的代码):
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
答案 1 :(得分:2)
如果您完全避免使用tapply
,这会快得多,这相当容易,因为您的tapply
调用假设数据已经按user_id
和DATE
排序。
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