R 使用data.table从重叠日期计算活动天数

R 使用data.table从重叠日期计算活动天数,r,date,data.table,lubridate,R,Date,Data.table,Lubridate,我正在尝试使用data.tablepackage或其他有效处理大数据(1400-2200万行)的解决方案来解决我发布的问题。关于如何加快此解决方案或找到更快的解决方法,有何提示 test replications elapsed relative 1 yourFunction(d) 1 10.22 340.667 2 myFunction3(d) 1 0.03 1.000 非常感谢你的帮助 1)让数据相乘

我正在尝试使用
data.table
package或其他有效处理大数据(1400-2200万行)的解决方案来解决我发布的问题。关于如何加快此解决方案或找到更快的解决方法,有何提示

             test replications elapsed relative
1 yourFunction(d)            1   10.22  340.667
2  myFunction3(d)            1    0.03    1.000
非常感谢你的帮助

1)让数据相乘:

d <- replicate(1e2, data, simplify = F)
d <- rbindlist(d, use.names = T, fill = T, idcol = T)
d[, user_id := paste0(user_id, .id)]
      .id user_id start_date   end_date
   1:   1     121 2010-10-31 2011-10-31
   2:   1     121 2010-12-18 2011-12-18
   3:   1     121 2011-10-31 2014-04-28
   4:   1     121 2011-12-18 2014-12-18
   5:   1     121 2014-03-27 2015-03-27
  ---                                  
1296: 100   33100 1992-07-01 2016-07-01
1297: 100   33100 1993-08-20 2016-08-16
1298: 100   33100 1999-10-28 2012-11-15
1299: 100   33100 2006-01-31 2006-02-28
1300: 100   33100 2016-08-26 2017-01-26
             test replications elapsed relative
1 yourFunction(d)            1   10.22  340.667
2  myFunction3(d)            1    0.03    1.000
3) 测试结果是否相等:

setDT(rez1)
setorder(rez1, user_id)
setorder(rez2, user_id)
all.equal(rez1, rez2)
[1] TRUE
             test replications elapsed relative
1 yourFunction(d)            1   10.22  340.667
2  myFunction3(d)            1    0.03    1.000
4) 基准:

cols <- c("test", "replications", "elapsed", "relative")
rbenchmark::benchmark(yourFunction(d),
                      myFunction(d), replications = 1, columns = cols)
             test replications elapsed relative
1 yourFunction(d)            1   10.23   42.625
2   myFunction(d)            1    0.24    1.000
             test replications elapsed relative
1 yourFunction(d)            1   10.22  340.667
2  myFunction3(d)            1    0.03    1.000
7) 现在我们可以使用比以前更大的数据来竞争我的First功能:

d <- replicate(1e4, data, simplify = F)
d <- rbindlist(d, use.names = T, fill = T, idcol = T)
d[, user_id := paste0(user_id, .id)]
d[, .N]
[1] 130000
### BENCHMARK
                    test replications elapsed relative
2  rez1 <- myFunction(d)            1   91.19    7.657
1 rez2 <- myFunction2(d)            1   11.91    1.000
all.equal(rez1, rez2)
[1] TRUE
             test replications elapsed relative
1 yourFunction(d)            1   10.22  340.667
2  myFunction3(d)            1    0.03    1.000
(十) 使用最后一种方法,我可以在大约25秒内处理130万行

             test replications elapsed relative
1 yourFunction(d)            1   10.22  340.667
2  myFunction3(d)            1    0.03    1.000
使用最后一种方法,我可以在大约1分钟内处理78万行(取决于内存)

             test replications elapsed relative
1 yourFunction(d)            1   10.22  340.667
2  myFunction3(d)            1    0.03    1.000
11) 原始与最后:(在1300行上)

             test replications elapsed relative
1 yourFunction(d)            1   10.22  340.667
2  myFunction3(d)            1    0.03    1.000
更新3: 12) 也许此功能可以稍微提高速度:

             test replications elapsed relative
1 yourFunction(d)            1   10.22  340.667
2  myFunction3(d)            1    0.03    1.000
myFunction5 <- function(d){
  setDT(d)
  setkey(d, user_id)
  seq2 <- Vectorize(seq.default, vectorize.args = c("from", "to"))
  startD <- as.integer(d[["start_date"]])
  endD <- as.integer(d[["end_date"]])
  seqences <- seq2(startD, endD)
  dd <- d[, .(list(.I)), by = user_id]
  indlist <- dd[[2]]
  mf <- function(x) uniqueN(unlist(x))
  ff <- function(x) mf(seqences[x])
  ff2 <- Vectorize(ff, "x")
  r <- ff2(indlist)
  data.table(user_id = dd[[1]], n = r, key = "user_id")
}
             test replications elapsed relative
1  myFunction3(d)            1    3.71     1.22
2 myFunction4(d1)            1    3.04     1.00

myFunction5此方法将seq保留在内部循环之外,但不幸的结果是内存不足,因此在1e5左右发生故障。但根据用户ID和日期范围条目的数量,这可能会更快:

             test replications elapsed relative
1 yourFunction(d)            1   10.22  340.667
2  myFunction3(d)            1    0.03    1.000
> d[, .SD
   ][, .(date=seq(from=min(start_date), to=max(end_date), by=1))
   ][d, .(user_id=i.user_id, start_date=i.start_date, end_date=i.end_date, date=x.date), on=.(date >= start_date, date <= end_date), allow.cartesian=T
   ][, unique(.SD, by=c('user_id', 'date'))
   ][, .N, user_id
   ][order(user_id)
   ]
>d[,.SD
][,(日期=序号(从=最小(开始日期),到=最大(结束日期),由=1)

][d,((user\u id=i.user\u id,start\u date=i.start\u date,end\u date=i.end\u date,date=x.date),on=。(date>=start\u date,date如果我理解您的问题,即计算每个id的唯一天数,则可以使用
Map
构建顺序日期

             test replications elapsed relative
1 yourFunction(d)            1   10.22  340.667
2  myFunction3(d)            1    0.03    1.000
setDT(data)[, .(cnt=uniqueN(unlist(Map(seq, start_date, end_date, by="day")))), by=user_id]
   user_id  cnt
1:      12 2606
2:      33 8967

你最好的选择是并行化。不幸的是,这需要一些工作。看看
parallel
doParallel
foreach
%dopar%
。主要的想法是按用户id分割数据帧,并将每组发送给并行工作程序。@Sotos,你能澄清你收到的错误消息是什么,是什么部分吗它所指的代码是什么?我的endnvm没有收到任何错误,我在粘贴时漏掉了一个字符:)@ChiPak,谢谢你,我想把
doParallel
作为最后的解决方案…很好的答案和测试,这基本上就是我所追求的,将处理时间缩短100倍是一个很好的开始。如果我知道怎么做的话,可以将其用于较小的数据集或与
doParallel
结合使用!谢谢!这真是太神奇了,马丁斯!非常感谢你的额外工作-他们改进了原来的解决方案…什么,4000次?太好了stuff@KasiaKulma使用小数据集对原始解决方案进行测试时,我得到了大约388次。最大的优点是我们可以处理更大的数据。记住,在任何计算中使用整数都会大大提高效率,这一点非常有用在speed.Martin中,我成功地在新数据上运行了您的代码,但是我在
MyFunction3
MyFunction2
中发现了一个错误,在
sequences@KasiaKulma附近我在那行(
sequences