使用pandas在滚动窗口中重新取样

时间:2014-07-21 22:09:26

标签: python pandas resampling

假设我有每日数据(不规则间隔),我想计算过去每个月的移动标准差(或任意非线性函数) 5个月。例如,对于2012年5月,我将计算从2012年1月到2012年5月(5个月)期间的stddev。对于2012年6月,期间从2012年2月开始,等等。最终结果是具有月度值的时间序列。

无法应用滚动窗口,因为这首先是每天,其次我需要指定值的数量(滚动窗口不按时间帧聚合,有些帖子解决了这个问题{{3但是它们与我的问题无关,因为滚动仍然适用于每一个新的一天。)

无法应用重新取样,因为那时样本将是每5个月一次,例如我将只有2012年5月,2012年10月,2013年3月的价值...最后,作为函数不是线性的我不能通过先做每月样本然后在其上应用5期滚动窗口来重建它。

所以我需要一种应用于由时间间隔(不是数值)定义的滚动窗口的重新取样功能。

我怎么能在熊猫中这样做?一种方法可能是将几个(本例中为5个)重采样(5个月)时间序列组合在一起,每个时间序列都有一个月的偏移量,然后将所有这些序列对齐成一个......但我不知道如何实现这个。

3 个答案:

答案 0 :(得分:2)

我在处理timedelta系列时有类似的问题,我想采用移动平均线然后重新采样。这是一个我有100秒数据的例子。我采用10秒窗口的滚动平均值,然后每5秒重新采样一次,取每个重采样箱中的第一个条目。结果应该是之前的10秒平均值,增量为5秒。您可以使用月份格式而不是秒来执行类似的操作:

df = pd.DataFrame(range(0,100), index=pd.TimedeltaIndex(range(0,100),'s'))
df.rolling('10s').mean().resample('5s').first()

结果:

             0
00:00:00   0.0
00:00:05   2.5
00:00:10   5.5
00:00:15  10.5
00:00:20  15.5
00:00:25  20.5
00:00:30  25.5
00:00:35  30.5
00:00:40  35.5
00:00:45  40.5
00:00:50  45.5
00:00:55  50.5
00:01:00  55.5
00:01:05  60.5
00:01:10  65.5
00:01:15  70.5
00:01:20  75.5
00:01:25  80.5
00:01:30  85.5
00:01:35  90.5

答案 1 :(得分:1)

这是一次尝试 - 不是超级干净,但它可能有用。

虚拟数据:

df = pd.DataFrame(data={'a': 1.}, 
                  index=pd.date_range(start='2001-1-1', periods=1000))

首先定义一个函数来减少日期n个月。这需要清理,但适用于n <= 12。

from datetime import datetime    
def decrease_month(date, n):
    assert(n <= 12)

    new_month = date.month - n
    year_offset = 0
    if new_month <= 0:
        year_offset = -1
        new_month = 12 + new_month

    return datetime(date.year + year_offset, new_month, 1)

然后,为每个日期将跨越的5个滚动周期添加5个新列。

for n in range(rolling_period):
    df['m_' + str(n)] = df.index.map(lambda x: decrease_month(x, n))

然后 - 使用melt函数将数据从wide转换为long,因此每个滚动周期将有一个条目。

df_m = pd.melt(df, id_vars='a')

您应该能够通过新创建的列进行分组,每个日期将代表正确的5个月滚动期。

In [222]: df_m.groupby('value').sum()
Out[222]: 
              a
value          
2000-09-01   31
2000-10-01   59
2000-11-01   90
2000-12-01  120
2001-01-01  151
2001-02-01  150
2001-03-01  153
2001-04-01  153
2001-05-01  153
2001-06-01  153
2001-07-01  153
...

答案 2 :(得分:0)

我已经通过以下代码解决了类似的问题:

interval = 5
frames = []
for base in range(interval):
  frame = data.resample(f"{interval}min", base=base).last()
  frames.append(frame)

pd.concat(frames, axis=0).sort_index()

在这里,我创建了5个数据帧,它们以相同的间隔重新采样,但是具有不同的偏移量(基本参数)。然后,我只需要串联并排序它们。通常应该比滚动+重采样更为有效(唯一的开销就是排序)。