dplyr使用na.rm=TRUE分组筛选最小值时丢失含NA组问题
问题:dplyr分组筛选含NA的日期最小值行时丢失分组
使用dplyr 1.1.2版本,按uid和cat两个变量分组后,筛选每组date最小值对应的行时,当组内存在NA值,即使设置了na.rm=TRUE,也没有忽略NA保留非NA的最小值,反而导致整个组被丢弃。
原始数据框
# Original data frame my_df <- structure(list(uid = c("id100", "id100", "id100", "id100", "id200", "id200", "id200", "id200", "id300", "id300", "id300", "id300" ), cat = c("franklin", "franklin", "aretha", "aretha", "franklin", "aretha", "aretha", "aretha", "franklin", "franklin", "aretha", "franklin"), food = c("fish", "beef", "chicken", "chicken", "beef", "pork", "turkey", "fish", "beef", "pork", "chicken", "beef"), date = structure(c(8674, 8703, 8685, 8689, 8675, 8677, 8680, 8691, 8701, NA, 8698, 8697), class = "Date")), class = "data.frame", row.names = c(NA, -12L))
尝试的筛选代码
# Group by two variables, filter new_df <- my_df %>% group_by(uid, cat) %>% filter(date == min(date), na.rm = TRUE)
当前执行结果
uid cat food date <chr> <chr> <chr> <date> 1 id100 franklin fish 1993-10-01 2 id100 aretha chicken 1993-10-12 3 id200 franklin beef 1993-10-02 4 id200 aretha pork 1993-10-04 5 id300 aretha chicken 1993-10-25
期望得到的结果
uid cat food date <chr> <chr> <chr> <date> 1 id100 franklin fish 1993-10-01 2 id100 aretha chicken 1993-10-12 3 id200 franklin beef 1993-10-02 4 id200 aretha pork 1993-10-04 5 id300 aretha chicken 1993-10-25 6 id300 franklin beef 1993-10-24
解决方案
问题根源是参数传递错误:你把na.rm=TRUE传给了filter()函数,但filter()本身并不支持这个参数,该参数被直接忽略。这导致min(date)计算时,因为组内存在NA值,返回结果为NA,进而date == NA的判断结果全是NA,filter()会丢弃所有NA对应的行,最终整个组被排除。
修正方法1:正确传递na.rm给min()
把na.rm=TRUE放到min()函数的参数中,确保计算最小值时忽略NA:
new_df <- my_df %>% group_by(uid, cat) %>% filter(date == min(date, na.rm = TRUE)) %>% ungroup() # 建议分组操作后取消分组,避免后续操作受分组状态影响
修正方法2:使用slice_min()更直观
dplyr提供了专门的slice_min()函数,用于筛选每组的最小值行,默认支持通过na_rm参数处理NA值,代码更简洁易懂:
new_df <- my_df %>% group_by(uid, cat) %>% slice_min(date, na_rm = TRUE, with_ties = FALSE) %>% # with_ties=FALSE:若组内有多个相同最小值的行,只保留第一行;设为TRUE则保留所有,按需调整 ungroup()
两种方法都能得到你期望的结果,包含id300的franklin组对应的最小日期行。
内容的提问来源于stack exchange,提问作者jvjvjv
相关产品推荐
相关产品推荐

