Создать новый столбец в зависимости от того, находится ли дата между другими датами за несколько периодов времени - PullRequest
2 голосов
/ 19 июня 2020

У меня есть таблица с несколькими строками человека и датой окончания каждого налогового года:

df1 <- tibble::tribble(~ID,       ~TAX_YEAR_END_DATE,
                       "01",      "2009-04-06",
                       "01",      "2010-04-06",
                       "01",      "2011-04-06",
                       "02",      "2010-04-06",
                       "02",      "2011-04-06",
                       "02",      "2012-04-06")

И еще одна таблица с несколькими строками на человека, дающая дату начала и дату окончания для периодов работа:

df2 <- tibble::tribble(~ID,     ~START_DATE,   ~END_DATE,
                       "01",    "2007-09-11",  "2010-04-06",
                       "02",    "2008-06-06",  "2010-04-06",
                       "02",    "2011-09-09",  "2014-04-06")

END_DATE всегда 6 апреля, и у всех всегда есть START_DATE и END_DATE - нет NULL s.

Я хочу добавить новый столбец STATUS в первую таблицу, в котором будет указано, ЗАНИМАЕТСЯ ли каждый человек или нет за каждый год. Вот как это будет выглядеть в приведенном выше примере:

ID      TAX_YEAR_END_DATE   STATUS
01      2009-04-06          EMPLOYED
01      2010-04-06          EMPLOYED
01      2011-04-06          NOT
02      2010-04-06          EMPLOYED
02      2011-04-06          NOT
02      2012-04-06          EMPLOYED

Я понял, что могу присоединиться к таблицам с помощью ID, а затем применить некоторые правила при использовании mutate() для создания нового столбец - если TY_END_DATE находится между START_DATE и END_DATE, то STATUS ЗАНЯТО, а если нет, то STATUS НЕ ЗНАЧИТ.

Где я застрял, с заемщиками, имеющими более одного стажа работы во второй таблице. В этих случаях строки в первой таблице дублируются (или больше), когда я выполняю соединение, и я не смог найти альтернативный способ сделать это.

Я использую R , предпочел бы data.table, поскольку он обычно быстрее, но dplyr тоже может подойти.

Ответы [ 4 ]

2 голосов
/ 19 июня 2020

Решение с использованием объединения для связывания таблиц, а затем суммирования

df1 %>% left_join(df2, by = "ID") %>% 
  mutate(employed = between(TAX_YEAR_END_DATE, START_DATE, END_DATE)) %>% 
  group_by(ID, TAX_YEAR_END_DATE) %>% 
  summarise(employed = any(employed))
0 голосов
/ 20 июня 2020

Вариант с использованием неэквивалентного соединения в таблице данных:

DT1[, status := c("NOT","EMP")[
    DT2[.SD, on=.(ID, START_DATE<=TAX_YEAR_END_DATE, END_DATE>=TAX_YEAR_END_DATE),
        by=.EACHI, .N>0L]$V1 + 1L
]]

вывод:

   ID TAX_YEAR_END_DATE status
1:  1        2009-04-06    EMP
2:  1        2010-04-06    EMP
3:  1        2011-04-06    NOT
4:  2        2010-04-06    EMP
5:  2        2011-04-06    NOT
6:  2        2012-04-06    EMP

данные:

library(data.table)
DT1 <- fread("ID      TAX_YEAR_END_DATE
01      2009-04-06
01      2010-04-06
01      2011-04-06
02      2010-04-06
02      2011-04-06
02      2012-04-06")[, 
    TAX_YEAR_END_DATE := as.IDate(TAX_YEAR_END_DATE)]

cols <- c("START_DATE", "END_DATE")
DT2 <- fread("ID    START_DATE    END_DATE
01    2007-09-11    2010-04-06
02    2008-06-06    2010-04-06
02    2011-09-09    2014-04-06")[, 
     (cols) := lapply(.SD, as.IDate), .SDcols=cols]
0 голосов
/ 19 июня 2020
# Create a lookup data.frame for the durations in which ID was employed:
# dates_ro => data.frame
dates_ro <- data.frame(do.call("rbind", lapply(split(df2, rownames(df2)), function(x){
      data.frame(id = x$ID, 
                 emp_date = seq.Date(x$START_DATE, x$END_DATE, by = "days"))
    }
  )
),
row.names = NULL)

# Lookup whether or not the person is employed at end date
# STATUS => character vector
df1$STATUS <- ifelse(is.na(
  match(df1$ID, dates_ro$id) &
    match(df1$TAX_YEAR_END_DATE, dates_ro$emp_date)),"UNEMPLOYED", "EMPLOYED")

Данные:

df1 <- structure(list(ID = c(1L, 1L, 1L, 2L, 2L, 2L), TAX_YEAR_END_DATE = structure(c(14340, 
14705, 15070, 14705, 15070, 15436), class = "Date")), 
class = "data.frame", row.names = c(NA, -6L))

df2 <- structure(list(ID = c(1L, 2L, 2L), START_DATE = structure(c(13767, 
14036, 15226), class = "Date"), END_DATE = structure(c(14705, 
14705, 16166), class = "Date")), class = "data.frame", row.names = c(NA, -3L))
0 голосов
/ 19 июня 2020

Одно решение dplyr и lubridate может быть:

df1 %>%
 left_join(df2) %>%
 group_by(ID, TAX_YEAR_END_DATE) %>%
 summarise(STATUS = any(int_overlaps(interval(TAX_YEAR_END_DATE, TAX_YEAR_END_DATE),
                                     interval(START_DATE, END_DATE))))

     ID TAX_YEAR_END_DATE STATUS
  <int> <chr>             <lgl> 
1     1 2009-04-06        TRUE  
2     1 2010-04-06        TRUE  
3     1 2011-04-06        FALSE 
4     2 2010-04-06        TRUE  
5     2 2011-04-06        FALSE 
6     2 2012-04-06        TRUE  
...