使用dplyr,tidyr和regex将名称的不同组合分为第一个和最后一个

时间:2016-11-01 15:53:26

标签: r regex dplyr tidyr stringr

示例数据框:

name <- c("Smith John Michael","Smith, John Michael","Smith John, Michael","Smith-John Michael","Smith-John, Michael")
df <- data.frame(name)

df
                 name
1  Smith John Michael
2 Smith, John Michael
3 Smith John, Michael
4  Smith-John Michael
5 Smith-John, Michael

我需要达到以下所需的输出:

                 name first.name  last.name
1  Smith John Michael       John      Smith
2 Smith, John Michael       John      Smith
3 Smith John, Michael    Michael Smith John
4  Smith-John Michael    Michael Smith-John
5 Smith-John, Michael    Michael Smith-John

规则是:如果字符串中有逗号,则之前的任何内容都是姓氏。逗号后面的第一个单词是名字。如果字符串中没有逗号,则第一个单词是姓氏,第二个单词是姓氏。带连字符的单词是一个单词。我宁愿用dplyr和regex来实现这一点,但我会采取任何解决方案。谢谢你的帮助

2 个答案:

答案 0 :(得分:1)

根据strsplit中是否有逗号,","" "之间的name切换,您可以实现所需的结果。在这里,我们定义了两个函数来使表示更清晰。您也可以在函数中内联代码。

get.last.name <- function(name) {
  lapply(ifelse(grepl(",",name),strsplit(name,","),strsplit(name," ")),`[[`,1)
}

strsplit的结果是一个列表。 lapply(...,'[[',1)遍历此列表并从每个列表元素中提取第一个元素,这是姓氏。

get.first.name <- function(name) {
  d <- lapply(ifelse(grepl(",",name),strsplit(name,","),strsplit(name," ")),`[[`,2)
  lapply(strsplit(gsub("^ ","",d), " "),`[[`,1)
}

此函数类似,只是我们从strsplit返回的每个列表元素中提取第二个元素,其中包含第一个名称。然后,我们使用gsub删除任何起始空格,然后我们再次使用" "拆分,以从strsplit作为名字返回的每个列表元素中提取第一个元素。

将所有内容与dplyr

放在一起
library(dplyr)
res <- df %>% mutate(first.name=get.first.name(name),
                     last.name=get.last.name(name))

结果如预期:

print(res)
##                  name first.name  last.name
## 1  Smith John Michael       John      Smith
## 2 Smith, John Michael       John      Smith
## 3 Smith John, Michael    Michael Smith John
## 4  Smith-John Michael    Michael Smith-John
## 5 Smith-John, Michael    Michael Smith-John

数据:

df <- structure(list(name = c("Smith John Michael", "Smith, John Michael", 
"Smith John, Michael", "Smith-John Michael", "Smith-John, Michael"
)), .Names = "name", row.names = c(NA, -5L), class = "data.frame")
##                 name
##1  Smith John Michael
##2 Smith, John Michael
##3 Smith John, Michael
##4  Smith-John Michael
##5 Smith-John, Michael

答案 1 :(得分:0)

我不确定这是否比aichao的答案更好,但无论如何我都试了一下。我给出了正确的输出。

df1 <- df %>% 
  filter(grepl(",",name)) %>%
  separate(name, c("last.name","first.middle.name"), sep = "\\,", remove=F) %>% 
  mutate(first.middle.name = trimws(first.middle.name)) %>%
  separate(first.middle.name, c("first.name","middle.name"), sep="\\ ",remove=T) %>%
  select(-middle.name)

df2 <- df %>%
  filter(!grepl(",",name)) %>%
  separate(name, c("last.name","first.name"), sep = "\\ ", remove=F)

df<-rbind(df1,df2)