合并部分匹配的数据

Merging data with partial match

我有两个大数据框,想根据其中一列合并它们。但是,某些单元格仅具有部分匹配。请看下面的例子:

df1 = data.frame(SampleID = c(1:6), Gene = c("ARF5;ARG1","AP3B1","CLDN5","XPO1;STX7","ABCC4","FLOT1"))
df2 = data.frame(Operation = c("Y"), Gene = c("ARG1","CLDN5;STK10","XPO1","PDE5A","ARF5","IPO7","VAPB","ABCC4"))           
#-----------------
SampleID Gene
1        ARF5;ARG1
2        AP3B1
3        CLDN5
4        XPO1;STX7
5        ABCC4
6        FLOT1
#-----------------
Operation Gene
Y         ARG1
Y         CLDN5;STK10
Y         XPO1
Y         PDE5A
Y         ARF5
Y         IPO7
Y         VAPB
Y         ABCC4

预期输出

#-----------------
    SampleID Gene       Operation
    1        ARF5;ARG1  Y
    2        AP3B1      -
    3        CLDN5      Y
    4        XPO1;STX7  Y
    5        ABCC4      Y
    6        FLOT1      -

可以看到df1$Gene和df2$Gene部分匹配,我想在匹配的时候把Operation信息添加到df1中。在这个例子中,df1 的第 1 行和第 4 行与 df2 的第 1 行和第 2 行部分匹配。对于那些没有匹配的,它可以是 NA,或者其他什么。我的数据框有数千行,所以我无法一一调整它们。

使用 dplyrfuzzyjoin:

library(dplyr)
# library(fuzzyjoin) # regex_left_join
df2 %>%
  mutate(Gene = sapply(strsplit(Gene, ";"), function(z) paste0("\b(", paste(z, collapse = "|"), ")\b"))) %>%
  fuzzyjoin::regex_left_join(df1, ., by = "Gene") %>%
  group_by(SampleID) %>%
  summarize(Gene = Gene.x[1], Operation = na.omit(Operation)[1], .groups = "drop")
# # A tibble: 6 x 3
#   SampleID Gene      Operation
#      <int> <chr>     <chr>    
# 1        1 ARF5;ARG1 Y        
# 2        2 AP3B1     NA       
# 3        3 CLDN5     Y        
# 4        4 XPO1;STX7 Y        
# 5        5 ABCC4     Y        
# 6        6 FLOT1     NA       

第一步将 df2$Gene[2]CLDN5;STK10 转换为 \b(CLDN5|STK10)\b,该模式允许匹配其任何 ; 分隔值(根据您的预期推断输出)。


编辑:如果你有很多其他列,你可以将它们添加到分组中,这样你就不需要明确地总结它们(使用[1]).例如,上面可能被重写为:

df2 %>%
  mutate(Gene = sapply(strsplit(Gene, ";"), function(z) paste0("\b(", paste(z, collapse = "|"), ")\b"))) %>%
  fuzzyjoin::regex_left_join(df1, ., by = "Gene") %>%
  rename(Gene = Gene.x) %>%
  group_by(across(SampleID:Gene)) %>%
  summarize(Operation = na.omit(Operation)[1], .groups = "drop")
# # A tibble: 6 x 3
#   SampleID Gene      Operation
#      <int> <chr>     <chr>    
# 1        1 ARF5;ARG1 Y        
# 2        2 AP3B1     NA       
# 3        3 CLDN5     Y        
# 4        4 XPO1;STX7 Y        
# 5        5 ABCC4     Y        
# 6        6 FLOT1     NA       

(不需要将 Gene.x 重命名为 Gene,但看起来不错 :-)

此方法假定您要保留的所有列都是连续的(允许 fromcolumn:tocolumn 使用 : 范围)或不难单独添加。