dplyr中group_by结合top_n无法获取分组内按字母序前2项的问题
解决分组后按字母顺序取前N个元素的问题
我来帮你搞定这个问题~你用group_by()加top_n()没得到预期结果,主要是踩了两个小坑:
top_n()的默认逻辑:它默认会根据数据框最后一列的值降序选取最大的n个元素,而不是按你之前的arrange顺序来取;arrange的执行顺序:你在group_by()之前做的arrange(Name, Group),会在分组后被打乱,因为group_by()会重新按分组键排列数据。
下面给你几个靠谱的解决方案,都是dplyr里的常用方法:
方法1:用slice_head()(推荐,dplyr 1.0.0+)
这个方法最直观,先分组,再在每个组内按Name升序排序,最后取前2个:
library(dplyr) df <- data.frame(Group = c(0, 0, 0, 1, 1, 1), Name = c("a", "c", "b", "e", "d", "f")) result <- df %>% group_by(Group) %>% arrange(Name, .by_group = TRUE) %>% # .by_group=TRUE确保在每个分组内排序 slice_head(n = 2) print(result)
输出正好符合你的期望:
# A tibble: 4 x 2 # Groups: Group [2] Group Name <dbl> <chr> 1 0 a 2 0 b 3 1 d 4 1 e
方法2:用slice_min()直接取最小的前2个
如果不需要显式排序,也可以直接用slice_min()指定按Name取每个组最小的2个元素:
result <- df %>% group_by(Group) %>% slice_min(Name, n = 2) %>% arrange(Group, Name) # 最后排序让结果更整洁 print(result)
方法3:修正top_n()的用法(不推荐,不如上面直观)
如果一定要用top_n(),需要明确指定排序权重wt,并且因为要取字母升序(即Name最小的前2个),需要用负号表示取最小的n个:
result <- df %>% group_by(Group) %>% top_n(-2, wt = Name) %>% arrange(Group, Name) print(result)
本质上,这些方法的核心都是先在分组内按Name排序,再选取前N个,区别只是语法简洁度不同~
内容的提问来源于stack exchange,提问作者Menno Van Dijk
相关产品推荐
相关产品推荐

