iloc只接受整数位置索引(如iloc[2]取第三行),不支持标签;loc按行索引值匹配(如loc['a']取索引为'a'的行);布尔索引(如df[df.age>30])才是按内容筛选的正确方式。

用 iloc 取行时,索引是位置不是标签
很多人一上来就写 df.iloc['A'],直接报错 TypeError: cannot do label indexing on <class> with these indexers</class>。因为 iloc 只认整数位置——从 0 开始数第几行,不管你的行名是什么。
常见错误现象:DataFrame 行索引是字符串(比如 ['A', 'B', 'C']),却用 iloc['B'];或者想取最后一行写了 iloc[-1] 却发现结果不对(其实是对的,但你误以为它该按标签找)。
-
iloc[2]→ 第三行(位置索引,0 起始) -
iloc[[0, 2, -1]]→ 多个位置,支持负数、列表、切片(如iloc[1:4]) - 不支持标签,哪怕行索引看起来像数字(如
df.index = ['1', '2', '3']),iloc[1]仍是第二行,不是索引为'1'的那行
用 loc 取行时,必须匹配行索引值
loc 看的是行索引(index)本身的值,不是位置。如果你的 DataFrame 没显式设过索引,默认是 RangeIndex(0, 1, 2...),这时 loc[0] 才等于第一行;但一旦你执行过 df.set_index('col') 或 df.index = ['x', 'y', 'z'],loc[0] 就会报 KeyError。
使用场景:按业务 ID、日期、名称等有意义的标签查行;或需要同时筛选行列(loc[行条件, 列名])。
-
loc['A']→ 行索引中值为'A'的那一行(必须存在,否则 KeyError) -
loc[['A', 'C']]→ 多个标签,顺序按原索引出现顺序,不保证和输入列表一致 -
loc['2023-01-01':'2023-01-03']→ 如果索引是有序日期,支持切片(含首含尾,和iloc不同)
想按内容筛选行?别硬套 iloc/loc,先用布尔索引
用户常问:“怎么取 age > 30 的所有行?”——这不是 iloc 或 loc 的本职工作。它们是“定位器”,不是“过滤器”。强行用 loc 套条件(如 loc[df.age > 30])能跑通,但本质已是布尔索引,loc 在这里只是可选容器,不是必需。
性能影响:布尔索引本身很快;但若在大 DataFrame 上反复写 df.loc[df.age > 30].iloc[0],相当于两次扫描,不如先存中间结果。
- 正确姿势:
df[df.age > 30](最直白)、df.query('age > 30')(可读性好) - 如果后续还要按位置取,再链式写:
df[df.age > 30].iloc[0],但注意此时iloc[0]是结果里的第一行,不是原表第一行 - 避免:
df.loc[df.age > 30, :].iloc[0]—— 多余的loc和:降低可读性
混合索引(MultiIndex)下 loc 必须传元组,iloc 不受影响
当行索引是两层(比如 (城市, 年份)),loc 就不能只写 loc['Beijing'] 了,会报 KeyError: 'Beijing' not in index,因为它默认要匹配整个索引元组。
容易踩的坑:以为 loc['Beijing'] 能模糊匹配第一层,实际不行;或用 iloc 时忘了 MultiIndex 不影响位置计数,iloc[0] 还是第一行,没问题。
- 取第一层所有:
df.loc['Beijing']→ 错误;应写df.loc[('Beijing', slice(None)), :]或更简单:df.xs('Beijing', level=0) - 取具体组合:
df.loc[('Beijing', 2023)]→ 正确,传元组 -
iloc[5]→ 依然有效,返回位置第 5 行,不管索引结构多复杂
真正容易被忽略的是索引类型本身——loc 对索引值做精确匹配,而索引可能是 int、str、datetime、tuple,甚至包含 NaN。一旦索引里有 np.nan,loc[np.nan] 必然失败,得用 df[df.index.isna()] 单独捞。这事不报错,但数据就悄悄漏了。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











