理解dplyr中summarise函数的.groups="drop"参数及异常排查
.groups="drop"的作用及分组缺失问题解答 为什么不加.groups="drop"会返回远超20行的结果?
在dplyr 1.0.0及之后的版本里,summarise()的默认.groups参数是"drop_last"——简单说就是执行完汇总后,会删掉分组变量列表里的最后一个,保留前面所有分组。
你的代码里用group_by(start_station_name, start_lat, start_lng)指定了三个分组变量,所以summarise()执行后,分组会变成start_station_name和start_lat,并没有完全取消分组。
这就导致后续的arrange(desc(count))和slice(1:20)都是按每个分组(也就是每个start_station_name + start_lat的组合)单独运行的:比如如果有10个不同的start_station_name + start_lat组合,每个组合里都会被取前20行,最终总行数自然会远超20。
而添加.groups="drop"后,summarise()会直接移除所有分组,把数据变回普通的未分组数据框。这时候arrange是全局排序,slice(1:20)就会从整个数据集中取排名前20的记录,完全符合你的需求。
为什么groups(summary)里看不到start_lng?
还是因为"drop_last"的默认行为:你最初的分组变量顺序是start_station_name → start_lat → start_lng,summarise()默认会去掉最后一个分组变量(也就是start_lng),只保留前面两个。所以调用groups(summary)时,只会显示剩下的分组变量。
用实际示例验证
我们构造一个模拟数据集来复现你的场景:
library(dplyr) # 模拟出行数据:10个不同的站点组合,每个组合对应50条记录 trips_2023 <- tibble( member_casual = rep("member", 500), start_station_name = rep(paste0("Station ", LETTERS[1:10]), each=50), start_lat = rep(seq(40.71, 40.80, 0.01), each=50), start_lng = rep(seq(-74.00, -73.91, 0.01), each=50) ) # 不加.groups="drop"的情况 summary_no_drop <- trips_2023 %>% filter(member_casual == "member") %>% group_by(start_station_name, start_lat, start_lng) %>% summarise(count = n()) %>% arrange(desc(count)) %>% mutate(type = "start", member = "member") %>% slice(1:20) # 查看当前分组 groups(summary_no_drop) # 输出:Groups: start_station_name, start_lat [10] # 查看结果行数 nrow(summary_no_drop) # 输出:10(每个分组里只有1条记录,slice(1:20)会取所有分组的记录) # 添加.groups="drop"的情况 summary_with_drop <- trips_2023 %>% filter(member_casual == "member") %>% group_by(start_station_name, start_lat, start_lng) %>% summarise(count = n(), .groups = "drop") %>% arrange(desc(count)) %>% mutate(type = "start", member = "member") %>% slice(1:20) # 查看当前分组 groups(summary_with_drop) # 输出:NULL(无任何分组) # 查看结果行数 nrow(summary_with_drop) # 输出:10(全局排序后取前20,这里只有10条记录,所以全部保留;如果有30条,就会取前20)
总结
.groups="drop"的核心作用是在summarise后完全清除所有分组,让后续操作在整个数据集上执行,而非按分组拆分执行。- 默认的
.groups="drop_last"会保留除最后一个之外的所有分组变量,这就是你看到分组缺失start_lng的直接原因。 - 如果你不想用
.groups="drop",也可以在summarise()之后加一行ungroup(),能达到完全一样的效果。
内容的提问来源于stack exchange,提问作者gorilla_ballz123

