我有一个人名向量列表,其中每个向量都只有名字和姓氏,而我还有另一个向量表,其中每个向量都具有名字,中间名字和姓氏。我需要匹配两个列表以查找两个列表中都包含的人。由于名称不按顺序排列(某些向量将名字作为第一个值,而另一些向量将姓氏作为第一个值),我想通过在第二个列表中查找哪个向量(全名)来匹配两个向量)包含第一个列表中向量的所有值(仅姓氏和名字)。
到目前为止我所做的:
#reproducible example
first_last_names_list <- list(c("boy", "boy"),
c("bob", "orengo"),
c("kalonzo", "musyoka"),
c("anami", "lisamula"))
full_names_list <- list(c("boy", "juma", "boy"),
c("stephen", "kalonzo", "musyoka"),
c("james", "bob", "orengo"),
c("lisamula", "silverse", "anami"))
首先,我尝试创建一个函数来检查另一个矢量中是否包含一个矢量(很大程度上基于here中的代码)。
my_contain <- function(values,x){
tx <- table(x)
tv <- table(values)
z <- tv[names(tx)] - tx
if(all(z >= 0 & !is.na(z))){
paste(x, collapse = " ")
}
}
#value would be the longer vector (from full_name_list)
#and x would be the shorter vector(from first_last_name_list)
然后,我尝试将此函数放在sapply()中,以便可以使用列表,这就是我遇到的问题。我可以查看一个向量列表中是否包含一个向量,但是我不确定如何检查一个列表中的所有向量,以及第二个列表中的向量中是否包含该向量。 >
#testing with the first vector from first_last_names_list.
#Need to make it run through all the vectors from first_last_names_list.
sapply(1:length(full_names_list),
function(i) any(my_contain(full_names_list[[i]],
first_last_names_list[[1]]) ==
paste(first_last_names_list[[1]], collapse = " ")))
#[1] TRUE FALSE FALSE FALSE
最后-尽管在一个问题中问得太多了-如果有人能给我任何关于如何将agrep()用于模糊匹配以解决名称中拼写错误的提示,那太好了!如果没有,那也没关系,因为我想至少首先获得匹配的零件。
答案 0 :(得分:1)
编辑 我已经修改了解决方案,以满足诸如“ John John”之类的重复名称与“ John Smith”不匹配的约束。
apply(sapply(first_last_names_list, unlist), 2, function(x){
any(sapply(full_names_list, function(y) sum(unlist(y) %in% x) >= length(x)))
})
此解决方案仍然使用%in%
和apply函数,但是它现在进行了一种反向搜索-针对它查看的first_last
名称中的每个元素
full_names
列表中每个名称中的多少个单词都匹配。如果此数字大于或等于正在考虑的first_list
名称项中的单词数(示例中始终为2个单词,但是代码可使用任何数量)返回TRUE。然后将此逻辑数组与ANY
进行聚合,以传回单个向量,该向量显示每个first_last是否与任何全名都匹配。
例如,“ John John” 不会与“ John Smith Random”匹配,因为“ John Smith Random”中三个单词中只有一个匹配。但是,它会与“约翰·亚当·约翰”相匹配,因为“约翰·亚当·约翰”中的3个单词中有2个是匹配的,而2个等于“约翰·约翰”的长度。它也将与“ John John John John John”匹配,因为这5个单词中有5个匹配,大于2。
答案 1 :(得分:1)
由于您正在处理lists
,最好将它们折叠成向量,以便于处理正则表达式。但是您只是按升序排列它们。在这种情况下,您可以轻松匹配它们:
lst=sapply(first_last_names_list,function(x)paste0(sort(x),collapse=" "))
lst1=gsub("\\s|$",".*",lst)
lst2=sapply(full_names_list,function(x)paste(sort(x),collapse=" "))
(lst3 = Vectorize(grep)(lst1,list(lst2),value=T,ignore.case=T))
boy.*boy.* bob.*orengo.* kalonzo.*musyoka.* anami.*lisamula.*
"boy boy juma" "bob james orengo" "kalonzo musyoka stephen" "anami lisamula silverse"
现在,如果您要链接first_name_last_name_list
和full_name_list
,则:
setNames(full_names_list[ match(lst3,lst2)],sapply(first_last_names_list[grep(paste0(names(lst3),collapse = "|"),lst1)],paste,collapse=" "))
$`boy boy`
[1] "boy" "juma" "boy"
$`bob orengo`
[1] "james" "bob" "orengo"
$`kalonzo musyoka`
[1] "stephen" "kalonzo" "musyoka"
$`anami lisamula`
[1] "lisamula" "silverse" "anami"
,其中名称来自first_last_list,元素来自full_name_list。您最好处理字符向量而不是列表:
答案 2 :(得分:0)
而不是my_contain,请尝试
x %in% values
也许还取消列出并使用数据框?不知道您是否考虑过-可能会使事情变得更容易:
# unlist to vectors
fl <- unlist(first_last_names_list)
fn <- unlist(full_names_list)
# grab individual names and convert to dfs;
# assumptions: first_last_names_list only contains 2-element vectors
# full_names_list only contains 3-element vectors
first_last_df <- data.frame(first_fl=fl[c(T, F)],last_fl=fl[c(F, T)])
full_name_df <- data.frame(first_fn=fn[c(T,F,F)],mid_fn=fn[c(F,T,F)],last_fn=fn[c(F,F,T)])
答案 3 :(得分:0)
或者您可以这样做:
first_last_names_list <- list(c("boy", "boy"),
c("bob", "orengo"),
c("kalonzo", "musyoka"),
c("anami", "lisamula"))
full_names_list <- list(c("boy", "juma", "boy"),
c("stephen", "kalonzo", "musyoka"),
c("james", "bob", "orengo"),
c("lisamula", "silverse", "anami"),
c("musyoka", "jeremy", "kalonzo")) # added just to test
# create copies of full_names_list without middle name;
# one list with matching name order, one with inverted order
full_names_short <- lapply(full_names_list,function(x){x[c(1,3)]})
full_names_inv <- lapply(full_names_list,function(x){x[c(3,1)]})
# check if names in full_names_list match either
full_names_list[full_names_short %in% first_last_names_list | full_names_inv %in% first_last_names_list]
在这种情况下,%in%
完全按照您的意愿进行操作,它会检查完整的名称向量是否匹配。