R data.table, если затем поиск sumif с использованием соединения

Я ищу individual id в таблице events_table и вычисляю total_duration как сумму продолжительности всех событий до date.

Продолжительность - это время между date_start и date (таблица1), если событие не закончилось (т.е. имеет date_end), и в этом случае если date_end < date, duration = date_end - date_start.

В псевдокоде:

IF (date>date_start) Then{
   IF(date_end < date & date_end != NA) Then{
       duration = date_end-date_start
   } else if (date_start < date) {
       duration = date - date_start
   }
}
Then sum all the durations separately for each "individual_id" and "date" combo

Я использую data.tables, так как у меня большие таблицы (> 1 млн строк).

Мои данные выглядят примерно так:

 table1 <- fread(
      "individual id | date       
       1             |  2019-01-02
       1             |  2019-01-03
       2             |  2019-01-02
       2             |  2019-01-03", 
      sep ="|"
    )
    events_table<- fread(
      "individual id | date_start  | date_end
       1             |  2018-01-02 |   NA     
       1             |  2018-01-04 | 2018-07-01     
       1             |  2018-01-05 |   NA       
       2             |  2018-01-01 |   NA         
       2             |  2018-01-02 |   NA           
       2             |  2018-01-05 | 2018-11-21",
      sep = "|"
    )

Результат должен быть следующим:

 table1 <- fread(
          "individual id | date         | total_duration
           1             |  2019-01-02  |    905
           1             |  2019-01-03  |    907
           2             |  2019-01-02  |    1051
           2             |  2019-01-03  |    1053", 
          sep ="|"
        )

Мое лучшее предположение о начале запроса исходит из:

table1[, total_duration:= events_table[table1, 
                              on = .(`individual id`, date>date_start), 
                              sum(date-date_start),
                              by = .EACHI][["V1"]]]

Но я не знаю синтаксиса для включения условия if.

Спасибо за любую помощь.


person Laurence_jj    schedule 17.04.2019    source источник
comment
Я думаю, вы пропустили " во втором фреде   -  person akrun    schedule 17.04.2019
comment
@akrun ты прав, я обновил ты   -  person Laurence_jj    schedule 17.04.2019


Ответы (1)


# formatting
table1[, date := as.IDate(date)]
events_table[, `:=`(date_start = as.IDate(date_start), date_end = as.IDate(date_end))]

# list max dur
events_table[, dur := date_end - date_start]

# add up completed events
table1[, v1 := 
  events_table[.SD, on=.(`individual id`, date_end <= date), sum(x.dur, na.rm = TRUE), by=.EACHI]$V1
]

# add on incomplete events
table1[, v2 := 
  events_table[!is.na(date_end)][.SD, on=.(`individual id`, date_start <= date, date_end > date), sum(i.date - x.date_start, na.rm = TRUE), by=.EACHI]$V1
]

# add on ill-defined events
table1[, v3 := 
  events_table[is.na(date_end)][.SD, on=.(`individual id`, date_start <= date), sum(i.date - x.date_start, na.rm = TRUE), by=.EACHI]$V1
]

table1[, v := v1 + v2 + v3]

   individual id       date total_duration  v1 v2  v3    v
1:             1 2019-01-02            905 178  0 727  905
2:             1 2019-01-03            907 178  0 729  907
3:             2 2019-01-02           1051 320  0 731 1051
4:             2 2019-01-03           1053 320  0 733 1053

Вам не нужно определять три отдельных столбца, хотя это проще для отладки. Вместо этого вы можете инициализировать table1[, v := 0] и для каждого шага делать table1[, v := v + ...].

person Frank    schedule 17.04.2019
comment
выглядит именно так, как я надеялся, завтра протестирую, большое спасибо @frank - person Laurence_jj; 17.04.2019
comment
Я получаю сообщение об ошибке, что команда для генерации продолжительности неполных событий (v2) приводит к слишком большому количеству строк. Join results in 19190493 rows; more than 1027748 = nrow(x)+nrow(i). Check for duplicate key values in i each of which join to the same group in x over and over again. Поскольку мы добавляем дополнительное условие (date_end > date), не должно ли это приводить к уменьшению количества строк? - person Laurence_jj; 18.04.2019
comment
Это потому, что мы собираемся на свидание дважды? @Откровенный - person Laurence_jj; 18.04.2019
comment
@Laurence_jj Вы можете добавить аргумент allow.cartesian=TRUE для принудительного вычисления; см. ?data.table. Это происходит потому, что некоторые строки i = table1 соответствуют многим строкам x = events_table [! Is.na (date_end)] в соответствии с условиями on =. Я смущен, если v2 выдает ошибку, а v3 - нет, поскольку, как вы сказали, v2 использует более узкие условия on = ... - person Frank; 18.04.2019
comment
Я попытался использовать allow.cartesian = TRUE, и он запустился, однако v2 дает мне только нули, где данные явно должны привести к тому, что date-date_start даст больше нуля. - person Laurence_jj; 18.04.2019
comment
есть ли способ суммировать if (чтобы вывести date_end > date из условия on) и суммировать if. Например, что-то вроде table1[, v2 := events_table[!is.na(date_end)][.SD, on=.(individual id, date_start <= date), sum(ifelse(date_end > date, i.date - x.date_start, 0), na.rm = TRUE), by=.EACHI]$V1 ] - person Laurence_jj; 18.04.2019
comment
хммм, это тоже работает для примера, но дает нули для моих данных. Я буду исследовать дальше - person Laurence_jj; 18.04.2019
comment
Я допустил опечатку и пропустил x. от date_start. У меня отлично работает !! - person Laurence_jj; 18.04.2019
comment
Каким-то образом подвести итог, если, да, я думаю, что расчет может быть выполнен другими способами, чем я показал здесь. Я бы склонился к pmin(x.date_end, i.date) - x.date_start, поскольку ifelse имеет какое-то странное / раздражающее поведение, например, stackoverflow.com/q/16275149 - person Frank; 18.04.2019