应优先使用.loc按索引值精确切片,而非.iloc(后者按位置编号);.loc支持字符串/日期索引、闭区间切片、布尔索引;抽样首选sample()以保留索引并提升性能;索引未排序时.loc切片需先sort_index()或改用布尔索引。

用 .loc 按行索引精确切片,别用 .iloc
如果索引是字符串、日期或非连续整数,.iloc 会按位置编号取数,和你想的“按索引值取”完全不是一回事。比如 df.iloc[0] 总是取第一行,哪怕索引是 '2023-01-01';而 df.loc['2023-01-01'] 才真按索引值匹配。
常见错误:把 .loc 当成“带标签的 .iloc”,结果遇到重复索引时报 KeyError 或返回多行却没意识到。
- 单个索引值:
df.loc['A'](返回Series)或df.loc[['A']](返回DataFrame) - 切片(闭区间):
df.loc['A':'C']—— 注意这是按索引顺序切,不是按原始行序 - 布尔索引配合:
df.loc[df.index.str.startswith('2023')],比先重置索引再.iloc快得多
抽样时优先用 sample() 而非 np.random.choice() + .iloc
df.sample(n=100, random_state=42) 内部直接操作索引,不触发数据拷贝,速度比手动构造位置列表再 .iloc 高 3–5 倍(尤其对百万行以上 DataFrame)。它默认按行抽样,且天然支持权重(weights=df['score'])和分层(stratify=df['category'])。
容易踩的坑:用 df.iloc[np.random.choice(len(df), size=100)] 会丢失原始索引,且无法利用 Pandas 的索引加速路径。
- 按索引抽样(保留原索引):
df.sample(n=100, axis=0) - 等价但更慢的写法:
df.iloc[np.random.permutation(len(df))[:100]] - 想确保抽到特定索引子集?先用
.loc过滤再.sample,别在全量数据上随机后筛选
索引未排序时,.loc 切片可能意外返回空或报错
df.loc['2023-01-01':'2023-01-05'] 要求索引已升序排列,否则 Pandas 会跳过中间未排序的段,甚至抛 KeyError(如索引是 ['2023-01-05', '2023-01-01'])。这不是 bug,是设计行为——Pandas 把切片当作有序查找优化路径。
- 检查是否有序:
df.index.is_monotonic_increasing - 安全做法:
df.sort_index().loc['2023-01-01':'2023-01-05'],但注意sort_index()有开销 - 替代方案(不排序):
df[df.index >= '2023-01-01'][df.index ,逻辑清晰但两次布尔索引略慢
大文件场景下,避免反复 .loc 查找,先缓存索引位置
如果你要对同一组索引做多次切片(比如循环中查 df.loc[key]),每次调用 .loc 都会重建哈希映射或二分搜索结构。对千万级索引,这能差出 10 倍时间。
- 提前构建索引映射:
idx_map = {k: i for i, k in enumerate(df.index)},然后用df.iloc[idx_map['A']] - 更推荐:
df.index.get_loc('A')返回位置,比字典查更快且内存省 - 批量查找多个键:
df.index.get_indexer(['A', 'B', 'C']),返回位置数组,一次搞定
索引类型影响性能:纯整数索引走快速路径,字符串或 datetime 索引依赖哈希或树结构,重复索引会退化为线性扫描。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











