在dplyr::mutate中使用向量化函数及逻辑运算符的报错问题
问题分析与解决方案
核心问题
str_to_seq返回列表而非向量,无法直接与数值型的yearminus50做元素级比较;- 使用
all()是对整个向量做全局判断,不符合逐行生成结果的需求; - 生成完整年份序列属于冗余操作,仅需提取年龄组的上下限即可完成判断。
方案一:直接在mutate中完成判断(最简洁)
无需保留原str_to_seq函数,直接在管道流中提取年龄组边界并逐行判断:
library(dplyr) library(stringr) library(purrr) year <- c(1970, 1980, 1990, 2000, 2010, 2020) agegroup <- "1950 - 1959" testt <- expand.grid(agegroup = agegroup, year = year, stringsAsFactors = F) testt %>% as_tibble() %>% mutate( yearminus50 = year - 50, # 提取年龄组的数字并转为数值向量 age_nums = str_extract_all(agegroup, "\\d+") %>% map(as.numeric), # 提取年龄组的上限值 age_upper = map_dbl(age_nums, max), # 逐行判断yearminus50是否超过年龄组上限 statement = yearminus50 > age_upper ) %>% # 可选:移除中间辅助列 select(-age_nums, -age_upper)
运行后statement列会得到c(FALSE, FALSE, FALSE, FALSE, TRUE, TRUE),完全符合预期。
方案二:修改函数复用边界提取逻辑
如果需要复用年龄组边界提取逻辑,可以修改函数直接返回上下限(而非完整序列):
library(dplyr) library(stringr) # 提取单个年龄组的上下限 str_to_range <- function(x) { nums <- str_extract_all(x, "\\d+") %>% unlist() %>% as.numeric() c(min = min(nums), max = max(nums)) } # 向量化函数,支持批量处理多个年龄组 str_to_range_vec <- Vectorize(str_to_range, SIMPLIFY = TRUE) year <- c(1970, 1980, 1990, 2000, 2010, 2020) agegroup <- "1950 - 1959" testt <- expand.grid(agegroup = agegroup, year = year, stringsAsFactors = F) testt %>% as_tibble() %>% mutate( yearminus50 = year - 50, age_upper = str_to_range_vec(agegroup)[, "max"], statement = yearminus50 > age_upper )
原代码报错原因
str_to_seq设置了SIMPLIFY = F,返回列表而非向量,无法与数值向量直接比较;all()会将所有比较结果合并为一个单一逻辑值,而非逐行生成结果;- 生成完整年份序列属于冗余操作,判断仅需边界值即可完成。
内容的提问来源于stack exchange,提问作者Vesanen
相关产品推荐
相关产品推荐

