data.table реплицировать строки после объединения? - PullRequest
0 голосов
/ 28 июня 2018

Я не уверен, что сталкиваюсь с этим правом, поэтому сначала я попытаюсь показать проблему, которую пытаюсь решить, а затем способ, которым я пытаюсь это сделать. Не стесняйтесь сказать мне, как я неправ, и любой лучший подход вы можете придумать.

У меня есть три 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 |
+--------+----+----+----+------------+

mevs:

+------------+------------+-------------+
|    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 |
+------------+

С этим мне нужно достичь 2 вещей:

  • Вставьте значения ВВП и ИПЦ со второго dt (мэВ) в первый (входной), чтобы сделать некоторые вычисления в последнем столбце на основе T1, T2, T3, GDP и CPI.

  • Сделайте прогноз для временных интервалов, указанных в третьем dt (времени), скопировав значения T1, T2 и T3 в предыдущем интервале в тот же идентификатор (таким образом, значения ACC001 останутся (1, 0, 1) ) и получение ВВП и ИПЦ от соответствующих дат. Окончательный расчет будет выполнен с использованием той же функции.

Что должно привести к "вводу" 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  |
+--------+----+----+----+------------+------+------+------+

Что я не умею делать правильно:

Я пытаюсь сделать правильное внешнее соединение (перед «выборочным соединением» на втором шаге в «Что я делаю») с «input» - «time» на основе «DATE» со следующим кодом : input <- input[time, on = "DATE"]. Но не только он не работает должным образом (я получаю NA в столбце ID, который мне понадобился для следующего шага), но также заставляет меня сделать назначение.

После этого я планировал сделать еще одно соединение с «input» - «input» на основе «ID», но, очевидно, я не могу, так как у меня нет никакого значения 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? Если нет, знаете ли вы какое-либо другое решение, возможно, основанное на rbindlist?

Большое спасибо за то, что зашли так далеко. Любой совет будет высоко оценен!

Дополнительные вопросы

Как избежать назначения

@ Решение Jaap возвращает желаемый data.table, благодаря этому. Мне нужно было бы превратить ввод в этот последний data.table, без использования стандартного назначения (<-), если это неизбежно. Как это можно сделать в этом случае?

Conditionals

Мне нужно было бы внести особенность в последнюю часть сценария. Если перед проекциями есть ID без каких-либо реестров, T1 / T2 / T3 должны быть 0 в проекциях. Это было бы в случае ACC002, который не имеет реестров после 31.12.2016:

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  |
+--------+----+----+----+------------+------+-------+------+

Фактическая окончательность этого состоит в том, что столбец CALC, который опирается на зависимый полином T1 / T2 / T3, равен 0 в этой ситуации (в случае, если вам лучше подойти непосредственно оттуда).

1 Ответ

0 голосов
/ 28 июня 2018

Использование:

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 таблицы данных time остальные столбцы, таким образом расширяя таблицу данных.
  • Широкая версия mevs (dcast(mevs, DATE ~ INDEX_NAME)) затем присоединяется к расширенной таблице data.table.
  • Наконец, пропущенные значения в расширенной таблице 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 = "|")
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...