dplyr across中ifelse执行非预期条件计算报错问题及解决
在dplyr的across中使用ifelse触发报错的原因及解决方法
问题说明
当在dplyr::across中结合ifelse调用lubridate::days_in_month时,即便条件为真,else分支的代码仍会被执行,导致参数超出范围报错;但通过rowwise()逐行处理时则能正常运行。
报错原因
ifelse是向量化函数,它会一次性计算所有参数(条件、真分支、假分支),再根据条件筛选结果。当处理向量x = 1:3时,.x-1会生成0,1,2,其中0不符合days_in_month要求的1-12范围,直接触发报错,和条件是否满足无关。
而rowwise()会让代码逐行执行:仅当当前行条件不满足时,才会计算else分支,避免了无效值传入days_in_month。另外,这里使用across完全多余——across是用来对多列批量应用函数的,你只是基于单个列生成新列,不需要用它。
解决方法
方法1:用purrr::map_dbl逐行计算
借助purrr的映射函数逐个处理元素,仅在需要时执行else分支:
library(tidyverse) tibble(x = 1:3) %>% mutate(y = map_dbl(x, ~ifelse(.x == 1, 1, days_in_month(.x - 1))))
方法2:保留rowwise()(并取消不必要的across)
用rowwise()开启逐行模式,计算完成后建议取消该模式避免后续操作变慢:
library(tidyverse) tibble(x = 1:3) %>% rowwise() %>% mutate(y = ifelse(x == 1, 1, days_in_month(x - 1))) %>% ungroup()
方法3:用base::Vectorize包装函数
将判断逻辑包装为仅在需要时执行的向量化函数:
library(tidyverse) safe_days <- Vectorize(function(x) { if (x == 1) 1 else days_in_month(x - 1) }) tibble(x = 1:3) %>% mutate(y = safe_days(x))
内容的提问来源于stack exchange,提问作者abalter
相关产品推荐
相关产品推荐

