查看列表中的哪个向量包含在另一个列表的向量中(查找人的名字匹配)

时间:2018-07-25 20:42:06

标签: r list match sapply

我有一个人名向量列表,其中每个向量都只有名字和姓氏,而我还有另一个向量表,其中每个向量都具有名字,中间名字和姓氏。我需要匹配两个列表以查找两个列表中都包含的人。由于名称不按顺序排列(某些向量将名字作为第一个值,而另一些向量将姓氏作为第一个值),我想通过在第二个列表中查找哪个向量(全名)来匹配两个向量)包含第一个列表中向量的所有值(仅姓氏和名字)。

到目前为止我所做的:

#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()用于模糊匹配以解决名称中拼写错误的提示,那太好了!如果没有,那也没关系,因为我想至少首先获得匹配的零件。

4 个答案:

答案 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_listfull_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%完全按照您的意愿进行操作,它会检查完整的名称向量是否匹配。