匹配两个数据框之间的字符串并将缺失的字符串添加到 R 中不完整的字符串

Match strings between two data frame and add missing strings to strings which are not complete in R

我有两个数据框,有 4 个不同的列,顺序不同。一个数据框 1 有一个 ID 列,其中的字符串具有完整且正确的名称。然后我有一个数据框 2,其中的 ID 列不完整 (ID_not_complete)。数据框 1 有更多行并且包含数据框 2 中 100% 的所有字符串。我想将缺失的字符串添加到数据框 2 中的 ID_not_complete 列。在我的示例中,数据框 2 中的字符串可以在数据框 1 中有多个匹配项,但只有一个匹配字符串的确切长度:

  1. rs1725 --> AX-42144793569__rs1725
  2. rs1725 --> AX-42179369__rs1725074

第一个选项应该是正确的。

数据框 1

ID<-c("AX-35388475__rs16896864","AX-11425569__rs289621","AX-11102771__rs10261724","AX-42179369__rs1725074","AX-42144793569__rs1725","AX-42749369__rs264930","AX-32893019__rs6114382")
ID<-as.data.frame(ID)

数据框 2

ID_not_complete<-c("rs16896864","rs289621","rs10261724","rs1725074","rs1725")
ID_not_complete <-as.data.frame(ID_not_complete)

输出数据框 2 应如下所示:

ID_complete<-c("AX-35388475__rs16896864","AX-11425569__rs289621","AX-11102771__rs10261724","AX-42179369__rs1725074","AX-42144793569__rs1725")
ID_complete <-as.data.frame(ID_complete)

我想我需要使用 grep。但我真的不知道如何处理列中的每个值。

fuzzyjoin 包允许加入正则表达式(模式)。

第一个(有缺陷的)方法是:

fuzzyjoin::regex_inner_join(ID, ID_not_complete, by = c(ID="ID_not_complete"))
#                            ID ID_not_complete
# 1     AX-35388475__rs16896864      rs16896864
# 2       AX-11425569__rs289621        rs289621
# 3 AX-11102771__rs10261724          rs10261724
# 4      AX-42179369__rs1725074       rs1725074
# 5      AX-42179369__rs1725074          rs1725
# 6      AX-42144793569__rs1725          rs1725

其中 rs1725 匹配 rs1725rs1725074(匹配前导字符)。我会推断你并不是要发生这种情况,所以使用一些额外的类似边界的模式快速修复(也纠正你的数据有空格):

ID_not_complete$ptn <- paste0("(^|[\s_])", ID_not_complete$ID_not_complete, "([\s_]|$)")
fuzzyjoin::regex_inner_join(ID, ID_not_complete, by = c(ID="ptn"))
#                            ID ID_not_complete                            ptn
# 1     AX-35388475__rs16896864      rs16896864 (^|[\s_])rs16896864([\s_]|$)
# 2       AX-11425569__rs289621        rs289621   (^|[\s_])rs289621([\s_]|$)
# 3 AX-11102771__rs10261724          rs10261724 (^|[\s_])rs10261724([\s_]|$)
# 4      AX-42179369__rs1725074       rs1725074  (^|[\s_])rs1725074([\s_]|$)
# 5      AX-42144793569__rs1725          rs1725     (^|[\s_])rs1725([\s_]|$)

(旁注:我最初想要并打算在模式中使用正则表达式字边界 \b,但根据 https://www.regular-expressions.info/shorthand.html,它认为 [A-Za-z0-9_] 是“字字符”,所以真实ID前面的_不是边界。所以如果其他用户有类似的问题没有使用下划线,那么(^|[\s_])可以完全替换为\b ,与结束模式类似。)


编辑

如果您只需要从 ID 中过滤掉那些没有找到的东西,那么也许只需

paste0("_(", paste(ID_not_complete$ID_not_complete, collapse = "|"), ") *$")
# [1] "_(rs16896864|rs289621|rs10261724|rs1725074|rs1725) *$"
grepl(paste0("_(", paste(ID_not_complete$ID_not_complete, collapse = "|"), ") *$"), ID$ID)
# [1]  TRUE  TRUE  TRUE  TRUE  TRUE FALSE FALSE
ID[grepl(paste0("_(", paste(ID_not_complete$ID_not_complete, collapse = "|"), ") *$"), ID$ID),,drop=FALSE]
#                            ID
# 1     AX-35388475__rs16896864
# 2       AX-11425569__rs289621
# 3 AX-11102771__rs10261724    
# 4      AX-42179369__rs1725074
# 5      AX-42144793569__rs1725

gsub("\s", "", gsub(".*_", "", ID$ID))
# [1] "rs16896864" "rs289621"   "rs10261724" "rs1725074"  "rs1725"     "rs264930"   "rs6114382" 
ID[ gsub("\s", "", gsub(".*_", "", ID$ID)) %in% ID_not_complete$ID_not_complete,,drop=FALSE]
#                            ID
# 1     AX-35388475__rs16896864
# 2       AX-11425569__rs289621
# 3 AX-11102771__rs10261724    
# 4      AX-42179369__rs1725074
# 5      AX-42144793569__rs1725

编辑:

数据:

ID <- c("AX-35388475__rs16896864","AX-11425569__rs289621","AX-11102771__rs10261724","AX-42179369__rs1725074","AX-42144793569__rs1725","AX-42749369__rs264930","AX-32893019__rs6114382")

df1 <- data.frame(
  ID = ID
)

ID_not_complete<-c("rs16896864","rs289621","rs10261724","rs1725074","rs1725")

df2 <- data.frame(
  ID_not_complete = ID_not_complete
)

解决方法: 首先定义模式:

patt0 <- paste0(sub("([^_]+)__(.*)", "\2", df1$ID), collapse = "|")
patt1 <- paste0(df2$ID_not_complete, collapse = "|")

现在变换df2$ID_not_complete:

df2$ID_not_complete <- paste0(sub("([^_]+)__(.*)", "\1__", df1$ID[grepl(patt1, df1$ID)]),
                          grep(patt0, df2$ID_not_complete, value = T))

结果:

df2
          ID_not_complete
1 AX-35388475__rs16896864
2   AX-11425569__rs289621
3 AX-11102771__rs10261724
4  AX-42179369__rs1725074
5  AX-42144793569__rs1725