You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用pandas shift(periods=1, freq='ME')出现日期偏移错误的原因咨询

为什么pandas的shift(freq='ME')结果和预期不符?

运行代码

import pandas as pd

d = [
  {'Date Enrolled': pd.Timestamp('2013-11-30'), 'metric': 2},
  {'Date Enrolled': pd.Timestamp('2013-12-01'), 'metric': 0},
  {'Date Enrolled': pd.Timestamp('2013-12-02'), 'metric': 0},
  {'Date Enrolled': pd.Timestamp('2013-12-03'), 'metric': 0},
  {'Date Enrolled': pd.Timestamp('2013-12-04'), 'metric': 0},
  {'Date Enrolled': pd.Timestamp('2013-12-05'), 'metric': 0}
]
tdf = pd.DataFrame(d)
tdf = tdf.set_index(['Date Enrolled']).asfreq('D')
tdf['metric'].shift(periods=1, freq='ME')

实际运行结果

Date Enrolled
2013-12-31    2
2013-12-31    0
2013-12-31    0
2013-12-31    0
2013-12-31    0
2013-12-31    0
Name: metric, dtype: int64

预期结果

Date Enrolled
2013-12-31    2
2014-01-31    0
2014-01-31    0
2014-01-31    0
2014-01-31    0
2014-01-31    0
Name: metric, dtype: int64

原因解释

问题出在freq='ME'的偏移逻辑上:

  • ME对应pd.offsets.MonthEnd偏移量,它的行为是返回不早于当前日期的下一个月末日期。
    • 对于2013-11-30(11月月末),下一个月末是2013-12-31;
    • 对于2013-12-01至2013-12-05这些12月内的日期,它们的下一个月末就是当月的月末2013-12-31。
      所以所有日期经过shift(periods=1, freq='ME')处理后,都会指向2013-12-31,这就是实际结果和预期不符的核心原因。

如果你想实现「将原日期所在月份向后推1个月,再取该月月末」的逻辑,可以用以下方式:

# 方法1:通过周期转换实现
result = tdf['metric']
result.index = result.index.to_period('M').shift(1).dt.to_timestamp(how='end')
print(result)

# 方法2:结合DateOffset和MonthEnd
result = tdf['metric'].shift(periods=1, freq=pd.DateOffset(months=1))
result.index = result.index + pd.offsets.MonthEnd(0)
print(result)

这两种方法都会得到你预期的结果。

内容的提问来源于stack exchange,提问作者Jamie Marshall

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 08:52:38