首页 > 解决方案 > R/data.table:部分滚动连接

问题描述

我有以下数据结构:

> dt
   ID MiscInfo       Date Val
1:  A   info_a 2000-01-01   0
2:  A   info_a 2000-01-03   3
3:  B   info_b 2001-01-01   1
4:  B   info_b 2001-01-04   5
5:  B   info_b 2001-01-07  13

WhereDate缺少一些 ID-wise 条目,其中Val == 0MiscInfo表示一组N > 50属性变量。我的最终目标是填写缺失的条目,以便获得以下结构。

> dt_pref
    ID MiscInfo       Date Val
 1:  A   info_a 2000-01-01   0
 2:  A   info_a 2000-01-02   0
 3:  A   info_a 2000-01-03   3
 4:  B   info_b 2001-01-01   1
 5:  B   info_b 2001-01-02   0
 6:  B   info_b 2001-01-03   0
 7:  B   info_b 2001-01-04   5
 8:  B   info_b 2001-01-05   0
 9:  B   info_b 2001-01-06   0
10:  B   info_b 2001-01-07  13 

类似的请求来看,滚动连接是实现这一目标的不错途径。我遇到的问题是无法选择要滚动的列,如下所述:

drange = dt[, .(Date = seq(min(Date), max(Date), 1)), ID] %>% setkey(ID, Date)
dt[drange, roll = T]

    ID MiscInfo       Date Val
 1:  A   info_a 2000-01-01   0
 2:  A   info_a 2000-01-02   0
 3:  A   info_a 2000-01-03   3
 4:  B   info_b 2001-01-01   1
 5:  B   info_b 2001-01-02   1
 6:  B   info_b 2001-01-03   1
 7:  B   info_b 2001-01-04   5
 8:  B   info_b 2001-01-05   5
 9:  B   info_b 2001-01-06   5
10:  B   info_b 2001-01-07  13

在这种情况下,MiscInfo列被适当地滚动到我满意的程度,但是 Val 列当然也被滚动,而我希望将它们设置为等于 0。我当然也可以通过传递向另一个方向迈出一步roll = 0

dt[drange, roll = 0]
    ID MiscInfo       Date Val
 1:  A   info_a 2000-01-01   0
 2:  A     <NA> 2000-01-02  NA
 3:  A   info_a 2000-01-03   3
 4:  B   info_b 2001-01-01   1
 5:  B     <NA> 2001-01-02  NA
 6:  B     <NA> 2001-01-03  NA
 7:  B   info_b 2001-01-04   5
 8:  B     <NA> 2001-01-05  NA
 9:  B     <NA> 2001-01-06  NA
10:  B   info_b 2001-01-07  13

在这种情况下,我当然可以应用类似的东西dt[is.na(Val), Val := 0],但是使用类似的路由处理数组的 NA 条目MiscInfo(非常大)在计算上效率不高,我怀疑有一种与连接相关的执行方式这个操作。简而言之,我想将“填充”条目的 Val 预设为 0,并以有效的方式滚动剩余的列。有任何想法吗?

重现性:

dt = data.table(
  ID = c('A', 'A', 'B', 'B', 'B'),
  MiscInfo = c(rep('info_a', 2), rep('info_b', 3)),
  Date = as.Date(c('2000-01-01', '2000-01-03', '2001-01-01', '2001-01-04', '2001-01-07')),
  Val = c(0,3,1,5,13)
) %>% setkey(ID, Date)

dt_pref = data.table(
  ID = c(rep('A', 3), rep('B', 7)), 
  MiscInfo = c(rep("info_a", 3), rep("info_b", 7)), 
  Date = as.Date(c(10957, 10958, 10959, 11323, 11324, 11325, 11326, 11327, 11328, 11329), origin = '1970-01-01'),
  Val = c(0, 0, 3, 1, 0, 0, 5, 0, 0, 13)
)

标签: rdata.tablemissing-datarolling-computation

解决方案


即使对于更复杂的情况,也可以使用它:

merge(dt, 
dt[, .(Date = seq.Date(from = min(Date), to = max(Date), by = 1)), by = c("ID", "MiscInfo") ], 
      by = c("ID", "Date"), 
      all = TRUE)[, .(ID, Date, MiscInfo.y, Val = case_when(is.na(Val) ~ 0, 
                                                      TRUE ~ Val))]

推荐阅读