熊猫重新采样到每月的特定工作日

时间:2018-09-25 09:52:16

标签: python pandas time-series

我有一个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]

enter image description here

但是,如果缺少第三个星期五(例如,在2月 星期五),我想获取最新值(截至2018年2月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]

enter image description here

结合使用每月重新采样和loffset可以得到月末值,并且具有抵消索引的功能,这也不是我想要的:

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

enter image description here

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

1 个答案:

答案 0 :(得分:4)

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

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

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

  

处理第3个星期五缺失的问题:

使用上述代码,如果您缺少第三个星期五,则整个月都将被排除。但是根据您要如何处理丢失的数据,可以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

如果您没有缺少任何第3个星期五并运行之前提供的代码:

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

如您所见,索引没有在此处移动,它返回了每个月的第三个星期五的确切值。

现在说您确实缺少一些第三个星期五,具体取决于您要使用的方式(使用上一个值:ffill,或下一个值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