Pandas TimeGrouper:删除 "non full groups"
Pandas TimeGrouper: Drop "non full groups"
我按一定频率对数据进行分组,但 TimeGrouper 似乎在右侧为某些 "left over" 数据创建了最后一个组。
df.groupby([pd.TimeGrouper("2AS", label='left')]).sum()['shopping'].plot()
我希望数据随着时间的推移相当稳定,但 2013
的最后一个数据点下降了将近一半。我预计会发生这种情况,因为每半年进行一次分组,后半部分 (2014
) 会丢失。
rolling_mean
允许 center=True
,这将把 NaN
/drop 余数放在左边和右边。 Grouper 有类似的功能吗? I couldn't find any on the manual,但也许有解决方法?
我认为这里的问题并不真正涉及 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
这是您的 table 形式的问题,前两组基于 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) 并进行某种规范化。我不确定你到底想要什么,所以我只是勾勒出这些想法。如果你想显示两年的总和,你可以只使用前面的例子,用 "AS" 替换“2AS”,然后乘以 2。这基本上使 table 看起来不对,但实际上让图表看起来不错的简单方法。
最后,只用滚动求和:
pd.rolling_sum(df.shopping,window=24)
不table 好,但会很好。
我按一定频率对数据进行分组,但 TimeGrouper 似乎在右侧为某些 "left over" 数据创建了最后一个组。
df.groupby([pd.TimeGrouper("2AS", label='left')]).sum()['shopping'].plot()
我希望数据随着时间的推移相当稳定,但 2013
的最后一个数据点下降了将近一半。我预计会发生这种情况,因为每半年进行一次分组,后半部分 (2014
) 会丢失。
rolling_mean
允许 center=True
,这将把 NaN
/drop 余数放在左边和右边。 Grouper 有类似的功能吗? I couldn't find any on the manual,但也许有解决方法?
我认为这里的问题并不真正涉及 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
这是您的 table 形式的问题,前两组基于 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) 并进行某种规范化。我不确定你到底想要什么,所以我只是勾勒出这些想法。如果你想显示两年的总和,你可以只使用前面的例子,用 "AS" 替换“2AS”,然后乘以 2。这基本上使 table 看起来不对,但实际上让图表看起来不错的简单方法。
最后,只用滚动求和:
pd.rolling_sum(df.shopping,window=24)
不table 好,但会很好。