【问题标题】:pandas resample to specific weekday in month熊猫重新采样到每月的特定工作日
【发布时间】:2019-02-28 21:48:09
【问题描述】:

我有一个 Pandas 数据框,我想在每个月的第三个星期五重新采样一次。

np.random.seed(0)
#requested output:
dates = pd.date_range("2018-01-01", "2018-08-31")
dates_df = pd.DataFrame(data=np.random.random(len(dates)), index=dates)
mask = (dates.weekday == 4) & (14 < dates.day) & (dates.day < 22)
dates_df.loc[mask]

但是当缺少第三个星期五时(例如,下降 2 月的第三个星期五 星期五),我想要最新的值(截至2018-02-15)。使用掩码给了我下一个值(2 月 17 日而不是 2 月 15 日):

# remove February third Friday:
dates_df = dates_df.drop([pd.to_datetime("2018-02-16")])
mask = (dates.weekday == 4) & (14 < dates.day) & (dates.day < 22)
dates_df.loc[mask]

将每月重采样与 loffset 结合使用可得出月末值并抵消索引,这也不是我想要的:

from pandas.tseries.offsets import WeekOfMonth
dates_df.resample("M", loffset=WeekOfMonth(week=2, weekday=4)).last()

是否有替代方法(最好使用重新采样),而不必先重新采样到每日值,然后添加掩码(这需要很长时间才能在我的数据帧上完成)

【问题讨论】:

  • 您是否尝试过其他偏移,例如业务月末频率pandas.pydata.org/pandas-docs/stable/… 这是相关帖子stackoverflow.com/questions/29871564/…
  • 恐怕使用偏移量对我没有帮助,因为它只会改变索引。
  • 你能提供预期输出的例子吗?使numpy.random 可预测使用np.random.seed(0)
  • 如果缺少第三个星期五,为什么第一个解决方案不起作用?
  • 我更新了示例。这表明二月份没有第三个星期五时缺少二月份的输出

标签: python pandas time-series


【解决方案1】:

您的第二次尝试是在正确的方向 IIUC,您只需要使用 WeekOfMonth 作为规则重新采样,而不是使用它作为偏移量:

dates_df.resample(WeekOfMonth(week=2, weekday=4)).asfreq().dropna()

这种方法不会抵消索引,它应该只是返回每个月第三个星期五的数据。

处理失踪的第三个星期五:

使用上面的代码,如果您缺少第三个星期五,则整个月都将被排除在外。但是根据你想如何处理丢失的数据,你可以bfillffillpad..你可以将上面的内容修改为:

dates_df.resample(rule=WeekOfMonth(week=2,weekday=4)).bfill().asfreq(freq='D').dropna()

上面将bfill 缺少的第三个星期五与下一个值。

更新:让我们使用固定数据集而不是np.random

# create a smaller daterange
dates = pd.date_range("2018-05-01", "2018-08-31")

# create a data with only 1,2,3 values
data = [1,2,3] * int(len(dates)/3)

dates_df = pd.DataFrame(data=data, index=dates)
dates_df.head()

# Output:

2018-05-01  1
2018-05-02  2
2018-05-03  3
2018-05-04  1
2018-05-05  2

现在让我们通过手动选择来检查每个月的第三个星期五的数据是什么样的:

dates_df.loc[[
    pd.Timestamp('2018-05-18'),
    pd.Timestamp('2018-06-15'),
    pd.Timestamp('2018-07-20'),
    pd.Timestamp('2018-08-17')
]]

Output:

2018-05-18  3
2018-06-15  1
2018-07-20  3
2018-08-17  1

如果您没有错过任何第三个星期五并运行之前提供的代码:

dates_df.resample(rule=WeekOfMonth(week=2,weekday=4)).asfreq().dropna()

将产生以下输出:

2018-05-18  3
2018-06-15  1
2018-07-20  3
2018-08-17  1

如您所见,这里的索引没有移动,它返回了每个月第三个星期五的准确值。

现在假设您确实缺少一些第 3 个星期五,这取决于您要如何处理(使用上一个值:ffill,或下一个值 bfill):

  • pad / ffill:将最后一个有效观察值向前传播到下一个有效观察值
  • backfill / bfill:使用 NEXT 有效观察来填补空白
dates_df.drop(index=pd.Timestamp('2018-08-17')).resample(rule=WeekOfMonth(week=2, weekday=4)).ffill().asfreq(freq='D').dropna()

2018-05-18  3
2018-06-15  1
2018-07-20  3
2018-08-17  3

dates_df.drop(index=pd.Timestamp('2018-08-17')).resample(rule=WeekOfMonth(week=2, weekday=4)).bfill().asfreq(freq='D').dropna()

2018-04-20  1
2018-05-18  3
2018-06-15  1
2018-07-20  3
2018-08-17  2

如果说整个索引像您的示例一样移动:

dates_df.resample(rule='M', loffset=WeekOfMonth(week=2, weekday=4)).asfreq().dropna()

# Output:

2018-06-15  1
2018-07-20  1
2018-08-17  2
2018-09-21  3

发生的情况是您按照规则“M”(月末)重新采样,然后在每个月的第三个星期五抵消(向前移动)索引。

正如你在偏移之前看到的,它的样子是这样的:

dates_df.resample(rule='M').asfreq().dropna()

# Output

2018-05-31  1
2018-06-30  1
2018-07-31  2
2018-08-31  3

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-04-25
    • 1970-01-01
    • 1970-01-01
    • 2020-10-19
    • 2017-06-10
    • 2021-06-01
    • 1970-01-01
    相关资源
    最近更新 更多