【问题标题】:Vector of Date between multiples dates多个日期之间的日期向量
【发布时间】:2021-09-24 15:21:51
【问题描述】:

帧 df1 和 df2。我想将来自 df2 数据框的版本列添加到 df1 中。条件是df1的Date列在df2.Date1和df2.Date之间,相应带上对应的版本。

例如df1的第一个日期是2020-03-25,它在2020-01-012020-03-25之间,所以对应的版本是CZ01。感谢您的帮助。

我的 df1

library(dplyr)
library(data.table)

set.seed(1);vec1 <- sample(seq(as.Date('2020-01-01'), as.Date('2020-12-31'), by="day"), 10)
set.seed(2);vec2 <- sample(seq(as.Date('2020-01-01'), as.Date('2020-12-31'), by="day"), 5)

df1 <- data.frame(ID = c(rep(1, 10),rep(2, 5)), Date = c(vec1, vec2)) %>%
       arrange(ID, Date)
   ID       Date
1   1 2020-03-25
2   1 2020-05-08
3   1 2020-06-15
4   1 2020-07-05
5   1 2020-09-26
6   1 2020-10-03
7   1 2020-10-25
8   1 2020-11-02
9   1 2020-11-19
10  1 2020-11-25
11  2 2020-07-16
12  2 2020-09-18
13  2 2020-09-29
14  2 2020-12-06
15  2 2020-12-14

我的 df2

df2 <- data.frame(ID = c(1,1,1,2,2), Version = c('CZ01','CZ02','CZ03','BX01','BX02'),
                  Date1 = as.Date(c('2020-01-01','2020-03-25','2020-07-02','2020-07-16','2020-10-31')),
                  Date2 = as.Date(c('2020-03-25','2020-07-02','2020-12-31','2020-10-31','2020-12-31')))
df2
  ID Version      Date1      Date2
1  1    CZ01 2020-01-01 2020-03-25
2  1    CZ02 2020-03-25 2020-07-02
3  1    CZ03 2020-07-02 2020-12-31
4  2    BX01 2020-07-16 2020-10-31
5  2    BX02 2020-10-31 2020-12-31

预期输出

   ID       Date Version
1   1 2020-03-25    CZ01
2   1 2020-05-08    CZ02
3   1 2020-06-15    CZ02
4   1 2020-07-05    CZ03
5   1 2020-09-26    CZ03
6   1 2020-10-03    CZ03
7   1 2020-10-25    CZ03
8   1 2020-11-02    CZ03
9   1 2020-11-19    CZ03
10  1 2020-11-25    CZ03
11  2 2020-07-16    BX01
12  2 2020-09-18    BX01
13  2 2020-09-29    BX01
14  2 2020-12-06    BX02
15  2 2020-12-14    BX02

【问题讨论】:

    标签: r


    【解决方案1】:

    您可以使用以下解决方案。以下是有关其工作原理的一些说明:

    • 我首先使用来自purrrmap2 函数,因为我需要在df1 的每一行中迭代IDDate 变量
    • 在下一步中,我在每一行中选择了df2 的所有变量,它们实际上分别是IDDate1Date2,这是一个长度为3 的数字向量,..1 变量位于@987654331 @指第一个等等
    • 您可能已经注意到我再次将您的日期转换为pmap 中的as.Date,这是因为当我收集除Version 之外的所有列时,它们都被强制转换为numeric
    • 最后我检查df1每一行中我们的Date是否属于任何类别,还考虑了IDs的匹配
    • 两者都会产生一个长度为 5 的逻辑向量,我选择了第一个返回 TRUE 的向量
    • 需要考虑的另一件事是,因为您的某些 Date 值可能属于多个类别,例如我使用 [1] 仅选择第一个的第一行
    library(dplyr)
    library(purrr)
    
    df1 %>%
      mutate(Version = map2(ID, Date, function(a, b) {
        df2$Version[pmap_lgl(df2 %>% select(!Version), ~ between(b, as.Date(..2), as.Date(..3)) &
                           a == ..1)][1]
      }))
    
       ID       Date Version
    1   1 2020-03-25    CZ01
    2   1 2020-05-08    CZ02
    3   1 2020-06-15    CZ02
    4   1 2020-07-05    CZ03
    5   1 2020-09-26    CZ03
    6   1 2020-10-03    CZ03
    7   1 2020-10-25    CZ03
    8   1 2020-11-02    CZ03
    9   1 2020-11-19    CZ03
    10  1 2020-11-25    CZ03
    11  2 2020-07-16    BX01
    12  2 2020-09-18    BX01
    13  2 2020-09-29    BX01
    14  2 2020-12-06    BX02
    15  2 2020-12-14    BX02
    

    【讨论】:

      【解决方案2】:

      首先,我们可以尝试直接非等式连接(同时具有非严格不等式)。我们会看到第 1 行是重复的:

      df2[df1, on = .(ID, Date1 <= Date, Date2 >= Date)
        ][, c("Date", "Date1", "Date2") := .(Date1, NULL, NULL)]
      #        ID Version       Date
      #     <num>  <char>     <Date>
      #  1:     1    CZ01 2020-03-25
      #  2:     1    CZ02 2020-03-25
      #  3:     1    CZ02 2020-05-08
      #  4:     1    CZ02 2020-06-15
      #  5:     1    CZ03 2020-07-05
      #  6:     1    CZ03 2020-09-26
      #  7:     1    CZ03 2020-10-03
      #  8:     1    CZ03 2020-10-25
      #  9:     1    CZ03 2020-11-02
      # 10:     1    CZ03 2020-11-19
      # 11:     1    CZ03 2020-11-25
      # 12:     2    BX01 2020-07-16
      # 13:     2    BX01 2020-09-18
      # 14:     2    BX01 2020-09-29
      # 15:     2    BX02 2020-12-06
      # 16:     2    BX02 2020-12-14
      

      这也许可以通过聚合来解决(即,取第一个非NAVersion),假设我们有办法唯一地识别原始行。我假设IDDate 是独一无二的,我们可以这样做

      df2[df1, on = .(ID, Date1 <= Date, Date2 >= Date)
        ][, c("Date", "Date1", "Date2") := .(Date1, NULL, NULL)
        ][, .SD[which.min(is.na(Version)),], by = .(ID, Date)]
      #        ID       Date Version
      #     <num>     <Date>  <char>
      #  1:     1 2020-03-25    CZ01
      #  2:     1 2020-05-08    CZ02
      #  3:     1 2020-06-15    CZ02
      #  4:     1 2020-07-05    CZ03
      #  5:     1 2020-09-26    CZ03
      #  6:     1 2020-10-03    CZ03
      #  7:     1 2020-10-25    CZ03
      #  8:     1 2020-11-02    CZ03
      #  9:     1 2020-11-19    CZ03
      # 10:     1 2020-11-25    CZ03
      # 11:     2 2020-07-16    BX01
      # 12:     2 2020-09-18    BX01
      # 13:     2 2020-09-29    BX01
      # 14:     2 2020-12-06    BX02
      # 15:     2 2020-12-14    BX02
      

      另一种方法是使用非等值连接列的赋值连接(恰好颠倒了 data.table 操作数的顺序),但我们遇到了另一个问题:因为 df1$Date[1]df2$Date2[1] 相同,并且df2$Date1[2],这表明非等连接应该一方面是严格的&lt;,另一方面是不严格的&gt;=。如果您这样做是为了在第一行找到"CZ01",那么df1$Date[11] 将不适合df2 中定义的范围。

      library(data.table)
      setDT(df1)
      setDT(df2)
      
      df1[df2, Version := Version, on = .(ID, Date > Date1, Date <= Date2)]
      #        ID       Date Version
      #     <num>     <Date>  <char>
      #  1:     1 2020-03-25    CZ01
      #  2:     1 2020-05-08    CZ02
      #  3:     1 2020-06-15    CZ02
      #  4:     1 2020-07-05    CZ03
      #  5:     1 2020-09-26    CZ03
      #  6:     1 2020-10-03    CZ03
      #  7:     1 2020-10-25    CZ03
      #  8:     1 2020-11-02    CZ03
      #  9:     1 2020-11-19    CZ03
      # 10:     1 2020-11-25    CZ03
      # 11:     2 2020-07-16    <NA>
      # 12:     2 2020-09-18    BX01
      # 13:     2 2020-09-29    BX01
      # 14:     2 2020-12-06    BX02
      # 15:     2 2020-12-14    BX02
      

      我们可以用

      填写NA
      tmp <- df1[is.na(Version),
        ][, Version := NULL
        ][df2, Version := Version, on = .(ID, Date >= Date1, Date <= Date2)]
      tmp
      #       ID       Date Version
      #    <num>     <Date>  <char>
      # 1:     2 2020-07-16    BX01
      
      rbindlist(list(df1[ !is.na(Version), ], tmp))
      #        ID       Date Version
      #     <num>     <Date>  <char>
      #  1:     1 2020-03-25    CZ01
      #  2:     1 2020-05-08    CZ02
      #  3:     1 2020-06-15    CZ02
      #  4:     1 2020-07-05    CZ03
      #  5:     1 2020-09-26    CZ03
      #  6:     1 2020-10-03    CZ03
      #  7:     1 2020-10-25    CZ03
      #  8:     1 2020-11-02    CZ03
      #  9:     1 2020-11-19    CZ03
      # 10:     1 2020-11-25    CZ03
      # 11:     2 2020-09-18    BX01
      # 12:     2 2020-09-29    BX01
      # 13:     2 2020-12-06    BX02
      # 14:     2 2020-12-14    BX02
      # 15:     2 2020-07-16    BX01
      

      【讨论】:

        猜你喜欢
        • 2013-01-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-08-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多