R:跨两个数据帧的名字和姓氏(即两列)的组合的不区分大小写的匹配

时间:2014-11-11 12:28:47

标签: regex r match

在R中,我想提取完成我设计的两个版本测试的人员,然后分两个阶段进行管理(我向参与者询问他们的名字和姓氏)。

问题在于1.人们在使用资本方面并不一致; 2.有些人可能会与其他人分享名字或姓氏。因此,1。我需要一个不区分大小写的搜索; 2.我想提取一个新的数据框,列出第一个版本的名字和姓氏,以及第二个版本的名字和姓氏,以便验证匹配(也因为某人可能会使用&#34 ; Tom"在一个实例中," Thomas"在另一个实例中:

df1 <- data.frame(firstName = c("John", "Josef", "Tom", "Huckleberry", "Johann"),
                  lastName = c("Doe", "K", "Sawyer", "Finn", "Bach"))

df2 <- data.frame(firstName = c("John", "josef", "Thomas", "Huck", "Pap", "Johann Sebastian", "Johann"),
                  lastName = c("Doe", "K", "Sawyer", "Finn", "Finn", "Bach", "Pachelbel"))

上述名称都应该与我匹配以验证:

repeatDF <- data.frame(firstName.1 = c("John", "Josef", "Tom", "Huckleberry", "Huckleberry", "Johann", "Johann"),
                       lastName.1 = c("Doe", "K", "Sawyer", "Finn", "Finn", "Bach", "Bach"),
                       firstName.2 = c("John", "josef", "Thomas", "Huck", "Pap", "Johann Sebastian", "Johann"),
                       lastName.2 = c("Doe", "K", "Sawyer", "Finn", "Finn", "Bach", "Pachelbel"))

然后我(可能手动?)批准所有人,但约翰·帕切尔贝尔&#34;并且&#34; Pap Finn&#34;,因为他们可能与名字匹配,但与他们匹配的人不是同一个人。

到目前为止,我已尝试merge(另请参阅match two data.frames based on multiple columns)和%in%,但这两种方法都区分大小写,并且错过了某些匹配项。我以某种方式无法使用apply使用grep函数(必须承认:这些函数不是很流畅),但也不知道如何考虑使用grep的姓氏和姓氏?我是在寻找正确的方向,还是应该使用完全不同的功能?

非常感谢任何帮助!

PS。似乎有很多很多类似的问题,但要么是针对不同的程序,要么是不需要我的两个考虑因素 - 如果确实已经有了我的问题的答案,请道歉!

1 个答案:

答案 0 :(得分:1)

这似乎基于OP的评论和新数据集。我稍微更改了df2,因此两个数据框中的名称顺序不同。

df1 <- data.frame(firstName = c("John", "Josef", "Tom", "Huckleberry", "Johann"),
                 lastName = c("Doe", "K", "Sawyer", "Finn", "Bach"))

df2 <- data.frame(firstName = c("John", "josef", "Huck", "Pap", "Johann Sebastian", "Johann", "Thomas"),
                  lastName = c("Doe", "K", "Finn", "Finn", "Bach", "Pachelbel", "Sawyer"))
get.match <- function(A,B) {
  A <- as.list(tolower(A)); B <- as.list(tolower(B))
  match.last  <- grepl(A$lastName,B$lastName)|grepl(B$lastName,A$lastName)
  match.first <- grepl(A$firstName,B$firstName)|grepl(B$firstName,A$firstName)
  match.first | match.last
} 

indx    <- apply(df2,1,function(row) apply(df1,1,get.match,row))
indx
#       [,1]  [,2]  [,3]  [,4]  [,5]  [,6]  [,7]
# [1,]  TRUE FALSE FALSE FALSE FALSE FALSE FALSE
# [2,] FALSE  TRUE FALSE FALSE FALSE FALSE FALSE
# [3,] FALSE FALSE FALSE FALSE FALSE FALSE  TRUE
# [4,] FALSE FALSE  TRUE  TRUE FALSE FALSE FALSE
# [5,] FALSE FALSE FALSE FALSE  TRUE  TRUE FALSE

m.1     <- df1[rep(1:nrow(df1),apply(indx,1,sum)),]
result  <- cbind(m.1,do.call(rbind,apply(indx,1,function(i)df2[i,])))
result
#       firstName lastName        firstName  lastName
# 1          John      Doe             John       Doe
# 2         Josef        K            josef         K
# 3           Tom   Sawyer           Thomas    Sawyer
# 4   Huckleberry     Finn             Huck      Finn
# 4.1 Huckleberry     Finn              Pap      Finn
# 5        Johann     Bach Johann Sebastian      Bach
# 5.1      Johann     Bach           Johann Pachelbel

因此,这使用get.match(...)中实现的算法,该算法将df1行与df2行进行比较,如果任一行中的第一个名称存在,则返回TRUE在另一行的第一个名称中,任一行中的姓氏都出现在另一行的姓氏中。这一行:

indx    <- apply(df2,1,function(row) apply(df1,1,get.match,row))

然后创建一个indx矩阵,其中行代表df1中的行,列代表df2,元素为TRUE如果df1df2的相应行匹配。这样就可以在df1df2中进行多次匹配。最后,我们将此indx矩阵转换为您想要使用的result

m.1     <- df1[rep(1:nrow(df1),apply(indx,1,sum)),]
result  <- cbind(m.1,do.call(rbind,apply(indx,1,function(i)df2[i,])))

此代码提取在df1中匹配的df2的所有行,然后将其绑定到df2的相应行。