Pandas中resample()的closed参数按月重采样时行为不符预期
closed="right"在月度频率下未生成1999-12-31结果的原因 首先,我先复现你遇到的场景,再一步步解释背后的逻辑:
1. 创建测试时间序列
>>> index = pd.date_range('1/1/2000', periods=60*24*400, freq='T') >>> series = pd.Series(range(60*24*400), index=index) >>> series.head() 2000-01-01 00:00:00 0 2000-01-01 00:01:00 1 2000-01-01 00:02:00 2 2000-01-01 00:03:00 3 2000-01-01 00:04:00 4
2. 日频率下closed参数的直观表现
按日重采样时,closed参数的行为和文档描述一致:
>>> series.resample('D', closed="right").head() 1999-12-31 0.0 # <-- 出现1999年的数据 2000-01-01 720.5 2000-01-02 2160.5 2000-01-03 3600.5 2000-01-04 5040.5 Freq: D, dtype: float64 >>> series.resample('D', closed="left").head() 2000-01-01 719.5 2000-01-02 2159.5 2000-01-03 3599.5 2000-01-04 5039.5 2000-01-05 6479.5
正如文档所说:
closed : {'right', 'left'}
指定区间的哪一侧是闭合的。
3. 月度频率下的疑问场景
但切换到月度频率时,closed="right"并没有生成1999-12-31的结果,这和日频率的表现不一致:
>>> series.resample('M', closed="right").head() 2000-01-31 22319.5 # <-- 未出现1999-12-31 2000-02-29 65519.5 2000-03-31 108719.5 2000-04-30 152639.5 2000-05-31 196559.5 Freq: M, dtype: float64 >>> series.resample('M', closed="left").head() 2000-01-31 21599.5 2000-02-29 64079.5 2000-03-31 107279.5 2000-04-30 151199.5 2000-05-31 195119.5 Freq: M, dtype: float64
(注:使用的pandas版本为0.22.0)
核心原因解析
这是pandas在处理**低频周期(月度/季度/年度)**重采样时的特殊逻辑:
日频率的特殊情况:在
closed="right"的日重采样规则下,你的第一个数据点2000-01-01 00:00:00被划分到了(1999-12-30, 1999-12-31]这个区间(pandas 0.22.0的区间划分逻辑),所以生成了1999-12-31的索引项,对应的值只有第一个数据点的均值(0.0)。月度频率的边界限制:当使用月度频率时,pandas会从数据的第一个时间点所在的周期开始构建重采样区间,不会向前扩展到前一个周期。你的数据起始于
2000-01-01,第一个月度区间为(1999-12-31, 2000-01-31](closed="right"规则),但你的数据中没有任何记录落在(1999-12-31, 2000-01-01)这个子区间里,pandas不会为这种几乎为空的区间生成1999-12-31的索引项——因为该区间内没有有效数据(只有从2000-01-01开始的记录,而这部分被包含到了2000-01-31对应的区间中)。
简单来说,月度重采样不会为没有有效数据的前置周期生成索引,而日频率下刚好有一个数据点被划分到了前一天的区间,所以出现了跨年度的索引项。
内容的提问来源于stack exchange,提问作者Jérôme

