【发布时间】:2014-10-28 03:28:12
【问题描述】:
我有一个多年的时间序列,需要我 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(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))
但我们每年都有单独的输出(多年来没有明显的方法来组合分位数限制)。
2004-12-01 0.036755
2005-03-01 0.034271
...
2007-09-01 0.098833
2007-12-01 0.068948
我还尝试制作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
分位数计算速度很快:
%%timeit
low_bounds = grouped.quantile(FRAC_2_TAIL)
> 2.94 ms per loop
添加季节列并对其进行分组在总体时间上是相似的。再次由dict 查找`主导:
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 秒。
【问题讨论】:
-
到底是哪一部分慢? low_bounds 和 high_bounds 计算?只是一个猜测,但也许在 groupby 之外创建季节变量会有所帮助。
-
问题现在似乎太长了。也许我应该通过对季节的上采样来改变最后一部分来回答。
标签: python pandas group-by time-series