【问题标题】:How to fuzzy join based on multiple columns and conditions?如何基于多列和条件进行模糊连接?
【发布时间】:2019-09-24 08:45:09
【问题描述】:

我正在尝试左连接两个数据框(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

其中“other”的值首先由区域确定,然后是最近的坡度。

我试过了:

    distance_left_join(df, df2, by=c("zone"= "zone", "slope"="slope"))

以及其他类型的模糊连接,但我认为它们可能无法正常工作,因为列的类型不同。我怀疑有一个fuzzy_left_join 解决方案,但我不明白如何创建一个匹配函数。

【问题讨论】:

    标签: r fuzzyjoin


    【解决方案1】:

    这里是如何使用多个 match_fun 进行模糊连接。如果你想混合复杂的 match_funs,你必须自己定义一个函数,就像我在这里所做的那样:Passing arguments into multiple match_fun functions in R fuzzyjoin::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 package (v0.3.0) 于 2020 年 10 月 20 日创建

    【讨论】:

      猜你喜欢
      • 2019-05-24
      • 1970-01-01
      • 1970-01-01
      • 2021-11-13
      • 1970-01-01
      • 1970-01-01
      • 2023-04-01
      • 2018-07-25
      • 1970-01-01
      相关资源
      最近更新 更多