"fuzzy" inner_join 在 dplyr 中保留完全匹配和不完全匹配的两行

"fuzzy" inner_join in dplyr to keep both rows that do AND not exactly match

我正在处理两个我想加入的数据集,而不是基于它们之间的 精确 匹配,而是近似匹配。我的问题与此类似 OP.

以下是我的两个数据框的示例。

df1是这个:

 x
 4.8
 12  
 4  
 3.5
 12.5
 18  

df2是这个:

 x     y
 4.8   6.6
 12    1  
 4.5   1  
 3.5   0.5
 13    1.8
 15    2

我目前正在使用 inner_join(df1, df2, by=c("x") 将两者连接在一起。

这给了我:

 x     y
 4.8   6.6
 12    1
 3.5   0.5

但是,我真正想做的是根据这些条件加入两个 df

  1. 首先加入任何完全匹配(与 inner_join() 目前的工作方式完全一样)
  2. 但是,如果没有完全匹配,则加入任何匹配 ± 0.5

我试图获得的输出类型如下所示:

 x     y
 4.8   6.6
 12    1
 4     1    #the y value is from x=4.5 in df1
 4     0.5  #the y value is from x=3.5 in df1
 3.5   0.5
 12.5  1    #the y value is from x=12 in df1
 12.5  1.8  #the y value is from x=13 in df1 

我通常在 dplyr 工作,因此 dplyr 解决方案将不胜感激。但是,我也愿意接受其他建议,因为我不知道 dplyr 是否足够灵活以进行“模糊”连接。

(我知道 fuzzyjoin 包,但它似乎并没有完全理解我在这里尝试做的事情)

一个可能的解决方案,没有join

library(tidyverse)

df1 %>%
  rename(x1 = x) %>%
  crossing(df2) %>%
  mutate(diff = abs(x1-x)) %>% 
  filter(diff <= 0.5) %>% 
  group_by(x1) %>% 
  mutate(aux = any(diff == 0)) %>% 
  filter(aux*(diff == 0) | !aux) %>% 
  select(-diff, -aux) %>% 
  ungroup

#> # A tibble: 7 × 3
#>      x1     x     y
#>   <dbl> <dbl> <dbl>
#> 1   3.5   3.5   0.5
#> 2   4     3.5   0.5
#> 3   4     4.5   1  
#> 4   4.8   4.8   6.6
#> 5  12    12     1  
#> 6  12.5  12     1  
#> 7  12.5  13     1.8

您可以使用{powerjoin}

library(powerjoin)
power_left_join(
  df1, df2,
  by = ~ .x$x == .y$x | ! .x$x %in% .y$x & .x$x <= .y$x +.5 & .x$x >= .y$x -.5, 
  keep = "left")
#>      x   y
#> 1  4.8 6.6
#> 2 12.0 1.0
#> 3  4.0 1.0
#> 4  4.0 0.5
#> 5  3.5 0.5
#> 6 12.5 1.0
#> 7 12.5 1.8

reprex package (v2.0.1)

于 2022-04-14 创建