Python 熊猫每年按季节分类
我有一个多年的时间序列,我想要95%的数据都在这个范围内。 我想按季节来看看这个('DJF','MAM','JJA','SON') 我试过以下几点:Python 熊猫每年按季节分类,python,pandas,group-by,time-series,Python,Pandas,Group By,Time Series,我有一个多年的时间序列,我想要95%的数据都在这个范围内。 我想按季节来看看这个('DJF','MAM','JJA','SON') 我试过以下几点: import pandas as pd import numpy as np FRAC_2_TAIL = 0.025 yr_idx = pd.date_range(start='2005-01-30', end='2008-02-02', freq='D') data = np.random.rand
import pandas as pd
import numpy as np
FRAC_2_TAIL = 0.025
yr_idx = pd.date_range(start='2005-01-30',
end='2008-02-02', freq='D')
data = np.random.rand(len(yr_idx))
df = pd.DataFrame(index=yr_idx, data=data, columns=['a'])
month_num_to_season = { 1:'DJF', 2:'DJF',
3:'MAM', 4:'MAM', 5:'MAM',
6:'JJA', 7:'JJA', 8:'JJA',
9:'SON', 10:'SON', 11:'SON',
12:'DJF'}
grouped = df.groupby(lambda x: month_num_to_season.get(x.month))
low_bounds = grouped.quantile(FRAC_2_TAIL)
high_bounds = grouped.quantile(1 - FRAC_2_TAIL)
它在给予的意义上起作用:
DJF 0.021284
JJA 0.024769
MAM 0.030149
SON 0.041784
但在我的每分钟频率、长达十年的数据集上需要很长时间
我可以利用TimeGrouper
几乎得到我想要的东西:
gp_time = df.groupby(pd.TimeGrouper('QS-DEC'))
low_bounds = gp_time.agg(lambda x: x.quantile(FRAC_2_TAIL))
但我们每年都有单独的产出(没有明显的方法来结合这些年的分位数限制)
我还尝试了制作一个freq='QS-DEC'
时间序列'DJF'、'MAM'等,以最小化字典查找,然后向上采样到df.index.freq
,并对其进行分组。它很慢,而且记忆也很重
我好像错过了一些明显的东西
编辑
根据@JohnE的评论
groupby中的dict
查找需要时间。使用5年的详细数据:
%%timeit
grouped = df.groupby(lambda x: month_num_to_season.get(x.month))
> 13.3 s per loop
In [16]: timeit [month_to_season_dct.get(t_stamp.month) for t_stamp in df.index]
1 loops, best of 3: 12.3 s per loop
In [17]: timeit month_to_season_lu[df.index.month]
1 loops, best of 3: 549 ms per loop
分位数计算速度很快:
%%timeit
low_bounds = grouped.quantile(FRAC_2_TAIL)
> 2.94 ms per loop
添加一个季节栏,并对其进行分组,这在总体时间安排上是类似的。再次被dict
lookup`控制:
SEAS = 'season'
%%timeit
df[SEAS] = [month_num_to_season.get(t_stamp.month) for t_stamp in df.index]
> 13.1 s per loop
%%timeit
gp_on_col = df.groupby(SEAS)
> 10000 loops, best of 3: 62.7 µs per loop
%%timeit
gp_on_col.quantile(FRAC_2_TAIL)
> 753 ms per loop
我重新实现了制作季度数据帧的方法,以最小化dict
查找,然后进行采样。这种方法现在看起来是一种实质性的改进:我不知道我以前是如何使它变得如此缓慢的:
SEASON_HALO = pd.datetools.relativedelta(months=4)
start_with_halo = df.index.min() - SEASON_HALO
end_with_halo = df.index.max() + SEASON_HALO
> 84.1 µs per loop
seasonal_idx = pd.DatetimeIndex(start=start_with_halo, end=end_with_halo, freq='QS-DEC')
seasonal_ts = pd.DataFrame(index=seasonal_idx)
> 440 µs per loop
seasonal_ts[SEAS] = [month_num_to_season.get(t_stamp.month) for t_stamp in seasonal_ts.index]
> 1.25 s per loop
seasonal_minutely_ts = seasonal_ts.resample(df.index.freq, fill_method='ffill')
> 5.12 ms per loop
df_via_resample = df.join(seasonal_minutely_ts)
> 47 ms per loop
gp_up_sample = df_via_resample.groupby(SEAS)
> 63.4 µs per loop
gp_up_sample.quantile(FRAC_2_TAIL)
> 834 ms per loop
对于其他方法,这大约是2秒对13秒。如果有帮助,我建议替换您认为缓慢的以下列表理解和dict查找:
month_to_season_dct = {
1: 'DJF', 2: 'DJF',
3: 'MAM', 4: 'MAM', 5: 'MAM',
6: 'JJA', 7: 'JJA', 8: 'JJA',
9: 'SON', 10: 'SON', 11: 'SON',
12: 'DJF'
}
grp_ary = [month_to_season_dct.get(t_stamp.month) for t_stamp in df.index]
使用以下命令,它使用numpy数组作为查找表
month_to_season_lu = np.array([
None,
'DJF', 'DJF',
'MAM', 'MAM', 'MAM',
'JJA', 'JJA', 'JJA',
'SON', 'SON', 'SON',
'DJF'
])
grp_ary = month_to_season_lu[df.index.month]
下面是两种方法在~3年的详细数据上的timeit比较:
%%timeit
grouped = df.groupby(lambda x: month_num_to_season.get(x.month))
> 13.3 s per loop
In [16]: timeit [month_to_season_dct.get(t_stamp.month) for t_stamp in df.index]
1 loops, best of 3: 12.3 s per loop
In [17]: timeit month_to_season_lu[df.index.month]
1 loops, best of 3: 549 ms per loop
到目前为止,最快的方法是创建一个低频时间序列来进行季节查找,以及@Garrett使用
numpy.array
索引查找而不是dict
的方法
season_lookup = np.array([
None,
'DJF', 'DJF',
'MAM', 'MAM', 'MAM',
'JJA', 'JJA', 'JJA',
'SON', 'SON', 'SON',
'DJF'])
SEASON_HALO = pd.datetools.relativedelta(months=4)
start_with_halo = df.index.min() - SEASON_HALO
end_with_halo = df.index.max() + SEASON_HALO
seasonal_idx = pd.DatetimeIndex(start=start_with_halo, end=end_with_halo, freq='QS-DEC')
seasonal_ts = pd.DataFrame(index=seasonal_idx)
seasonal_ts[SEAS] = season_lookup[seasonal_ts.index.month]
seasonal_minutely_ts = seasonal_ts.resample(df.index.freq, fill_method='ffill')
df_via_resample = df.join(seasonal_minutely_ts)
gp_up_sample = df_via_resample.groupby(SEAS)
gp_up_sample.quantile(FRAC_2_TAIL)
10年的分钟数据,在我的机器上:这是关于:
- 比低频
lookup-up-sample快2%dict
- 比正常频率快7%。数组查找
- >比我原来的方法提高400%
data = pd.read_excel(DATAPATH)
data["Date"] = pd.to_datetime(data["Date"])
def MonthToSeason(x):
global season
if x == 6 or x == 7 or x == 8 or x == 9:
season = "Monsoon"
elif x == 10 or x == 11:
season = "Post-monsoon"
elif x == 12 or x == 1 or x == 2:
season = "Winter"
elif x == 3 or x == 4 or x == 5:
season = "Summer"
else:
season = np.nan
return season
data['Season'] = data['Date'].dt.month.apply(lambda x : MonthToSeason(x))
GroupedData = data.groupby(data["Season"]).agg(['count','min','mean','max','std'])
到底哪一部分慢?下限和上限计算?只是一个猜测,但也许在groupby之外创建季节变量会有所帮助。现在这个问题似乎太长了。也许我应该把最后一部分的季节抽样改成一个答案。既然我采用了@Garrett的方法,我应该把它标记为社区维基吗?