【问题标题】:Create new column based on whether date is between other dates, over multiple time periods根据日期是否在多个时间段内的其他日期之间创建新列
【发布时间】:2020-10-09 15:20:18
【问题描述】:

我有一个包含多行人员的表格,以及每个纳税年度结束的日期:

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 总是在 4 月 6 日,每个人总是有 START_DATEEND_DATE - 没有 NULLs。

我想在第一个表中添加一个新的 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_DATEEND_DATE 之间,那么STATUS 已使用,如果未使用,则 STATUS 未使用。

我遇到困难的地方是第二张表中有多个工作期的借款人。在这些情况下,当我执行连接时,第一个表中的行会重复(或更多),而我无法找到另一种方法。

我正在使用 R,更喜欢 data.table,因为它通常更快,但 dplyr 也可能没问题。

【问题讨论】:

    标签: r dplyr data.table data-manipulation


    【解决方案1】:

    dplyrlubridate 的一个解决方案可能是:

    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  
    

    【讨论】:

      【解决方案2】:

      使用连接关联表然后进行汇总的解决方案

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

      【讨论】:

        【解决方案3】:
        # 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))
        

        【讨论】:

          【解决方案4】:

          在 data.table 中使用非等值连接的选项:

          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]
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2020-09-04
            • 1970-01-01
            • 2022-07-21
            • 1970-01-01
            • 2018-04-30
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多