【问题标题】:Fill all gaps between starting and ending dates with dplyr使用 dplyr 填补开始日期和结束日期之间的所有空白
【发布时间】:2021-02-22 18:51:26
【问题描述】:

假设我有一个如下所示的 data.frame:

user_df = read.table(text = "person_id job_number job_type start_date end_date
                  1 1 B 2012-11-01 2014-01-01
                  1 2 A 2016-02-01 2016-10-01
                  1 3 A 2016-12-01 2020-01-01
                  1 4 B 2020-01-01 2021-01-01
                  2 1 A 2011-03-01 2012-08-01
                  2 2 B 2013-01-01 2020-01-01
                  2 3 A 2020-01-01 2021-01-01
                  2 4 B 2021-01-01 2021-01-17
                  3 1 A 2005-03-01 2011-03-01
                  3 2 B 2012-01-01 2014-01-01", header = T)

每个person_id 都有给定工作的开始日期和结束日期。我想在作业之间的空白区域之间插入行,并为这些列创建一个名为 unemployed 的附加列。

前几行的结果 data.frame 如下所示:

user_df = read.table(text = "person_id job_number job_type start_date end_date unemployed
                  1 1 B 2012-11-01 2014-01-01 0
                  1 1 B 2014-01-01 2016-02-01 1
                  1 2 A 2016-02-01 2016-10-01 0
                  1 2 A 2016-10-01 2016-12-01 1
                  1 3 A 2016-12-01 2020-01-01 0
                  1 4 B 2020-01-01 2021-01-01 0
                  2 1 A 2011-03-01 2012-08-01 0
                  2 1 A 2012-08-01 2013-01-01 1
                  2 2 B 2013-01-01 2020-01-01 0", header = T)

所以我实际上插入了一个新行,其中前一行的结束日期作为其开始日期,下一行的开始日期作为其结束日期。

不知道从哪里开始。我可以通过简单地将跨越最早开始日期和最后结束日期的天数相加并从每行实际累积的总时间中减去它来计算失业总时间。但我不确定如何以编程方式在 dplyr 链中插入行来填补失业时间。

【问题讨论】:

    标签: r dplyr


    【解决方案1】:
    library(dplyr)
    user_df %>%
      arrange(start_date) %>%
      group_by(person_id) %>%
      mutate(nextstart = lead(start_date)) %>%
      filter(end_date < nextstart) %>%
      mutate(start_date = end_date, end_date = nextstart, unemployed = 1L) %>%
      select(-nextstart) %>%
      bind_rows(mutate(user_df, unemployed = 0L)) %>%
      arrange(person_id, start_date) %>%
      ungroup()
    # # A tibble: 14 x 6
    #    person_id job_number job_type start_date end_date   unemployed
    #        <int>      <int> <chr>    <chr>      <chr>           <int>
    #  1         1          1 B        2012-11-01 2014-01-01          0
    #  2         1          1 B        2014-01-01 2016-02-01          1
    #  3         1          2 A        2016-02-01 2016-10-01          0
    #  4         1          2 A        2016-10-01 2016-12-01          1
    #  5         1          3 A        2016-12-01 2020-01-01          0
    #  6         1          4 B        2020-01-01 2021-01-01          0
    #  7         2          1 A        2011-03-01 2012-08-01          0
    #  8         2          1 A        2012-08-01 2013-01-01          1
    #  9         2          2 B        2013-01-01 2020-01-01          0
    # 10         2          3 A        2020-01-01 2021-01-01          0
    # 11         2          4 B        2021-01-01 2021-01-17          0
    # 12         3          1 A        2005-03-01 2011-03-01          0
    # 13         3          1 A        2011-03-01 2012-01-01          1
    # 14         3          2 B        2012-01-01 2014-01-01          0
    

    从技术上讲,这是按日期的字母顺序进行比较;在这种情况下,它的效果是相同的(格式很好),但效率会稍低(整数/数字排序比字母排序快)。

    这是通过首先创建然后仅捕获失业时间段来实现的,

    user_df %>%
      arrange(start_date) %>%
      group_by(person_id) %>%
      mutate(nextstart = lead(start_date)) %>%
      filter(end_date < nextstart)
    # # A tibble: 4 x 6
    # # Groups:   person_id [3]
    #   person_id job_number job_type start_date end_date   nextstart 
    #       <int>      <int> <chr>    <chr>      <chr>      <chr>     
    # 1         3          1 A        2005-03-01 2011-03-01 2012-01-01
    # 2         2          1 A        2011-03-01 2012-08-01 2013-01-01
    # 3         1          1 B        2012-11-01 2014-01-01 2016-02-01
    # 4         1          2 A        2016-02-01 2016-10-01 2016-12-01
    

    然后移动变量,然后添加unemployed,最后将其返回到原始数据集。在这种情况下,我将unemployed添加到原来的mid-bind_rows;在哪里做这主要是偏好。

    【讨论】:

    • 哇,这太聪明了!非常感谢。从阅读这段代码中学到了很多东西。
    • 希望快速跟进问题。我注意到在我的数据中,一些参与者在一行中的日期位于另一行的开始日期和结束日期之间。例如,如果他们同时做两份工作,一份在 2005-03-01 - 2011-03-01 之间,另一份在 2006-03-01 和 2007-03-01 之间。对于这些情况如何处理,你有什么猜测吗?
    • 这是一个棘手的问题:对我来说,这是完全有效的数据。不过,听起来它与您的下游处理不一致。例如,您是否假设没有两行(对于一个人)可以完全重叠?如果是这样,你想如何处理冲突?最短的工作?最长的工作?两个工作的联合(最小开始和最大结束)?这完全是上下文相关的,你必须完全定义。不,没有工具可以为您完成所有这些工作,因为这是您的限制。 (但是是的,它可以通过明确的规则来完成。)
    • 嗯,抱歉——我应该更具体一些。我将创建一个新问题,如果您有兴趣回答,我会将其链接到此处。
    猜你喜欢
    • 2013-01-12
    • 2020-10-05
    • 2015-07-05
    • 1970-01-01
    • 1970-01-01
    • 2021-09-14
    • 2019-04-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多