Python 使用日期指数从pandas数据框计算3个月滚动中值

Python 使用日期指数从pandas数据框计算3个月滚动中值,python,pandas,time-series,Python,Pandas,Time Series,我从一个输入数据帧开始,看起来像: df = pd.DataFrame({"created_on":[datetime(2015, 1, 3), datetime(2015 , 1, 5), datetime(2015, 2, 24), datetime(2015, 3, 6),

我从一个输入
数据帧开始,看起来像:

df = pd.DataFrame({"created_on":[datetime(2015, 1, 3),
                                 datetime(2015 , 1, 5),
                                 datetime(2015, 2, 24),
                                 datetime(2015, 3, 6),
                                 datetime(2015, 3, 17),
                                 datetime(2015, 5, 31),
                                 datetime(2015, 6, 3)],
           "value":[3, 2, 1, 1, 3, 2, 2]
           }
   )

我想得到,每个月,
创建的观测值的中位数是在当前月份或从当前月份开始的过去2个月内

上述输入数据的预期输出为:

month        median_value
2015-01-01   2.5
2015-02-01   2
2015-03-01   2
2015-04-01   1
2015-05-01   2
2015-06-01   2
即对于“2015-01-01”,仅使用观察值“2015-01-03”和“2015-01-05”,对于“2015-02-01”月,我取“2015-01-03”、“2015-01-05”和“2015-02-24”等

我想从日期列中提取月份,然后像这样使用
groupby

 df['created_on_month'] = df['created_on'].apply(
                   lambda dt: datetime(dt.year, dt.month, 1)
 )
 df.groupby('created_on_month').median()
但是我不知道如何在3个月内在
groupby
中聚合,从而一行可以属于多个组。此解决方案的另一个问题是,结果中不会出现空月(“上述示例中的“2015-04-01”)

我也尝试过使用pandas提供的
rolling_median
来完成这项工作,但它使用了
resample
,在计算观察次数时效果很好,但中间值并不相同

最后,我还可以使用一个简单的循环,如:

months = pd.date_range('2015-01-01', '2015-06-01', freq='MS')
output = pd.DataFrame(index=months, columns=("month", "median_value"))

for m in months:
    tmp = df [ (df.created_on >= (m - pd.DateOffset(months=2))) 
             & (df.created_on <= m+pd.DateOffset(months=1))]
    res = {"month":m, "median_value":tmp["value"].median()}
    output.loc[m] = res

print output 

但是,如果有一个更优雅的解决方案存在,我会很高兴了解它

好的,这应该很接近了。我使用90天窗口b/c,我不确定是否可以使用3个月窗口。否则,它似乎工作得很好

df2 = pd.rolling_apply( df.set_index('created_on')['value'], window=90, 
                        func=np.nanmedian, freq='d', min_periods=1 )

df2[ (df2.index.day == 1)[1:] ]   # [1:] is a kludge to get end of month
                                  # rather than beginning, probably a 
                                  # better way to do that...

created_on
2015-01-31    2.5
2015-02-28    2.0
2015-03-31    2.0
2015-04-30    1.0
2015-05-31    2.0
请注意,因为我的方法与您的不同,它显示为月底而不是月初,但这不会以任何方式影响结果,而且我认为月底实际上更准确

我不确定打印2015年6月的结果的最佳方法,但它已正确存储在6月3日的df2中:

df2.tail(1)

created_on
2015-06-03    2

因此,这只是如何最好地提取和显示信息的问题。我想用6月30日的缺失值填充原始数据帧是一种方法。

我刚刚测试过,是的,我们可以使用
freq=“3MS”
。无论如何,非常感谢你,它就像一个符咒!
df2 = pd.rolling_apply( df.set_index('created_on')['value'], window=90, 
                        func=np.nanmedian, freq='d', min_periods=1 )

df2[ (df2.index.day == 1)[1:] ]   # [1:] is a kludge to get end of month
                                  # rather than beginning, probably a 
                                  # better way to do that...

created_on
2015-01-31    2.5
2015-02-28    2.0
2015-03-31    2.0
2015-04-30    1.0
2015-05-31    2.0
df2.tail(1)

created_on
2015-06-03    2