R:嵌套的data.table操作

时间:2017-09-04 15:06:53

标签: r data.table

这里有一个简单的例子来说明我的问题: 我有两个数据表(data.table对象),一个非常大的表,表A,有400万个产品,它们记录在日期并且有 ex(盗版)日期< / em>的。在这两个日期期间,如果产品的期限涵盖某个 payment_date ,产品将支付某个金额,后两个变量将在第二个表B中收集。

表A的负责人:

         date     exdate unique_id
1: 1999-01-04 1999-09-18         294
2: 1999-01-04 1999-09-18         295
3: 1999-01-04 1999-09-18         296
4: 1999-01-04 1999-09-18         297
5: 1999-01-04 1999-09-18         298
6: 1999-01-05 1999-09-18         299

表B的负责人:

   payment_date amount
1:   1998-06-30   4.18
2:   1998-09-30   4.26
3:   1998-12-31   4.00
4:   1999-03-31   4.01
5:   1999-06-30   4.18
6:   1999-09-30   4.45

重要的是,表A中的产品具有不同的期间长度,因此对于一些产品有多个付款日期,而有些则没有(日期在%Y%M%D)。

我现在想要收集A中所有金额和付款日期的每个产品,直到其到期日为止。当然,这可以通过for循环来实现,但是考虑到巨大的表格,这非常讨厌。因此,我想使用更快的data.table方法。

现在,以下内容为金额提供了技巧:

tmp <- B[A,on=.(payment_date>date, payment_date<=exdate),.(amount,unique_id,payment_date),by=.EACHI]
colnames(tmp)<-c("date","exdate","amount","unique_id","payment_date")

输出如下:

         date     exdate amount unique_id payment_date
1: 1999-01-04 1999-09-18   4.01       294   1999-03-31
2: 1999-01-04 1999-09-18   4.18       294   1999-03-31
3: 1999-01-04 1999-09-18   4.01       295   1999-03-31
4: 1999-01-04 1999-09-18   4.18       295   1999-03-31
5: 1999-01-04 1999-09-18   4.01       296   1999-03-31
6: 1999-01-04 1999-09-18   4.18       296   1999-03-31
7: 1999-01-04 1999-09-18   4.01       297   1999-03-31
8: 1999-01-04 1999-09-18   4.18       297   1999-03-31
9: 1999-01-04 1999-09-18   4.01       298   1999-03-31

我的问题是data.table只给我每个金额的第一个payment_date,所以尽管这些产品在其生命周期中明显有两个付款日期,但我只得到(1999-03-31,1999-03-31),而不是(1999-03-31,1999-06-30)。

是否有人知道我如何告诉data.table为我提供金额和payment_dates的相应向量,而不仅仅是每个产品的金额和payment_dates向量的第一个元素?

我希望这个例子涵盖了我的整个斗争,如果还需要更多东西让事情更清楚,请告诉我。任何帮助都非常感谢。

P.S:当然我也尝试了sapply(),但是像往常一样,它就像for循环一样,并且与data.table方法相比不会节省太多时间。

2 个答案:

答案 0 :(得分:2)

奇怪,但如果将一份payment_date添加到B似乎正常工作

let

答案 1 :(得分:1)

您的数据

A <- structure(list(date = structure(c(10595, 10595, 10595, 10595, 
10595, 10596), class = "Date"), exdate = structure(c(10852, 10852, 
10852, 10852, 10852, 10852), class = "Date"), unique_id = 294:299), class = "data.frame", .Names = c("date", 
"exdate", "unique_id"), row.names = c(NA, -6L))

B <- structure(list(payment_date = structure(c(10407, 10499, 10591, 
10681, 10772, 10864), class = "Date"), amount = c(4.18, 4.26, 
4, 4.01, 4.18, 4.45)), class = "data.frame", .Names = c("payment_date", 
"amount"), row.names = c(NA, -6L))

tidyverse解决方案

您可以使用tidyr:nestpurrr:map来完成此操作。 dplyr:betweenx >= left_arg & x <= right_arg

的包装器
library(tidyverse)
A %>% 
  mutate(copy1=date, copy2=exdate) %>%
  nest(copy1, copy2) %>%                         # nest copies of date and exdate
  mutate(data = map(data, ~B %>% filter(between(payment_date, .x$copy1, .x$copy2)))) %>%               # filter B where payment_date is between date and ex_date of A[row,]
  unnest(data) 

输出

         date     exdate unique_id payment_date amount
       <date>     <date>     <int>       <date>  <dbl>
 1 1999-01-04 1999-09-18       294   1999-03-31   4.01
 2 1999-01-04 1999-09-18       294   1999-06-30   4.18
 3 1999-01-04 1999-09-18       295   1999-03-31   4.01
 4 1999-01-04 1999-09-18       295   1999-06-30   4.18
 5 1999-01-04 1999-09-18       296   1999-03-31   4.01
 6 1999-01-04 1999-09-18       296   1999-06-30   4.18
 7 1999-01-04 1999-09-18       297   1999-03-31   4.01
 8 1999-01-04 1999-09-18       297   1999-06-30   4.18
 9 1999-01-04 1999-09-18       298   1999-03-31   4.01
10 1999-01-04 1999-09-18       298   1999-06-30   4.18
11 1999-01-05 1999-09-18       299   1999-03-31   4.01
12 1999-01-05 1999-09-18       299   1999-06-30   4.18