合并部分匹配的数据
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,或者其他什么。我的数据框有数千行,所以我无法一一调整它们。
使用 dplyr
和 fuzzyjoin
:
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
使用 :
范围)或不难单独添加。
我有两个大数据框,想根据其中一列合并它们。但是,某些单元格仅具有部分匹配。请看下面的例子:
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,或者其他什么。我的数据框有数千行,所以我无法一一调整它们。
使用 dplyr
和 fuzzyjoin
:
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
使用 :
范围)或不难单独添加。