r - 如何基于多列和条件进行模糊连接?
问题描述
我正在尝试左连接两个数据框(df1,df2)。数据框共有两列:区域和坡度。区域是一个因子列,斜率是数字。
df1 = data.frame(slope = c(1:6), zone = c(rep("Low", 3), rep("High", 3)))
df2 = data.frame(slope = c(2.4, 2.4,6.2), zone = c(rep("Low", 1), rep("High", 2)), other = c(rep("a", 1), rep("b", 1), rep("c", 1)))
df1
df2
我想加入数据框,以便它们首先在区域上完全匹配,然后是坡度最接近的匹配。如果有两个等距的斜率值,只要一致地应用规则并且不会导致重复行,连接向上还是向下舍入都没有关系。
我更喜欢用fuzzy_join 或dplyr 而不是data.table 来做到这一点。
结果应该类似于:
df3 = data.frame(slope = c(1:6), zone = c(rep("Low", 3), rep("High", 3)), other = c(rep("a", 3), rep("b",1), rep("c",2)))
df3
其中“其他”的值首先由区域确定,然后是最近的坡度。
我试过了:
distance_left_join(df, df2, by=c("zone"= "zone", "slope"="slope"))
以及其他类型的模糊连接,但我认为它们可能无法正常工作,因为列的类型不同。我怀疑有一个fuzzy_left_join 解决方案,但我不明白如何创建一个匹配函数。
解决方案
以下是如何使用多个 match_fun 进行模糊连接。如果你想混合复杂的 match_fun,你必须自己定义一个函数,就像我在这里所做的那样:Passing arguments into multiple match_fun functions in R blurjoin::fuzzy_join
df1 = data.frame(slope = c(1:6), zone = c(rep("Low", 3), rep("High", 3)))
df2 = data.frame(slope = c(2.4, 2.4,6.2), zone = c(rep("Low", 1), rep("High", 2)), other = c(rep("a", 1), rep("b", 1), rep("c", 1)))
library(fuzzyjoin); library(dplyr)
# First, need to define match_fun_distance.
# This is copied from the source code for distance_join in https://github.com/dgrtwo/fuzzyjoin
match_fun_distance <- function(v1, v2) {
# settings for this method
method = "manhattan"
max_dist = 99
distance_col = "dist"
if (is.null(dim(v1))) {
v1 <- t(t(v1))
v2 <- t(t(v2))
}
if (method == "euclidean") {
d <- sqrt(rowSums((v1 - v2)^2))
}
else if (method == "manhattan") {
d <- rowSums(abs(v1 - v2))
}
ret <- tibble::tibble(instance = d <= max_dist)
if (!is.null(distance_col)) {
ret[[distance_col]] <- d
}
ret
}
(joined_result <- fuzzy_join(df1, df2,
by=c("zone"= "zone", "slope"="slope"),
match_fun = list(`==`, match_fun_distance),
mode = "left"))
#> slope.x zone.x slope.y zone.y other slope.dist zone.dist
#> 1 1 Low 2.4 Low a 1.4 NA
#> 2 2 Low 2.4 Low a 0.4 NA
#> 3 3 Low 2.4 Low a 0.6 NA
#> 4 4 High 2.4 High b 1.6 NA
#> 5 4 High 6.2 High c 2.2 NA
#> 6 5 High 2.4 High b 2.6 NA
#> 7 5 High 6.2 High c 1.2 NA
#> 8 6 High 2.4 High b 3.6 NA
#> 9 6 High 6.2 High c 0.2 NA
joined_result %>%
group_by(slope.x, zone.x) %>%
top_n(1, -slope.dist)
#> # A tibble: 6 x 7
#> # Groups: slope.x, zone.x [6]
#> slope.x zone.x slope.y zone.y other slope.dist zone.dist
#> <int> <fct> <dbl> <fct> <fct> <dbl> <dbl>
#> 1 1 Low 2.4 Low a 1.4 NA
#> 2 2 Low 2.4 Low a 0.400 NA
#> 3 3 Low 2.4 Low a 0.6 NA
#> 4 4 High 2.4 High b 1.6 NA
#> 5 5 High 6.2 High c 1.2 NA
#> 6 6 High 6.2 High c 0.2 NA
由reprex 包于 2020-10-20 创建(v0.3.0)
推荐阅读
- javascript - 进入悬停时播放视频,然后在悬停时播放 gif,然后在离开悬停时播放另一个视频
- git - 在 git 上安装新包的最佳分支在哪里?
- azure - 为什么我在 Log Analytics 中看不到我的 Azure Web 应用程序的对象 ID,而是看到 Microsoft Azure 应用服务的对象 ID?
- java - 如何防止gradle在每次导入后将我的模块作为intellij中的孤儿模块删除
- python - TensorBoard Colab UnimplementedError 文件系统方案“[本地]”未实现
- r - 如何将我的数字数据放入具有两个级别的分类变量中
- javascript - Dispatch 不是函数 - 带有 React Redux Hooks 的 React 测试库
- modelica - 关于 Modelica 初始化的一般问题
- c++ - 如何在 C++ 中创建一个数组长度的 int?
- c# - 在通用存储库中加载导航属性