head()和tail()取前n行未必返回预期结果:默认各5行,但索引修改、链式操作易致视图/副本问题;groupby后head(n)是每组取n行;空数据或筛选后不足n行时返回实际行数,不补不报错。

用 head() 和 tail() 快速取前N行,不是所有情况都返回预期结果
这两个方法默认返回前5行或后5行,但传入数字参数后,head(n) 确实能取前n行——前提是数据没被修改过索引、没触发视图/副本警告。常见错误是:在链式操作里调用 head() 后接着改列,结果发现原 DataFrame 没变,或者报 SettingWithCopyWarning。这是因为 head() 返回的是原数据的视图(view)或副本(copy),取决于底层内存布局,Pandas 不保证可写性。
- 直接对原始 DataFrame 调用:
df.head(10)安全,只读查看没问题 - 如果后续要修改,先明确复制:
df.head(10).copy() - 别在链式赋值里依赖它:
df.head(10)['col'] = value极可能失效或报错 - 空 DataFrame 调用
head(10)仍返回空,不会报错,但容易误判数据是否存在
head() 在 groupby 后的行为和普通 DataFrame 不一样
groupby 后接 head(n) 是“每组取前n行”,不是整个结果取前n行。比如 df.groupby('category').head(2) 会从每个 category 中各拿最多2条记录,最终行数可能是 2×组数。这常被误当成“全局取头2行”。
- 想取分组后整体的前n行?得先
reset_index(drop=True)再用head(n) -
head()在 groupby 中支持负数,.head(-1)表示每组去掉最后一行 - 性能上,groupby + head 比先 head 再 groupby 快得多,因为避免了全量分组计算
- 注意 NaN 分组:默认会被单独归为一组,
head()也会对其生效
当 head() 返回空或行数少于N时,说明什么
返回行数小于请求的 N,通常不是 bug,而是数据本身不足或过滤逻辑提前生效。比如 df.query('x > 10').head(10) 如果只有3行满足条件,就只返回3行——head() 不补、不报错、不警告。
- 检查是否用了
query()、loc[]或布尔索引等前置筛选 - 确认索引是否被重置过:如果索引有跳跃或非连续整数,
head()仍按逻辑顺序取,不是按索引值大小 - 读取大文件时用
pd.read_csv(..., nrows=1000)比read_csv().head(1000)更省内存 - 用
len(df.head(n))判断实际返回行数,别假设一定等于 n
替代方案:什么时候不该用 head() 和 tail()
需要精确切片、带条件截断、或配合其他库(如 Dask、Polars)时,head() 就不够用了。它本质是语法糖,底层仍是基于位置的索引切片,但隐藏了 iloc 的明确性。
- 要取第5到第15行?用
df.iloc[5:15],比df.tail(-5).head(10)直观且稳定 - 处理超大数据集(>1GB)时,
head()可能触发整表加载,而pd.read_parquet(path, columns=..., use_pandas_metadata=True)配合use_pandas_metadata可跳过解析 - 在函数中封装“取前N行”逻辑时,显式用
df.iloc[:n]更易测试、更少歧义 -
tail()对未排序时间序列可能返回“最新”也可能返回“最后读入”,需确认索引是否为时间类型并已排序










