loc按标签索引且右端点包含,iloc按整数位置索引且左闭右开;混用不报错但结果易错,关键看操作对象是标签还是物理位置。

loc 和 iloc 不是“选哪个更好”,而是“用错就 silently 错”——它们根本不在同一坐标系里工作,混用不会报错,但结果可能差一行、一列,甚至整块数据全偏。
loc 按标签切片:右端点被包含,且必须真实存在
当你写 df.loc[0:100, 'amount'],它找的是索引中标签为 0 到 100(含)的所有行。如果 df.index 是 [0, 1, 2, ..., 99, 100],那确实取 101 行;如果索引是 ['a', 'b', 'c'],这行直接 KeyError;如果索引是 [10, 20, 30, 40],df.loc[0:100] 会返回空——因为标签 0 根本不存在。
- 列切片也一样:
df.loc[:, 'A':'C']要求列名'A'、'B'、'C'必须在df.columns中,且能比较大小(比如数字或规范日期字符串),否则抛TypeError - 单标签访问如
df.loc[5]返回Series,df.loc[[5]]才返回单行DataFrame——后续接.assign()或pd.concat()时类型不匹配会静默失败 - 重置索引后风险放大:执行过
df = df.sample(frac=1).reset_index(drop=True),df.loc[0]就不再是你以为的“第一行”,而可能是原始数据里某条索引恰好为 0 的记录(如果还存在),也可能直接报错
iloc 按位置切片:纯整数,左闭右开,不看索引长啥样
df.iloc[0:100] 就是物理上第 0 行到第 99 行(共 100 行),和 df.index 是什么完全无关。哪怕你删了前 50 行,df.iloc[0] 仍指向当前 DataFrame 的首行。
-
df.iloc[2]永远是第三行,不管那一行的索引标签是'2023-Q3'还是None - 传非整数会立刻报错:
df.iloc['b']→TypeError: cannot do positional indexing,比loc的静默错误更容易暴露问题 -
df.iloc[:, 1]返回Series,df.iloc[:, [1]]返回单列DataFrame——这点和loc行为一致,但新手常忽略,导致后续.plot()或.mean(axis=1)报错
布尔条件筛选时,loc 和 iloc 的行为差异最隐蔽
写 df[df['age'] > 30] 实际调用的是 df.loc[df['age'] > 30],不是 iloc。但如果你先用布尔数组得到位置序号再转成 iloc,就得自己映射:
mask = df['age'] > 30 positions = np.where(mask)[0] # 得到满足条件的物理位置 df.iloc[positions] # 这才等价于 df.loc[mask]
- 直接
df.iloc[mask]会报错——iloc不接受布尔数组,只认整数、整数列表或切片 - 用
df.loc[mask]最安全,因为它天然支持布尔索引,且返回结果的索引保持原样(可用于后续对齐) - 性能上:
iloc是 O(1) 数组直取,loc需哈希或二分查找,大数据量下延迟更明显,但日常分析中感知不强
怎么选?看你的“参照系”是什么
不看文档,只问自己两个问题:
- 你想取“索引值为
'2023-01'的那几行”?→ 用loc - 你想取“表格里从上往下数第 5 到第 10 行”?→ 用
iloc - 你在做条件过滤(比如
df['score'] >= 85)?→ 默认走loc,别动它 - 你在拼接多个
DataFrame后统一取第 2 列?→ 用iloc[:, 1],避免列名不一致引发的KeyError
最容易被忽略的点:同一个切片表达式,在不同 DataFrame 上可能一个走 loc 一个走 iloc,只因索引类型不同。别依赖“看起来一样”,要明确自己在操作标签还是位置。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











