【问题标题】:Pandas, unexpected behavior of .resample('B')熊猫,.resample('B') 的意外行为
【发布时间】:2016-05-20 22:36:29
【问题描述】:

我从以月末为时间戳的月度系列开始。我想通过填充远期值将它们上采样到业务(周一至周五)的每日频率。 我希望 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')

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

【问题讨论】:

    标签: python pandas resampling


    【解决方案1】:

    这种行为方式的发生是由于为下采样设置了周期。 间隔中小于日历日的工作日数。 这就是为什么周五和周一与周六和周日相连并表示为一个单元的原因。 周六和周日的值用于使用“how”和“close”参数进行下采样。

    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)

    【讨论】:

    • 只有一个小的修正:使用默认参数,在周五、周六和周日重新采样组,因此我们在周五得到周六的值github.com/pydata/pandas/issues/11123
    • @FLab 我说的完全一样。一组由周五、周六、周日和周一组成。当 closed='left' 星期一被排除,当 closed='right' 星期五被排除。关闭的默认值是“左” - 我们在组中有周五、周六和周日。
    • @FLab 检查我的答案的更新(一个更有趣的例子)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-10-31
    • 1970-01-01
    • 1970-01-01
    • 2021-11-21
    • 2019-09-05
    • 2018-10-29
    • 1970-01-01
    相关资源
    最近更新 更多