内连接恰好在一列上,而在另一列上模糊

Posted

技术标签:

【中文标题】内连接恰好在一列上,而在另一列上模糊【英文标题】:Inner join exactly on one column and fuzzy on another 【发布时间】:2018-02-11 05:02:25 【问题描述】:

我有两个要加入的数据框。它们共享两个字段:group_idperson_name。我想完全加入group_id 和模糊person_name。我该怎么做?

约束:

它应该是一个内连接。所以group_id正好和person_namefuzzy必须同时出现在左右帧中。 真正的数据帧很大。我试过the answer suggested by David Robinson using his package fuzzyjoin,但是数据太多,无法在过滤之前创建笛卡尔积。 我希望在tidyverse 中得到答案,但这不是绝对必要的。

这是一个小例子:

a = data.frame(
    group_id=c(1,2,2,3,3,3),
    person_name=c('Alice', 'Bob', 'Charlie', 'David', 'Eve', 'Frank'),
    eye_color=c('brown', 'green', 'blue', 'brown', 'green', 'blue')
)
b = data.frame(
    group_id=c(2,2,2,3,3,3,3),
    person_name=c('Alie', 'Bobo', 'Charles', 'Charlie', 'Davis', 'Eva', 'Zed' ),
    hair_color=c('brown', 'brown', 'black', 'grey', 'brown', 'black', 'blond')
)
expected = data.frame(
    group_id=c(2,2,3,3),
    person_name_x=c('Bob', 'Charlie', 'David', 'Eve'),
    person_name_y=c('Bobo', 'Charles', 'Davis', 'Eva'),
    eye_color=c('green', 'blue', 'brown', 'green'),
    hair_color=c('brown', 'black', 'brown', 'black')
)

【问题讨论】:

您可能想查看包RecordLinkage(见答案)或fastLink,它们允许阻塞和模糊匹配。 【参考方案1】:

你可以试试

library(RecordLinkage)
library(tidyverse)
compare.linkage(a, b, strcmp = 2, exclude=3, blockfld = 1) %>% 
  epiWeights %>% 
  epiClassify(.8) %>% 
  getPairs(show="links", single.rows=T) %>% 
  .[(c(2,3,7,4,8))]
# group_id.1 person_name.1 person_name.2 eye_color.1 hair_color.2
# 3          2       Charlie       Charles        blue        black
# 2          2           Bob          Bobo       green        brown
# 4          3         David         Davis       brown        brown
# 5          3           Eve           Eva       green        black

【讨论】:

【参考方案2】:

在这个例子中,我们基本上需要一个混合连接。对于一列 (group_id),我们需要精确匹配列名,而对于另一列 (person_name),我们需要模糊连接。

一种方法:

library(fuzzyjoin)
common_id <- intersect(a$group_id, b$group_id)
stringdist_inner_join(a[a$group_id %in% common_id, ], b[b$group_id %in% common_id, ], 
                                                      by = "person_name")

# group_id.x person_name.x eye_color group_id.y person_name.y hair_color
#        <dbl>        <fctr>    <fctr>      <dbl>        <fctr>     <fctr>
#1          2           Bob     green          2          Bobo      Brown
#2          2       Charlie      blue          2       Charles      Black
#3          3         David     brown          3         Davis      Brown
#4          3           Eve     green          3           Eva      Black

在这里,我们首先使用intersect 找到两个数据帧中都存在的常见group_id,并从ab 中相应地过滤它们,然后仅在person_name 上使用stringdist_inner_join 函数柱子。我们稍后可以删除已经生成的额外的group_id 列。

【讨论】:

这不会检查group_id 上的完全匹配。我编辑了我的测试用例来演示。这样做然后过滤会占用太多内存。 @Hatshepsut 所以你试过df &lt;- stringdist_inner_join(a, b, by = "person_name"); df[df$group_id.x == df$group_id.y, ] 对吗?

以上是关于内连接恰好在一列上,而在另一列上模糊的主要内容,如果未能解决你的问题,请参考以下文章

在一列上排名表,同时在另一列上排序

PostgreSQL 中的高效全文搜索,在另一列上排序

选择一列上的值在另一列上具有相同的一组值

熊猫在一列上分组,另一列上的最大日期python

在一个列上应用 distinct 并在另一列上按 count 排序

如何在另一列上显示html表格的计算