使用dplyr::mutate结合str_detect处理舱位列提取异常问题
问题:dplyr处理cabin列生成新列时单组合场景结果异常
需求说明
需要用dplyr::mutate()创建新列cabin_zone,规则如下:
- 当
cabin列是单组字母+数字组合(如E4),提取字母部分(如E) - 当
cabin列包含两组及以上组合(如F G73或B57 B59 B63 B66),提取所有唯一字母并用逗号分隔(如F,G或B)
数据样本
structure(list(pclass = c(1L, 1L, 1L, 3L, 3L), survived = c(0L, 1L, 1L, 0L, 0L), name = c("Allison, Miss. Helen Loraine", "Anderson, Mr. Harry", "Andrews, Miss. Kornelia Theodosia", "Moen, Mr. Sigurd Hansen", "Soholt, Mr. Peter Andreas Lauritz Andersen"), sex = c("female", "male", "female", "male", "male"), age = c(2, 48, 63, 25, 19), sibsp = c(1L, 0L, 1L, 0L, 0L), parch = c(2L, 0L, 0L, 0L, 0L), ticket = c("113781", "19952", "13502", "348123", "348124" ), fare = c(151.55, 26.55, 77.9583, 7.65, 7.65), cabin = c("C22 C26", "E12", "D7", "F G73", "F G73"), embarked = c("S", "S", "S", "S", "S"), boat = c("", "3", "10", "", ""), body = c(NA, NA, NA, 309L, NA), home.dest = c("Montreal, PQ / Chesterville, ON", "New York, NY", "Hudson, NY", "", ""), title = c("Miss.", "Mr.", "Miss.", "Mr.", "Mr.")), row.names = c("3", "6", "7", "1025", "1218"), class = "data.frame")
用户代码
titanic_data <- titanic_data %>% mutate(cabin_zone = ifelse(str_detect(cabin," "), cabin %>% str_extract("[A-Z]") %>% str_split(.," ") %>% unlist(.) %>% unique(.) %>% paste(.,collapse = ","), gsub("[0-9 ]", "", cabin)))
问题原因
问题出在向量化操作和逐行操作的冲突:ifelse是向量化函数,要求三个参数的长度与输入列一致。但你在ifelse的TRUE分支中,对整个cabin列执行了链式操作,最终生成一个全局唯一的拼接字符串(所有舱位字母的集合,即'B,C,E,D,A,NA,T,F,G'),而非针对每个满足条件的行单独处理。当ifelse执行时,这个全局字符串会被循环填充到所有行,覆盖了单组合场景下gsub的正确结果。
解决方案
方法1:用case_when结合purrr::map_chr逐行处理
library(dplyr) library(stringr) library(purrr) titanic_data <- titanic_data %>% mutate(cabin_zone = case_when( # 处理多组合场景:逐行提取每个舱位的字母,去重后拼接 str_detect(cabin, " ") ~ map_chr(cabin, function(x) { x %>% str_split(" ") %>% unlist() %>% str_extract("[A-Z]") %>% unique() %>% paste(collapse = ",") }), # 处理单组合场景:移除数字,保留字母 TRUE ~ str_remove_all(cabin, "[0-9]") ))
方法2:用rowwise()强制逐行执行操作
library(dplyr) library(stringr) titanic_data <- titanic_data %>% rowwise() %>% mutate(cabin_zone = ifelse(str_detect(cabin, " "), cabin %>% str_split(" ") %>% unlist() %>% str_extract("[A-Z]") %>% unique() %>% paste(collapse = ","), str_remove_all(cabin, "[0-9]"))) %>% ungroup() # 取消逐行模式,恢复常规向量化操作
预期结果
运行上述代码后,cabin_zone列的结果为:
C22 C26→CE12→ED7→DF G73→F,GF G73→F,G
内容的提问来源于stack exchange,提问作者talocodat
相关产品推荐
相关产品推荐

