use*_*007 8 string r dplyr partial-matches
我正在使用R
一些数据框。我的问题与如何检查第一个数据帧中的变量值是否与另一个数据帧中的值匹配有关。merge
该匹配与或 之类的匹配非常不同join
。我将介绍我的数据框(dput()
最后):
我的第一个数据框是df1
. name
它包含我想与第二个数据帧中的其他变量进行对比的变量。它看起来像这样:
df1
name
1 JUAN GIRON
2 GINA OLEAS
3 JUAN FERNANDO ELIZAGA
4 MARCO TORRES
5 JUAN PABLO GONZALEZ
6 IRMA GOMEZ
Run Code Online (Sandbox Code Playgroud)
第二个数据框是df2
. 它还包含一个变量name
,用于与name
from进行对比df1
。它看起来像这样(在实际情况中df2
可能非常大,超过 1000 行):
df2
name val
1 JUANA MARQUEZ 1
2 FERNANDO ELIZAGA 2
3 IRMA GOMEZ 3
4 PABLO GONZALEZ 4
5 GINA LUCIO 5
6 MARK TORRES 6
7 LETICIA BLACIO 7
8 JUAN PABLO GIRON BELTRAN 8
Run Code Online (Sandbox Code Playgroud)
我正在寻找一种方法来检查df1
forname
变量的每一行是否包含或与name
in的任何值匹配df2
。例如,JUAN GIRON
使用name
from检查后的值df2
应该返回,给出值 ,yes
因为它包含在字符串JUAN PABLO GIRON BELTRAN
from中df2
。同样的情况也适用于其他值。最后我想要这样的东西:
df3
name val
1 JUAN GIRON yes
2 GINA OLEAS no
3 JUAN FERNANDO ELIZAGA yes
4 MARCO TORRES no
5 JUAN PABLO GONZALEZ yes
6 IRMA GOMEZ yes
Run Code Online (Sandbox Code Playgroud)
我怎样才能达到这个结果?我尝试过grepl()
使用连接字符串|
,但它不起作用,因为某些值yes
在不匹配时返回匹配。
另外,由于数据可能很大,我希望有一个解决方案dplyr
,因为比较是按行进行的,所以速度可能很慢。或者欢迎任何快速解决方案。非常感谢!
接下来是数据:
#df1
df1 <- structure(list(name = c("JUAN GIRON", "GINA OLEAS", "JUAN FERNANDO ELIZAGA",
"MARCO TORRES", "JUAN PABLO GONZALEZ", "IRMA GOMEZ")), row.names = c(NA,
-6L), class = "data.frame")
#df2
df2 <- structure(list(name = c("JUANA MARQUEZ", "FERNANDO ELIZAGA",
"IRMA GOMEZ", "PABLO GONZALEZ", "GINA LUCIO", "MARK TORRES",
"LETICIA BLACIO", "JUAN PABLO GIRON BELTRAN"), val = 1:8), row.names = c(NA,
-8L), class = "data.frame")
Run Code Online (Sandbox Code Playgroud)
也许我们可以这样做
df1 %>%
mutate(val = c("no", "yes")[1 + (rowSums(
outer(
strsplit(name, "\\s+"),
strsplit(df2$name, "\\s+"),
Vectorize(function(x, y) all(x %in% y) | all(y %in% x))
)
) > 0)])
Run Code Online (Sandbox Code Playgroud)
这使
name val
1 JUAN GIRON yes
2 GINA OLEAS no
3 JUAN FERNANDO ELIZAGA yes
4 MARCO TORRES no
5 JUAN PABLO GONZALEZ yes
6 IRMA GOMEZ yes
Run Code Online (Sandbox Code Playgroud)
这是一种使用正则表达式模式并处理长度为 2 或 3 的名称的方法。还有改进的空间,我很想阅读这个问题的其他答案。
# Input
a <- strsplit(df2$name, " ")
# Output
b <- c()
# Define regex pattern
for(i in 1:length(a)){
if(length(a[[i]]) == 3){
temp <- paste0(
a[[i]][1], " ", a[[i]][2], "|",
a[[i]][1], " ", a[[i]][3], "|",
a[[i]][2], " ", a[[i]][3])
} else if(length(a[[i]] == 2)){
temp <- paste(a[[i]], collapse = " ")
} else {
stop("Length of split name was not 2 or 3")
}
b <- c(b, temp)
}
df1$val <- grepl(paste(b, collapse = "|"), df1$name)
Run Code Online (Sandbox Code Playgroud)
或者,在b
使用上面的循环定义之后:
library(dplyr)
patt <- paste(b, collapse = "|")
df1 %>%
mutate(val = grepl(patt, name))
Run Code Online (Sandbox Code Playgroud)
结果:
> df1
name val
1 JUAN GIRON TRUE
2 GINA OLEAS FALSE
3 JUAN FERNANDO ELIZAGA TRUE
4 MARCO TORRES FALSE
5 JUAN PABLO GONZALEZ TRUE
6 IRMA GOMEZ TRUE
Run Code Online (Sandbox Code Playgroud)