loc按年切片需索引为DatetimeIndex且频率匹配:'2023'对日/月频有效,但freq为None时会报KeyError;按月应用'2023-01'而非'2023-01-01';跨年范围用'2022-06':'2023-02'闭区间;失效时回退df.index.year布尔索引。

用 loc 按年切片时,字符串写法必须匹配 DatetimeIndex 频率
直接写 df.loc['2023'] 能切出全年数据,但前提是索引是 DatetimeIndex 且频率为日级或更细(如 freq='D'、'H')。如果索引是月度频率(freq='M'),'2023' 仍有效;但若索引含不规则时间点(如从 CSV 读入未设频率),loc['2023'] 可能报 KeyError。
实操建议:
- 先确认索引类型:
isinstance(df.index, pd.DatetimeIndex),再看df.index.freq是否为None - 若
freq为None,可强制转为日频(不影响数据):df.index = pd.to_datetime(df.index) - 避免用
iloc替代——它按位置切,和年份语义无关
按月切片要小心 '2023-01' 和 '2023-01-01' 的区别
df.loc['2023-01'] 是标准写法,Pandas 会自动匹配整个月(无论索引是日频还是月频);而 df.loc['2023-01-01'] 只匹配单日,若索引无该日(比如只有每月最后一天),就会报 KeyError 或返回空。
常见错误现象:
立即学习“Python免费学习笔记(深入)”;
- 写
df.loc['2023-1'](少补零)→ 报KeyError: '2023-1' - 索引是
PeriodIndex却用DatetimeIndex写法 → 不报错但结果为空 - 用
df[df.index.month == 1]替代切片 → 可行,但性能差,尤其大数据量时比loc慢数倍
跨年跨月范围切片优先用闭区间字符串,别用 slice()
df.loc['2022-06':'2023-02'] 是最简洁可靠的写法,Pandas 自动处理起止边界(包含首尾日期/月份)。不要写成 df.loc[slice('2022-06', '2023-02')]——多此一举,且易因 slice 对象误用导致索引对齐失败。
使用场景注意点:
- 起止字符串格式需一致:都用
'YYYY-MM'或都用'YYYY-MM-DD',混用可能截断或报错 - 若起始早于索引最小值,Pandas 自动从第一个有效点开始;结束晚于最大值也同理
- 对高频数据(如秒级),
'2023-01'仍有效,但底层会扫描整个 1 月范围,不是 O(1) 查找
当 loc 失效时,回退到布尔索引 + dt 访问器
遇到索引非标准 DatetimeIndex(比如含 NaT、时区混杂、或从 HDF5 加载后丢失 dtype),loc 字符串切片大概率失效。这时用 df[df.index.year == 2023] 或 df[(df.index.year == 2023) & (df.index.month == 5)] 更鲁棒。
性能与兼容性权衡:
-
df.index.year返回Int64Index,支持所有DatetimeIndex子类(包括PeriodIndex经.to_timestamp()转换后) - 注意
df.index.dt.year才是正确写法(dt是访问器),漏掉.dt会报AttributeError - 布尔索引在超大数据集上内存开销略高,但胜在确定性——不依赖索引频率推断逻辑
NaT,df.index.freq 就会变成 None,进而让所有字符串切片行为变得不可预测。动手前先跑一遍 df.index.isna().sum() 和 df.index.freq。


















