R语言dplyr管道按行计算max时返回NA而非-Inf的方法
问题复现
以下代码可完整复现全NA行返回-Inf的异常:
library(dplyr) # 构造测试用日期数据框 df <- tibble( id = 1:3, mr_daterd_1 = as.Date(c("2023-01-05", "2023-02-10", NA)), mr_daterd_2 = as.Date(c("2023-03-12", NA, NA)), date_contact_1 = as.Date(c("2023-01-02", "2023-02-15", NA)), date_contact_2 = as.Date(c("2022-12-20", NA, NA)) ) # 原有管道写法,全NA行返回-Inf df_problem <- df %>% rowwise() %>% mutate( latest_mri = max(c_across(starts_with("mr_daterd")), na.rm = TRUE), latest_contact = max(c_across(starts_with("date_contact")), na.rm = TRUE) ) %>% ungroup()
运行上述代码后,第3行所有MRI、接触日期列均为NA,计算得到的latest_mri、latest_contact值为-Inf,不符合日期类型预期。
解决方案
完全保留原有rowwise + c_across + starts_with的管道逻辑,不需要调整选列或行计算框架,两种写法可直接嵌入现有代码:
写法1:直接在mutate中加判断
不需要额外定义函数,仅对全NA场景做分支判断即可:
df_fixed <- df %>% rowwise() %>% mutate( latest_mri = if (all(is.na(c_across(starts_with("mr_daterd"))))) { NA_Date_ } else { max(c_across(starts_with("mr_daterd")), na.rm = TRUE) }, latest_contact = if (all(is.na(c_across(starts_with("date_contact"))))) { NA_Date_ } else { max(c_across(starts_with("date_contact")), na.rm = TRUE) } ) %>% ungroup()
写法2:封装安全取最大值函数(多分组场景更简洁)
如果同类型前缀分组较多,可以先封装一个适配日期类型的安全max函数,直接替换原有max调用即可,代码更整洁:
# 定义日期类型安全取最大值函数 safe_date_max <- function(x) { if (all(is.na(x))) return(NA_Date_) max(x, na.rm = TRUE) } # 嵌入原有管道 df_fixed2 <- df %>% rowwise() %>% mutate( latest_mri = safe_date_max(c_across(starts_with("mr_daterd"))), latest_contact = safe_date_max(c_across(starts_with("date_contact"))) ) %>% ungroup()
- 两种写法输出结果一致:非全NA行正常返回分组内最晚日期,全NA行返回日期类型的
NA,不会出现-Inf值,也不会改变原有数据框的列类型 - 不要用通用
NA替换NA_Date_:通用NA为逻辑类型,直接赋值给日期列会触发类型不匹配错误 - 不需要改动原有选列逻辑:
starts_with匹配前缀、c_across抓取值、rowwise按行计算的逻辑完全保留,和原有代码完全兼容
内容的提问来源于stack exchange,提问作者cmirian
相关产品推荐
相关产品推荐

