[英]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
中選擇了最接近df1
的Date 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.