Pandas,.resample('B') 的意外行为

Pandas, unexpected behavior of .resample('B')

我从标记为月末的每月系列开始。我想通过填充前向值将它们上采样到业务(周一至周五)的每日频率。 我希望 2 个条件为真:

  1. 如果原来是周末,则在重新采样时不会丢失任何值 时间序列
  2. 始终向前填充:如果原始系列中的 EOM 日期是 星期六,我希望该观察结果显示为下星期一 每日系列

虽然不优雅,但我得出结论,最安全的方法是:

    daily_series = monthly_series.resample(rule='D').ffill().resample(rule='B',how='first')

现在,意想不到的情况:

    dates = ['1953-02-28', '1953-03-31', '1953-04-30', '1953-05-31']
    # '1953-02-28' was a Saturday

    values = [1,2,3,4]
    monthly_ts  = pd.Series(values, index = dates)

    monthly_ts
    Out[74]: 
    1953-02-28    1
    1953-03-31    2
    1953-04-30    3
    1953-05-31    4
    dtype: int64

    daily_ts = monthly_ts.resample(rule='D').ffill().resample(rule='B',how='first')

     Out[77]: 
     1953-02-27    1           # Why do I have this observation?
     1953-03-02    1
     1953-03-03    1
     1953-03-04    1

星期六的观测值用于星期五的重采样。 这发生在 .resample(rule = 'B')

之后

能否请您解释一下为什么会发生这种情况以及如何防止这种情况发生?

这种行为方式是由于为下采样设置周期而发生的。 间隔内的营业日数量小于日历天数。 这就是为什么星期五和星期一与星期六和星期日连接在一起并表示为一个单元的原因。 周六和周日的值用于使用 'how' 和 'closed' 参数进行下采样。

dates = ['1953-02-28', '1953-03-31', '1953-04-30', '1953-05-31']
values = [1,2,3,4]
monthly_ts  = pd.Series(values, index = pd.to_datetime(dates))

首先上采样到日历天数

calendar_daily_ts = monthly_ts.resample(rule='D').ffill()

让我们看看最后三个记录

In[8]: calendar_daily_ts[-3:]
Out[8]: 
1953-05-29    3
1953-05-30    3
1953-05-31    4
Freq: D, dtype: int64

如果我们使用均值和关闭='left'下采样到工作日,最后的值将为 3.33333

In [15]: calendar_daily_ts.resample(rule='B', closed='left').mean()[-2:]
Out[15]: 
1953-05-28    3.000000
1953-05-29    3.333333
Freq: B, dtype: float64

周五 (1953-05-29) 的值计算为周五、周六和周日 (3 + 3 + 4) / 3 的平均值

如果我们使用均值和关闭='right'下采样到工作日,最后的值将为 3.5

In [16]: calendar_daily_ts.resample(rule='B', closed='right').mean()[-2:]
Out[16]: 
1953-05-28    3.0
1953-05-29    3.5
Freq: B, dtype: float64

周五 (1953-05-29) 的值计算为周六、周日和下周一 (3 + 4 + 0) / 2 的平均值

没有星期五值。

所以你问题中的观察出现了,因为对于 1953-02-28(星期六),下采样的时间段包括 1953-02-27、1953-02-28、1953-03-01 和 1953-03- 02. 默认情况下,区间为左闭 - (1953-02-27、1953-02-28、1953-03-01)。 你得到了第一个 - 它是 1953-02-27

还有一个有趣的例子

In [45]: calendar_daily_ts[:4]
Out[45]: 
1953-02-27    1
1953-02-28    2
1953-03-01    3
1953-03-02    4
dtype: int64

In [47]: calendar_daily_ts.resample(rule='B', closed='left').first()[:4]
Out[47]: 
1953-02-27    1
1953-03-02    4
1953-03-03    1
1953-03-04    1
Freq: B, dtype: int64

In [48]: calendar_daily_ts.resample(rule='B', closed='right').first()[:4]
Out[48]: 
1953-02-26    1
1953-02-27    2
1953-03-02    1
1953-03-03    1
Freq: B, dtype: int64

看看有什么不同! (1953-02-26 值为 1)