连接后要data.table复制行吗?

时间:2018-06-28 16:05:25

标签: r join data.table

我不确定我是否正确,因此,我将首先展示我要解决的问题,然后再展示我要解决的问题。随时告诉我我有多严重,以及您能想到的任何更好的方法。

我有3个data.tables(实际的“输入”数据要大得多,并且性能很重要,因此我必须尽可能多地使用):

输入:

+--------+----+----+----+------------+
|   ID   | T1 | T2 | T3 |    DATE    | 
+--------+----+----+----+------------+
| ACC001 |  1 |  0 |  0 | 31/12/2016 |
| ACC001 |  1 |  0 |  1 | 30/06/2017 |
| ACC002 |  0 |  1 |  1 | 31/12/2016 |
| ACC002 |  0 |  1 |  1 | 30/06/2017 |
+--------+----+----+----+------------+

重要程度:

+------------+------------+-------------+
|    DATE    | INDEX_NAME | INDEX_VALUE |
+------------+------------+-------------+
| 31/12/2016 | GDP        |  1.05       |
| 30/06/2017 | GDP        |  1.06       |
| 31/12/2017 | GDP        |  1.07       |
| 30/06/2018 | GDP        |  1.08       |
| 31/12/2016 | CPI        |  0.02       |
| 30/06/2017 | CPI        |  0.00       |
| 31/12/2017 | CPI        | -0.01       |
| 30/06/2018 | CPI        |  0.01       |
+------------+------------+-------------+   

时间:

+------------+
|    DATE    |
+------------+
| 31/12/2016 |
| 30/06/2017 |
| 31/12/2017 |
| 30/06/2018 |
+------------+

有了这些,我需要实现两件事:

  • 将第二个dt(mevs)中的GDP和CPI值插入第一个dt(mevs)中,以便根据T1,T2,T3,GDP和CPI在最后一列中进行一些计算。

  • 对第三个dt(时间)中给出的时间间隔进行投影,将前一个间隔中的T1,T2和T3值复制到相同的ID中(这样ACC001的值将保持(1、0、1) ),然后从相应日期获取GDP和CPI。最终的计算将使用相同的函数完成。

应该导致这样的“输入” dt:

+--------+----+----+----+------------+------+-------+------+
| ID     | T1 | T2 | T3 | DATE       | GDP  | CPI   | CALC |
+--------+----+----+----+------------+------+-------+------+
| ACC001 | 1  | 0  | 0  | 31/12/2016 | 1.05 | 0.02  | fun  |
| ACC001 | 1  | 0  | 1  | 30/06/2017 | 1.06 | 0.00  | fun  |
| ACC001 | 1  | 0  | 1  | 31/12/2017 | 1.07 | -0.01 | fun  |
| ACC001 | 1  | 0  | 1  | 30/06/2018 | 1.08 | 0.01  | fun  |
| ACC002 | 0  | 1  | 1  | 31/12/2016 | 1.05 | 0.02  | fun  |
| ACC002 | 0  | 1  | 1  | 30/06/2017 | 1.06 | 0.00  | fun  |
| ACC002 | 0  | 1  | 1  | 31/12/2017 | 1.07 | -0.01 | fun  |
| ACC002 | 0  | 1  | 1  | 30/06/2018 | 1.08 | 0.01  | fun  |
+--------+----+----+----+------------+------+-------+------+

我设法做到的事情:

  • mevs <- mevs %>% tidyr::spread(INDEX_NAME, INDEX_VALUE)将索引值放入列中。
  • input[mevs, ':=' (GDP = i.GDP, CPI = i.CPI), on = "RUN_DATE"]设置索引值(如果我没记错的话,请避免赋值)。

结果:

+--------+----+----+----+------------+------+------+------+
| ID     | C1 | C2 | C3 | DATE       | GDP  | CPI  | CALC |
+--------+----+----+----+------------+------+------+------+
| ACC001 | 1  | 0  | 0  | 31/12/2016 | 1.05 | 0.02 | fun  |
| ACC001 | 1  | 0  | 1  | 30/06/2017 | 1.06 | 0    | fun  |
| ACC002 | 0  | 1  | 1  | 31/12/2016 | 1.05 | 0.02 | fun  |
| ACC002 | 0  | 1  | 1  | 30/06/2017 | 1.06 | 0    | fun  |
+--------+----+----+----+------------+------+------+------+

我不知道该怎么做:

我正在尝试使用基于“ DATE”的“ input”-“ time”和以下代码进行正确的外部联接(在“我在做什么”的第二步的“选择性联接”之前) :input <- input[time, on = "DATE"]。但是,这不仅不能正常工作(我在下一步需要的ID列中获得了NA),而且还迫使我进行分配。

在那之后,我计划基于“ ID”使用“ input”-“ input”进行另一个联接,但是显然我不能,因为在这些新行中没有任何ID值:

+--------+----+----+----+------------+
| ID     | T1 | T2 | T3 | DATE       |
+--------+----+----+----+------------+
| ACC001 | 1  | 0  | 0  | 31/12/2016 |
| ACC001 | 1  | 0  | 1  | 30/06/2017 |
| NA     | NA | NA | NA | 31/12/2017 |
| NA     | NA | NA | NA | 30/06/2018 |
| ACC002 | 0  | 1  | 1  | 31/12/2016 |
| ACC002 | 0  | 1  | 1  | 30/06/2017 |
| NA     | NA | NA | NA | 31/12/2017 |
| NA     | NA | NA | NA | 30/06/2018 |
+--------+----+----+----+------------+

例如,是否有任何方法可以根据DATE列上的某些条件复制这些ID?如果不是,您是否知道其他解决方案,也许基于rbindlist

非常感谢您所做的一切。任何建议将不胜感激!

其他问题

避免分配

@Jaap的解决方案因此返回了所需的data.table。除非不可避免,否则我需要将输入转换为最后一个data.table,而不使用标准分配(<-)。在这种情况下该怎么办?

条件

我需要在票据的最后一部分中引入特殊性。如果在投影之前有一个没有任何注册表的ID,则T1 / T2 / T3在投影中必须为0。此处就是ACC002,在2016年12月31日之前没有注册表:

input <- fread("  ID   | T1 | T2 | T3 |    DATE    
                ACC001 |  1 |  0 |  0 | 31/12/2016 
                ACC001 |  1 |  0 |  1 | 30/06/2017 
                ACC002 |  0 |  1 |  1 | 31/12/2016", sep = "|")

那应该最终变成:

+--------+----+----+----+------------+------+-------+------+
| ID     | T1 | T2 | T3 | DATE       | GDP  | CPI   | CALC |
+--------+----+----+----+------------+------+-------+------+
| ACC001 | 1  | 0  | 0  | 31/12/2016 | 1.05 | 0.02  | fun  |
| ACC001 | 1  | 0  | 1  | 30/06/2017 | 1.06 | 0.00  | fun  |
| ACC001 | 1  | 0  | 1  | 31/12/2017 | 1.07 | -0.01 | fun  |
| ACC001 | 1  | 0  | 1  | 30/06/2018 | 1.08 | 0.01  | fun  |
| ACC002 | 0  | 1  | 1  | 31/12/2016 | 1.05 | 0.02  | fun  |
| ACC002 | 0  | 0  | 0  | 30/06/2017 | 1.06 | 0.00  | fun  |
| ACC002 | 0  | 0  | 0  | 31/12/2017 | 1.07 | -0.01 | fun  |
| ACC002 | 0  | 0  | 0  | 30/06/2018 | 1.08 | 0.01  | fun  |
+--------+----+----+----+------------+------+-------+------+

实际的最终结论是,在这种情况下,依赖于T1 / T2 / T3多项式的CALC列等于0(以防万一,您可以直接从那里求近)。

1 个答案:

答案 0 :(得分:1)

使用:

input[, .SD[time, on = "DATE"], by = ID
      ][dcast(mevs, DATE ~ INDEX_NAME), on = "DATE", `:=` (GDP = i.GDP, CPI = i.CPI)
        ][, (2:4) := lapply(.SD, zoo::na.locf), by = ID, .SDcols = 2:4][]

给予:

       ID T1 T2 T3       DATE  GDP   CPI
1: ACC001  1  0  0 31/12/2016 1.05  0.02
2: ACC001  1  0  1 30/06/2017 1.06  0.00
3: ACC001  1  0  1 31/12/2017 1.07 -0.01
4: ACC001  1  0  1 30/06/2018 1.08  0.01
5: ACC002  0  1  1 31/12/2016 1.05  0.02
6: ACC002  0  1  1 30/06/2017 1.06  0.00
7: ACC002  0  1  1 31/12/2017 1.07 -0.01
8: ACC002  0  1  1 30/06/2018 1.08  0.01

这是什么:

  • input[, .SD[time, on = "DATE"], by = ID]ID data.table的每个time连接到其余列,从而扩展了data.table。
  • 然后将扩展版本的mevsdcast(mevs, DATE ~ INDEX_NAME))加入扩展的data.table。
  • 最后,扩展数据表中的缺失值被包中的na.locf函数填充。

要满足已更新问题的额外条件,您可以执行以下操作:

ones <- input[, .N, by = ID][N == 1, ID]

input[, .SD[time, on = "DATE"], by = ID
      ][dcast(mevs, DATE ~ INDEX_NAME), on = "DATE", `:=` (GDP = i.GDP, CPI = i.CPI)
        ][, (2:4) := lapply(.SD, function(x) if (.BY %in% ones) replace(x, is.na(x), 0L) else zoo::na.locf(x) )
          , by = ID, .SDcols = 2:4][]

给出:

       ID T1 T2 T3       DATE  GDP   CPI
1: ACC001  1  0  0 31/12/2016 1.05  0.02
2: ACC001  1  0  1 30/06/2017 1.06  0.00
3: ACC001  1  0  1 31/12/2017 1.07 -0.01
4: ACC001  1  0  1 30/06/2018 1.08  0.01
5: ACC002  0  1  1 31/12/2016 1.05  0.02
6: ACC002  0  0  0 30/06/2017 1.06  0.00
7: ACC002  0  0  0 31/12/2017 1.07 -0.01
8: ACC002  0  0  0 30/06/2018 1.08  0.01

使用的数据:

input <- fread("  ID   | T1 | T2 | T3 |    DATE    
                ACC001 |  1 |  0 |  0 | 31/12/2016 
                ACC001 |  1 |  0 |  1 | 30/06/2017 
                ACC002 |  0 |  1 |  1 | 31/12/2016 
                ACC002 |  0 |  1 |  1 | 30/06/2017 ", sep = "|")

mevs <- fread("  DATE    | INDEX_NAME | INDEX_VALUE 
              31/12/2016 | GDP        |  1.05       
              30/06/2017 | GDP        |  1.06       
              31/12/2017 | GDP        |  1.07       
              30/06/2018 | GDP        |  1.08       
              31/12/2016 | CPI        |  0.02       
              30/06/2017 | CPI        |  0.00       
              31/12/2017 | CPI        | -0.01       
              30/06/2018 | CPI        |  0.01   ", sep = "|")

time <- fread("    DATE   
               31/12/2016 
               30/06/2017 
               31/12/2017 
               30/06/2018 ", sep = "|")