我认为这里的问题并不真正涉及 TimeGrouper 可用的选项,而是您希望如何处理不均匀的数据。你基本上有4个我能想到的选择:
1) 删除足够的观察值(在开始或结束时),这样您就有了 2 年的观察值的倍数。
2) 推断您的开始(或结束)时期,使其与具有完整数据的时期具有可比性。
3) 根据少于 2 年的基础时间段将您的数据标准化为 2 年的总和。这种方法可以与其他两种方法结合使用。
4) 不要使用 groupby 方法,只需做一个 rolling_sum。
示例数据框:
rng = pd.date_range('1/1/2010', periods=60, freq='1m')
df = pd.DataFrame({ 'shopping' : np.random.choice(12,60) }, index=rng )
我刚刚用从 1 月 1 日开始的 5 年数据创建了示例数据集,所以如果你每年都这样做,你就完成了。
df.groupby([pd.TimeGrouper("AS", label='left')]).sum()['shopping']
Out[206]:
2010-01-01 78
2011-01-01 60
2012-01-01 76
2013-01-01 51
2014-01-01 60
Freq: AS-JAN, Name: shopping, dtype: int64
这是表格形式的问题,前两组基于 2 年的数据,而第三组仅基于 1 年的数据。
df.groupby([pd.TimeGrouper("2AS", label='left')]).sum()['shopping']
Out[205]:
2010-01-01 138
2012-01-01 127
2014-01-01 60
Freq: 2AS-JAN, Name: shopping, dtype: int64
如果您采用上述方法(1),您只需要放弃一些观察。删除后面的观察并重新输入相同的命令非常容易。放弃较早的观察有点棘手,因为这样您的第一次观察不会在偶数年的 1 月 1 日开始,并且您会丢失自动标记等。这是一种方法,将删除第一年并保留最后 4 年,但您会丢失漂亮的标签(您可以与上面的年度数据进行比较以验证这是否正确):
In [202]: df2 = df[12:]
In [203]: df2['group24'] = (np.arange( len(df2) ) / 24 ).astype(int)
In [204]: df2.groupby('group24').sum()['shopping']
Out[204]:
group24
0 136
1 111
或者,让我们尝试方法 (2),外推。为此,只需将 sum() 替换为 mean() 并乘以 24。对于上一期,这仅意味着我们假设 2014 年的 60 将等于 2015 年的另一个 60。这是否合理将是需要您做出判断,您可能希望用星号标记并将其称为估计值。
df.groupby([pd.TimeGrouper("2AS")]).mean()['shopping']*24
Out[208]:
2010-01-01 138
2012-01-01 127
2014-01-01 120
Freq: 2AS-JAN, Name: shopping, dtype: float64
另外请记住,这只是您可以在期末推断的一种简单(可能过于简单)的方法。这是否是最好的方法(或者推断是否有意义)是您根据情况做出的判断。
接下来,您可以采用方法 (3) 并进行某种标准化。我不确定你到底想要什么,所以我只是勾勒出这些想法。如果您想显示两年的总和,您可以使用前面的示例,将“2AS”替换为“AS”,然后乘以 2。这基本上会使表格看起来不正确,但这是制作图表的一种非常简单的方法看起来不错。
最后,只需使用滚动和:
pd.rolling_sum(df.shopping,window=24)
不能很好地表,但会很好地绘制。