簡體   English   中英

使用 +/- 3 天按日期加入兩個數據框

[英]Join two data frames by date using +/- 3 days

嗨,我有兩個數據框。

都有 ID 變量和日期變量。 我想按 ID 和日期加入,但日期可以以正負 3 天的方式加入。 第一個數據幀的順序需要保留。 這兩個數據框有不同的長度,並不是所有的日期或 ID 都會對齊。 ID 也可以在不同日期有 2 個或更多條目作為不同的 collections。

希望這是有道理的。

第一個數據框 -

structure(list(ID = c(1, 1, 1, 2, 3, 3, 3, 4, 5, 5, 5, 6, 6, 
6, 6, 7), `Date Collected` = structure(c(18903, 18936, 18976, 
18539, 18508, 18581, 18655, 17688, 17975, 18037, 18297, 18081, 
18242, 18338, 18721, 18128), class = "Date")), row.names = c(NA, 
-16L), class = c("tbl_df", "tbl", "data.frame"))

第二個數據框 -

structure(list(ID = c(1, 1, 1, 1, 3, 3, 3, 4, 4, 4, 5), `Date Relapse` = structure(c(18900, 
18938, 18973, 19004, 18511, 18578, 18657, 17322, 17685, 18129, 
18300), class = "Date")), row.names = c(NA, -11L), class = c("tbl_df", 
"tbl", "data.frame"))

這是一個整潔的解決方案。

group_modify采用分組的 tibble 並將 function 應用於每個組。 function 應該帶兩個 arguments。 第一個提供當前組中的行(不包括定義組的列,第二個是單列 tibble,定義組的每一列都有一列。此 tibble 的一行中的包含定義的值當前組。

由於您還沒有定義如何解決關系,我只是在df2中選擇了最接近df1Date Collected的行。 如果df2中的兩行與Date Collected等距,則取較早的行。

# Modify to allow validation
df2 <- df2 %>% 
         mutate(Row2=row_number())

df1 %>% 
  group_by(ID, `Date Collected`) %>% 
  group_modify(
    function(.x, .y) {
      t <- df2 %>% 
             filter(ID == .y$ID) %>% 
             add_column(Delta=abs(as.numeric(.y$`Date Collected` - .$`Date Relapse`))) %>% 
             arrange(Delta) %>% 
             filter(Delta <= 3) %>% 
             head(1) %>% 
             select(-ID)
      if (t %>% nrow() > 0) {
        .x %>% bind_cols(t)
      } else {
        .x
      }
    }
  )
# A tibble: 16 × 5
# Groups:   ID, Date Collected [16]
      ID `Date Collected` `Date Relapse`  Row2 Delta
   <dbl> <date>           <date>         <int> <dbl>
 1     1 2021-10-03       2021-09-30         1     3
 2     1 2021-11-05       2021-11-07         2     2
 3     1 2021-12-15       2021-12-12         3     3
 4     2 2020-10-04       NA                NA    NA
 5     3 2020-09-03       2020-09-06         5     3
 6     3 2020-11-15       2020-11-12         6     3
 7     3 2021-01-28       2021-01-30         7     2
 8     4 2018-06-06       2018-06-03         9     3
 9     5 2019-03-20       NA                NA    NA
10     5 2019-05-21       NA                NA    NA
11     5 2020-02-05       2020-02-08        11     3
12     6 2019-07-04       NA                NA    NA
13     6 2019-12-12       NA                NA    NA
14     6 2020-03-17       NA                NA    NA
15     6 2021-04-04       NA                NA    NA
16     7 2019-08-20       NA                NA    NA

有一種更簡單的方法 - 使用非 equi 連接

library(data.table)
setDT(df2)[,`:=`(d_lower = `Date Relapse`-3, d_upper = `Date Relapse`+3)]

df2[
  i=setDT(df1),
  on = .(ID, d_lower<=`Date Collected`, d_upper>=`Date Collected`),
  j=.(ID, "Date Collected"=d_lower, `Date Relapse`)
]

如果您更喜歡 dplyr,只需加入 ID,然后根據需要進行過濾

left_join(df1,inner_join(df1,df2, by="ID") %>%
  filter(abs(`Date Collected`-`Date Relapse`)<=3),
  by=c("ID", "Date Collected")
)

無論哪種方式,output:

    ID Date Collected Date Relapse
 1:  1     2021-10-03   2021-09-30
 2:  1     2021-11-05   2021-11-07
 3:  1     2021-12-15   2021-12-12
 4:  2     2020-10-04         <NA>
 5:  3     2020-09-03   2020-09-06
 6:  3     2020-11-15   2020-11-12
 7:  3     2021-01-28   2021-01-30
 8:  4     2018-06-06   2018-06-03
 9:  5     2019-03-20         <NA>
10:  5     2019-05-21         <NA>
11:  5     2020-02-05   2020-02-08
12:  6     2019-07-04         <NA>
13:  6     2019-12-12         <NA>
14:  6     2020-03-17         <NA>
15:  6     2021-04-04         <NA>
16:  7     2019-08-20         <NA>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM