groupby().head(n)仅取组内原始顺序前n行,非排序后top n;误用因混淆“行序”与“数值大小”;正确需先sort_values()再head(),或用nlargest()(单列)或rank()(多列/复杂逻辑)。

直接用 groupby().head(N) 最简单,但要注意它保留的是原始顺序前N条,不是按某列排序后的前N条——真要按排名留记录,得先 sort_values() 再 head(),或用 nlargest()。
为什么 groupby().head(N) 常被误用?
很多人以为 head() 会自动按数值大小取“最大”的前N条,其实它只认行序:组内哪几行在原始 DataFrame 里排最前,就取哪几行。如果数据没预先排序,结果完全不可控。
- 错误示例:
df.groupby('category').head(3)—— 若同一 category 的记录在原始数据中分散、无序,返回的三条可能毫无业务意义 - 正确前提:必须先按目标列(如
score、date)降序/升序排列,再分组取头 - 等价但更明确的写法:
df.sort_values('score', ascending=False).groupby('category').head(3)
nlargest() 更安全,但只适用于单列排序场景
当你要按**一个数值列**取每组 Top N,nlargest() 是专为此设计的,内部自动处理排序+截断,语义清晰且不易出错。
- 写法:
df.groupby('category')['score'].nlargest(3)—— 返回Series,索引含原行号,可接reset_index()恢复成 DataFrame - 若需保留其他列,加
keep='all'(Pandas ≥ 1.4):df.groupby('category').apply(lambda x: x.nlargest(3, 'score', keep='all')) - 注意:
nlargest()不支持多列联合排序(比如“先按 score 降序,score 相同时按 date 升序”),这种得回退到sort_values + head
多列排序 + 组内排名去重:用 rank() 配合布尔索引
当需要复杂排序逻辑(如多列、自定义 tie-breaking)、或想显式控制“并列怎么算名次”,就得引入 rank() 方法生成组内排名,再过滤。
- 步骤:先
sort_values(['score', 'date'], ascending=[False, True]),再groupby('category')['score'].rank(method='min', ascending=False) - 生成排名后,用
df['rank'] 筛选即可,<code>method='min'保证并列时共享同一最小名次(如两个第1名,则下一个为第3名) - 性能提示:对超大表,
rank()比nlargest()或sort + head开销略高,因需计算完整排名;若只要 Top N,优先选前两者
真正容易被忽略的是排序稳定性:sort_values 默认 kind='quicksort' 不稳定,相同 key 的行相对顺序可能变;若依赖原始顺序作为第二排序依据,务必加 kind='mergesort' 或用 stable=True(Pandas ≥ 1.1)。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











