11.6 重新采样与频率转换
重新采样是指将时间序列从一个频率转化为另一个频率的过程。将更高频率的数据聚合到低频率称为向下采样,从低到高就是向上采样。当然,并不是所有的都是那两个,比如W-WED 转换到W-FRI 就不是向上或向下。
pandas对象有resample 方法,该方法时所有频率转换的工具函数,resample有类似goupby 的API,调用resample进行分组在调用聚合函数。
rng=pd.date_range('2000-01-01',periods=100,freq='D')
ts = pd.Series(np.random.randn(len(rng)),index=rng)
ts
2000-01-01 1.786314
2000-01-02 -0.291799
2000-01-03 -1.956842
2000-01-04 0.648374
2000-01-05 -1.181992
...
2000-04-05 2.299763
2000-04-06 -0.047460
2000-04-07 0.437328
2000-04-08 -2.216516
2000-04-09 -0.504831
Freq: D, Length: 100, dtype: float64
ts.resample('M').mean()
2000-01-31 -0.233850
2000-02-29 -0.106162
2000-03-31 -0.226881
2000-04-30 0.034787
Freq: M, dtype: float64
ts.resample('M',kind='period').size()
2000-01 31
2000-02 29
2000-03 31
2000-04 9
Freq: M, dtype: int64
resample 是一个灵活且高能的方法,用于处理大型时间序列。
resample参数 | 描述 |
---|---|
freq | 喵喵所需采样频率的字符串或dateoffset对象(例如M 5min, Second(1)) |
axis | 需要采样的轴向,默认axis=0 |
fill_method | 向上采样时的插值方式,开始ffill or bfill,默认不插值 |
closed | 向下采样中,每段间隔的那一段时封闭的,right or left |
label | 向下采样中,如果用right or left 的箱标签标记聚合结果(例如,9:30 到 9:35 的每分钟间隔可用标记为9:30 or 9"35) |
loffset | 对箱标签进行时间调教,例如 ‘ -1s’ /Second(-1) 可以将聚合标签向前移动一秒 |
limit | 向前或向后填充时,填充区间啊的最大值 |
kind | 对区间(‘period’) 或时间戳(timestamp) 的聚合,默认是时间序列索引的类型 |
convention | 在对区间重新采样时,用于将低频周期转换为高频的约定(start or end),默认 end |
11.6.1 向下采样
将数据聚合到一个规则的低频率上。你要聚合的数据不必是固定频率的。期望的频率定义了用于对时间序列切以聚合和的箱体边界。例如,要将时间转换为每月,M orMB ,你需要将数据分成一个月的时间间隔,每个间隔都是半闭合的,一个数据点只能属于一个间隔,时间间隔的并集必须是整个时间帧,现在使用resample 进行向下采样数据是要考虑:
- 每段间隔那一边是闭合的
- 如何在间隔的起始或结束位置标记每个已聚合的箱体。
rng = pd.date_range('2000-01-01', periods=12, freq='T')
ts = pd.Series(np.arange(12), index=rng)
ts
2000-01-01 00:00:00 0
2000-01-01 00:01:00 1
2000-01-01 00:02:00 2
2000-01-01 00:03:00 3
2000-01-01 00:04:00 4
2000-01-01 00:05:00 5
2000-01-01 00:06:00 6
2000-01-01 00:07:00 7
2000-01-01 00:08:00 8
2000-01-01 00:09:00 9
2000-01-01 00:10:00 10
2000-01-01 00:11:00 11
Freq: T, dtype: int32
ts.resample('5min',closed='right').sum() # 通过计算每一组的和将这些数据聚合到五分钟的块内。
1999-12-31 23:55:00 0
2000-01-01 00:00:00 15 # 这里按五分钟的增量定义了箱体边界,默认是左包含,00:00包含在00:00 00:05间隔内。
2000-01-01 00:05:00 40 # 由于传递了right 就变成了右包含。00:00 包含在23:55 :00:00 内
2000-01-01 00:10:00 11
Freq: 5T, dtype: int32
ts.resample('5min', closed='right', label='right').sum() # 产生的时间序列按照每个箱体左边的时间戳被标记
2000-01-01 00:00:00 0 # 传递label =right可以使用右箱体编辑标记时间序列。
2000-01-01 00:05:00 15 # 就是把右边那个边界当作了这个箱的标签。。。
2000-01-01 00:10:00 40
2000-01-01 00:15:00 11
Freq: 5T, dtype: int32
最后需要改将结果索引移动一定的数量,例如从右边缘减去一秒,以使其更清楚的表明时间戳所致的间隔。使用loffset 传递字符串或日期偏置
ts.resample('5min', closed='right',
label='right', loffset='-1s').sum()
1999-12-31 23:59:59 0
2000-01-01 00:04:59 15
2000-01-01 00:09:59 40
2000-01-01 00:14:59 11
Freq: 5T, dtype: int32 # 也可以在结果上调用shift 来完成loffset的效果。
11.6.1.1 开端-峰值-谷值-结束(OHLC)重新采样
金融中,每个数据桶计算四个值使一种流行的时间序列聚合方法:第一个/最后一个值,最大值/最小值。通过使用ohlc 聚合函数将会获得这四种列的dataframe, 这些值在数据的单次扫描中被高效计算。
ts.resample('5min').ohlc()
open high low close
2000-01-01 00:00:00 0 4 0 4
2000-01-01 00:05:00 5 9 5 9
2000-01-01 00:10:00 10 11 10 11
11.6.2 向上采样与插值
低频率转换为高频率,不用聚合。
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
Colorado Texas New York Ohio
2000-01-05 -2.645128 0.046365 2.081303 -0.269813
2000-01-12 0.628091 -0.796716 0.745522 0.543738 # 这是每周数据
# 当你对这数据使用聚合函数时,每一组只有一个值,其他的就是缺失值。使用asfeq 方法在不聚合的情况下转换到高频率。
df_daily = frame.resample('D').asfreq()
df_daily
Colorado Texas New York Ohio
2000-01-05 -2.645128 0.046365 2.081303 -0.269813
2000-01-06 NaN NaN NaN NaN
2000-01-07 NaN NaN NaN NaN
2000-01-08 NaN NaN NaN NaN
2000-01-09 NaN NaN NaN NaN
2000-01-10 NaN NaN NaN NaN
2000-01-11 NaN NaN NaN NaN
2000-01-12 0.628091 -0.796716 0.745522 0.543738
frame.resample('D').ffill(limit=2) # 向前填充,限制两层
Colorado Texas New York Ohio
2000-01-05 -2.645128 0.046365 2.081303 -0.269813
2000-01-06 -2.645128 0.046365 2.081303 -0.269813
2000-01-07 -2.645128 0.046365 2.081303 -0.269813
2000-01-08 NaN NaN NaN NaN
2000-01-09 NaN NaN NaN NaN
2000-01-10 NaN NaN NaN NaN
2000-01-11 NaN NaN NaN NaN
2000-01-12 0.628091 -0.796716 0.745522 0.543738
frame.resample('W-THU').ffill() # 新的入侵索引不需要u旧的索引重叠。
Colorado Texas New York Ohio
2000-01-06 -2.645128 0.046365 2.081303 -0.269813
2000-01-13 0.628091 -0.796716 0.745522 0.543738
11.6.3 使用区间进行重新采样
与时间戳的情况类似:
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]
Colorado Texas New York Ohio
2000-01 -1.717227 -0.760344 -0.765159 0.169781
2000-02 -2.126560 -0.111980 0.638584 -0.165626
2000-03 -0.022074 0.712966 0.119652 0.926564
2000-04 0.579960 1.233219 -0.245011 -0.520845
2000-05 0.621369 -0.581604 -1.582550 -0.155883
annual_frame = frame.resample('A-DEC').mean()
annual_frame
Colorado Texas New York Ohio
2000 -0.031077 -0.245267 0.181879 0.301356
2001 0.139282 -0.164084 0.004472 0.167112
向上采集更加细致,因为i你要在重新采集前决定新频率在时间段的那一段放置数值,就像asfreq 方法一样,convention参数默认时start ,可以时end
# Q-DEC: 季度末在12月
annual_frame.resample('Q-DEC').ffill()
Colorado Texas New York Ohio
2000Q1 -0.031077 -0.245267 0.181879 0.301356
2000Q2 -0.031077 -0.245267 0.181879 0.301356
2000Q3 -0.031077 -0.245267 0.181879 0.301356
2000Q4 -0.031077 -0.245267 0.181879 0.301356
2001Q1 0.139282 -0.164084 0.004472 0.167112
2001Q2 0.139282 -0.164084 0.004472 0.167112
2001Q3 0.139282 -0.164084 0.004472 0.167112
2001Q4 0.139282 -0.164084 0.004472 0.167112
annual_frame.resample('Q-DEC', convention='end').ffill() # 按我理解就是convention=start时,以2000.2001这两年的Q1放
Colorado Texas New York Ohio # 数据,之间的向前填充
2000Q4 -0.031077 -0.245267 0.181879 0.301356 # 为end 时,Q4 放数据,2000Q4之前的就没有填充值了,,,
2001Q1 -0.031077 -0.245267 0.181879 0.301356
2001Q2 -0.031077 -0.245267 0.181879 0.301356
2001Q3 -0.031077 -0.245267 0.181879 0.301356 # 仔细想想还是可以看懂的。。。
2001Q4 0.139282 -0.164084 0.004472 0.167112
区间设及时间范围,向上和向下采样旧更加严格
- 在向下采集中,目标频率必须是原频率的子区间
- 在向上采集中,目标频率必须时原频率的父区间
如果不满足就会引发异常。这主要会影响每季度,每年,每周的频率。例如:Q-MAR定义的时间范围将只和A-MAR,A-JUN A-SEP A-DEC保存一致
annual_frame.resample('Q-MAR').ffill()
Colorado Texas New York Ohio
2000Q4 -0.031077 -0.245267 0.181879 0.301356
2001Q1 -0.031077 -0.245267 0.181879 0.301356
2001Q2 -0.031077 -0.245267 0.181879 0.301356
2001Q3 -0.031077 -0.245267 0.181879 0.301356
2001Q4 0.139282 -0.164084 0.004472 0.167112
2002Q1 0.139282 -0.164084 0.004472 0.167112
2002Q2 0.139282 -0.164084 0.004472 0.167112
2002Q3 0.139282 -0.164084 0.004472 0.167112