dplyr::case_when动态引用列值进行日期比较的异常问题
解决dplyr case_when动态日期列比较结果异常的问题
你遇到的问题核心是动态列名引用时没有逐行处理,直接用!!!sym或get会获取整个列的向量进行比较,而非当前行的单个日期值,导致逻辑判断完全混乱。
解决方案1:用rowwise()+get逐行处理
这是最贴合dplyr风格的写法,通过rowwise()让代码逐行执行,确保get()能拿到当前行对应列的单元格值:
library(dplyr) df_fixed <- df %>% rowwise() %>% mutate( # 动态拼接目标日期列名 vac_col = paste0("date_", hlp_vac), inf_col = paste0("date_infection_", to_modif), # 修正earlier和later列 earlier = case_when( get(vac_col) < get(inf_col) ~ "Vacation", get(vac_col) > get(inf_col) ~ "Infection", TRUE ~ earlier # 日期为空或相等时保留原值 ), later = case_when( get(vac_col) < get(inf_col) ~ "Infection", get(vac_col) > get(inf_col) ~ "Vacation", TRUE ~ later ) ) %>% ungroup() # 验证id=215的结果 df_fixed %>% filter(id == "215")
执行后id=215的earlier会正确显示为Vacation,later为Infection,符合日期比较逻辑。
解决方案2:用purrr::pmap逐行映射
如果需要更灵活的行内逻辑,可使用pmap逐行处理每一行数据:
library(purrr) library(dplyr) df_fixed <- df %>% bind_cols( pmap_dfr(., function(...) { row <- tibble(...) vac_date <- pull(row, paste0("date_", row$hlp_vac)) inf_date <- pull(row, paste0("date_infection_", row$to_modif)) # 仅当两个日期都非空时修正,否则保留原值 if (!is.na(vac_date) && !is.na(inf_date)) { list( earlier = if(vac_date < inf_date) "Vacation" else "Infection", later = if(vac_date < inf_date) "Infection" else "Vacation" ) } else { list(earlier = row$earlier, later = row$later) } }) )
关键原因说明
之前的错误在于:!!!sym或get在非rowwise环境中会直接操作整个列向量,比如get("date_Vacation4")会拿到所有行的Vacation4日期,和get("date_infection_m30")的整个列比较,得到的是一个布尔向量,case_when会按向量的位置匹配,而非逐行判断,最终导致结果完全不符合预期。而rowwise()会强制函数逐行执行,让get()每次只取当前行的对应值,比较逻辑才会正确。
内容的提问来源于stack exchange,提问作者Mirin1357
相关产品推荐
相关产品推荐

