【发布时间】:2021-03-12 21:12:28
【问题描述】:
我在代码中经常使用 dplyr,并且经常必须在日期上完成非 equi left join。我想使用整洁的语法和管道来做到这一点。我看到了一个名为fuzzyjoin 的包,它完成了这个任务,但是我正在使用的客户端在他们的服务器上没有这个包。他们有一套标准的软件包,安装新软件包很困难。现在,我已经编写了这个函数,non_equi_left_join,它可以帮助我完成我想要完成的任务:
library(data.table)
library(dplyr)
library(lubridate)
# lst_conditions: conditions for the left join
non_equi_left_join <- function(df_lhs, df_rhs, lst_conditions) {
sel_columns_lhs <- unique(unlist(map(lst_conditions, 1)))
sel_columns_rhs <- unique(unlist(map(lst_conditions, 3)))
setDT(df_lhs)[, paste0(sel_columns_lhs, "_tempJoin") := mget(sel_columns_lhs)]
setDT(df_rhs)[, paste0(sel_columns_rhs, "_tempJoin") := mget(sel_columns_rhs)]
onkey <- unlist(paste(
paste0(map(lst_conditions, 3), "_tempJoin"),
map(lst_conditions, 2),
paste0(map(lst_conditions, 1), "_tempJoin")
))
df_ret <-
df_rhs[df_lhs, on = onkey]
df_ret[, grep(".*_tempJoin$", colnames(df_ret)):=NULL]
return(setDF(df_ret) %>% as_tibble())
}
_tempJoin 部分是为了摆脱这篇文章中列出的行为:fuzzyjoin two data frames using data.table
我创建了加入中涉及的所有列的副本,并在加入后立即删除它们。该函数帮助我编写以下代码:
df1 <- data.frame(
ID = c(1L,2L,3L,3L),
CallDate = c(ymd("2021-01-20"), ymd("2021-02-20"), ymd("2021-02-04"), ymd("2021-04-02"))
) %>% as_tibble()
df2 <- data.frame(
ID = c(1L,2L,3L,3L),
CustomerType = c("basic", "basic", "basic", "premium"),
StartDate = c(ymd("2021-02-02"), ymd("2021-02-02"), ymd("2021-02-02"), ymd("2021-02-05")),
EndDate = c(ymd("2099-01-01"), ymd("2099-01-01"), ymd("2021-02-05"), ymd("2099-01-01"))
) %>% as_tibble()
lst_condition <-
list(c("ID", "==", "ID"),
c("CallDate", "<=", "StartDate"),
c("CallDate", ">=", "EndDate") )
df1 %>%
non_equi_left_join(., df2, lst_condition)
我知道它很粗糙,但在我测试它的示例上运行良好。我担心它可能会默默地给我不正确的结果。这里需要专家意见。我使用的数据通常是几百 MB 的数据帧。
谢谢。
【问题讨论】:
-
您可能需要包含许可证并且应该感谢创建者,但是由于
fuzzyjoin是开源的,您不能只复制并粘贴您需要的功能的源代码到您的“自定义”代码?一种安装新软件包的穷人方式。
标签: r dplyr data.table