#!/usr/bin/env python # coding: utf-8 # # 11.6 Resampling and Frequency Conversion(重采样和频度转换) # # 重采样(Resampling)指的是把时间序列的频度变为另一个频度的过程。把高频度的数据变为低频度叫做降采样(downsampling),把低频度变为高频度叫做增采样(upsampling)。并不是所有的重采样都会落入上面这几个类型,例如,把W-WED(weekly on Wednesday)变为W-FRI,既不属于降采样,也不属于增采样。 # # pandas对象自带resampe方法,用于所有的频度变化。resample有一个和groupby类似的API;我们可以用resample来对数据进行分组,然后调用聚合函数(aggregation function): # In[1]: import numpy as np import pandas as pd # In[3]: rng = pd.date_range('2000-01-01', periods=100, freq='D') # In[11]: ts = pd.Series(np.random.randn(len(rng)), index=rng) ts # In[10]: ts.resample('M').mean() # In[12]: ts.resample('M', kind='period').mean() # resample是一个灵活且高效的方法,可以用于处理大量的时间序列。下面是一些相关的选项: # # ![](http://oydgk2hgw.bkt.clouddn.com/pydata-book/nwc0s.png) # # # 1 Downsampling(降采样) # # 把数据聚合为规律、低频度是一个很普通的时间序列任务。用于处理的数据不必是有固定频度的;我们想要设定的频度会定义箱界(bin edges),根据bin edges会把时间序列分割为多个片段,然后进行聚合。例如,转换为月度,比如'M'或'BM',我们需要把数据以月为间隔进行切割。每一个间隔都是半开放的(half-open);一个数据点只能属于一个间隔,所有间隔的合集,构成整个时间范围(time frame)。当使用resample去降采样数据的时候,有很多事情需要考虑: # # - 在每个间隔里,哪一边要闭合 # - 怎样对每一个聚合的bin贴标签,可以使用间隔的开始或结束 # # 为了演示一下,下面用一个一分钟的数据来举例: # In[13]: rng = pd.date_range('2000-01-01', periods=12, freq='T') # In[14]: ts = pd.Series(np.arange(12), index=rng) ts # 假设我们想要按5分钟一个数据块来进行聚合,然后对每一个组计算总和: # In[15]: ts.resample('5min', closed='right').sum() # 我们传入的频度定义了每个bin的边界按5分钟递增。默认,bin的左边界是闭合的,所以`00:00`值是属于`00:00`到`00:05`间隔的。设定closed='right',会让间隔的右边闭合: # In[16]: ts.resample('5min', closed='right').sum() # 默认,每一个bin的左边的时间戳,会被用来作为结果里时间序列的标签。通过设置label='right',我们可以使用bin右边的时间戳来作为标签: # In[17]: ts.resample('5min', closed='right', label='right').sum() # 可以看下图方便理解: # # ![](http://oydgk2hgw.bkt.clouddn.com/pydata-book/d770h.png) # # 最后,我们可能想要对结果的索引进行位移,比如在右边界减少一秒。想要实现的话,传递一个字符串或日期偏移给loffset: # In[18]: ts.resample('5min', closed='right', label='right', loffset='-1s').sum() # 我们也可以使用shift方法来实现上面loffset的效果。 # # ### Open-High-Low-Close (OHLC) resampling(股价图重取样) # # > Open-High-Low-Close: 开盘-盘高-盘低-收盘图;股票图;股价图 # # 在经济界,一个比较流行的用法,是对时间序列进行聚合,计算每一个桶(bucket)里的四个值:first(open),last(close),maximum(high),minimal(low),即开盘-收盘-盘高-盘低,四个值。使用ohlc聚合函数可以得到这四个聚合结果: # In[19]: ts.resample('5min').ohlc() # # 2 Upsampling and Interpolation(增采样和插值) # # 把一个低频度转换为高频度,是不需要进行聚合的。下面是一个有周数据的DataFrame: # In[20]: frame = pd.DataFrame(np.random.randn(2, 4), index=pd.date_range('1/1/2000', periods=2, freq='W-WED'), columns=['Colorado', 'Texas', 'New York', 'Ohio']) frame # 当我们对这个数据进行聚合的的时候,每个组只有一个值,以及gap(间隔)之间的缺失值。在不使用任何聚合函数的情况下,我们使用asfreq方法将其转换为高频度: # In[21]: df_daily = frame.resample('D').asfreq() df_daily # 假设我们想要用每周的值来填写非周三的部分。这种方法叫做填充(filling)或插值(interpolation),可以使用fillna或reindex方法来实现重采样: # In[22]: frame.resample('D').ffill() # 我们可以选择只对一部分的周期进行填写: # In[23]: frame.resample('D').ffill(limit=2) # 注意,新的日期索引不能与旧的有重叠: # In[25]: frame.resample('W-THU').ffill() # # 3 Resampling with Periods(对周期进行重采样) # # 对周期的索引进行重采样的过程,与之前时间戳的方法相似: # In[26]: frame = pd.DataFrame(np.random.randn(24, 4), index=pd.period_range('1-2000', '12-2001', freq='M'), columns=['Colorado', 'Texas', 'New York', 'Ohio']) frame[:5] # In[27]: annual_frame = frame.resample('A-DEC').mean() annual_frame # 增采样需要考虑的要多一些,比如在重采样前,选择哪一个时间跨度作为结束,就像asfreq方法那样。convertion参数默认是'start',但也能用'end': # In[28]: # Q-DEC: Quarterly, year ending in December annual_frame.resample('Q-DEC').ffill() # In[29]: annual_frame.resample('Q-DEC', convention='end').ffill() # 增采样和降采样的规则更严格一些: # # - 降采样中,目标频度必须是原频度的子周期(subperiod) # - 增采样中,目标频度必须是原频度的母周期(superperiod) # # 如果不满足上面的规则,会报错。主要会影响到季度,年度,周度频度;例如,用Q-MAR定义的时间跨度只与A-MAR, A-JUN, A-SEP, A-DEC进行对齐(line up with): # In[30]: annual_frame.resample('Q-MAR').ffill()