如何在R的dplyr工作流中提取姓名列首尾元素并合并为新列?
在tidyverse中提取姓名首末元素并合并的解决方案
首先加载所需包与样本数据:
library(tidyverse) # 加载样本数据框 df <- structure(list(FirstName = c("Albus Percival Wulfric Brian Dumbledore", "Harry James Potter", "Tom Marvollo Riddle", "Lord Voldemort" ), Email = c("albusD@hogwarts.com", "harryP@hogwarts.com", "tomR@hogwarts.com", "LV@Wiz.com"), ClassSection = c("HeadMaster", "Student", "Dark Lord in training", "Dark Lord")), row.names = c(NA, -4L), spec = structure(list( cols = list(FirstName = structure(list(), class = c("collector_character", "collector")), Email = structure(list(), class = c("collector_character", "collector")), ClassSection = structure(list(), class = c("collector_character", "collector"))), default = structure(list(), class = c("collector_guess", "collector")), delim = ","), class = "col_spec"), class = c("spec_tbl_df", "tbl_df", "tbl", "data.frame"))
方法一:拆分列表后提取首尾元素
利用str_split拆分姓名为列表列,再通过purrr::map_chr逐元素提取首末项并合并:
df_1 <- df %>% mutate(name_abbrev = map_chr(str_split(FirstName, "\\s+"), ~paste(first(.x), last(.x), sep = " "))) # 查看结果 df_1 %>% select(FirstName, name_abbrev)
说明:
str_split(FirstName, "\\s+"):按一个或多个空格拆分姓名,生成存储字符向量的列表列map_chr(..., ~paste(first(.x), last(.x), sep = " ")):对每个拆分后的字符向量,用first()取首元素、last()取尾元素,再用paste()合并成字符串,最终返回字符列而非列表列
方法二:正则表达式直接匹配(更高效)
无需拆分字符串,直接用正则提取首尾单词并合并,避免列表列操作:
方式A:分别提取首尾后合并
df_2 <- df %>% mutate( first_name = str_extract(FirstName, "^\\w+"), last_name = str_extract(FirstName, "\\w+$"), name_abbrev = str_c(first_name, last_name, sep = " ") ) %>% select(-first_name, -last_name) # 可选:删除中间辅助列
方式B:单次正则替换
用捕获组匹配首尾单词,直接替换掉中间内容:
df_3 <- df %>% mutate(name_abbrev = str_replace(FirstName, "^(\\w+).*(\\w+)$", "\\1 \\2"))
说明:
^\\w+:匹配字符串开头的第一个单词(\\w匹配字母/数字/下划线,适用于常规姓名)\\w+$:匹配字符串结尾的最后一个单词^(\\w+).*(\\w+)$:两个捕获组分别锁定首、尾单词,中间.*匹配任意内容,替换时用\\1 \\2提取捕获组内容合并
之前尝试失效的原因
separate丢失中间元素:该函数需要预设拆分后的列数,无法灵活处理不同长度的姓名- 直接用
tail/last处理列表列:这类函数针对向量设计,必须结合map系列函数逐元素操作,才能正确提取每个列表项的首尾元素
内容的提问来源于stack exchange,提问作者Pss
相关产品推荐
相关产品推荐

