Py学习  »  Python

利用Python进行数据分析(十八)之时区时期处理续

BrainZou • 5 年前 • 517 次点击  

利用Python进行数据分析(十八)之时区时期处理续

微信公众号:BrainZou
欢迎关注,一起学习。
回复“资料”,有本人收集的各种Python,Java,Android,小程序,后端,算法等等近1T的资料免费分享给你。

重采样及频率转换

重采样(resampling)指的是将时间序列从一个频率转换到另一个频率的处理过程。将高频率数据聚合到低频率称为降采样(downsampling),而将低频率数据转换到高频率则称为升采样(upsampling)。
pandas对象都带有一个resample方法,它是各种频率转换工作的主力函数:

import pandas as pd
from pandas import Series,DataFrame
import numpy as np
rng = pd.date_range('1/1/2000',periods=100,freq='D')
ts = Series(np.random.randn(len(rng)),index = rng)
ts.resample('M').mean()
out
2000-01-31 -0.190745
2000 -02-29 -0.126734
2000-03-31 -0.080295
2000-04-30 0.157770
Freq: M, dtype: float64
ts.resample('M',kind='period').mean()
out
2000-01 -0.190745
2000-02 -0.126734
2000-03 -0.080295
2000-04 0.157770
Freq: M, dtype: float64
resample方法参数
resample方法参数

注意 how='mean' 的使用已经变成了.mean()。

降采样

将数据聚合到规整的低频率是一件非常普通的时间序列处理任务。待聚合的数据不必拥有固定的频率,期望的频率会自动定义聚合的面元边界,这些面元用于将时间序列拆分为多个片段。例如,要转换到月度频率(M‘或‘BM’),数据需要被划分到多个单月时间段中。各时间段都是半开放的。一个数据点只能属于一个时间段,所有时间段的并集必须能组成整个时间帧。在用resample对数据进行降采样时,需要考虑两样东西:
·各区间哪边是闭合的。
·如何标记各个聚合面元,用区间的开头还是末尾。
首先,我们来看一些“1分钟”数据:

rng = pd.date_range('1/1/2000',periods=12,freq='T')
rng
out
DatetimeIndex(['2000-01-01 00:00:00', '2000-01-01 00:01:00',
'2000-01-01 00:02:00', '2000-01-01 00:03:00',
'2000-01-01 00:04:00', '2000-01-01 00:05:00',
'2000-01-01 00:06:00', '2000-01-01 00:07:00',
'2000-01-01 00:08:00', '2000-01-01 00:09:00',
'2000-01-01 00:10:00', '2000-01-01 00:11:00'],
dtype='datetime64[ns]', freq='T')

假设想要通过求和的方式将这些数据聚合到“5分钟”块中:

ts.resample('5min').sum()
out :
2000-01-01 00:00:00 10
2000-01-01 00:05:00 35
2000-01-01 00:10:00 21
Freq: 5T, dtype: int32
#现在已经改了,目前是00:00:00代表的是[0,5)左闭右开
#即默认closed='left'

传入closed='right'则代表(0,5]
而默认的label=‘left’则是显示00:00:00这个取左边界做标签。用label='right'则取右边界。
最后,你可能希望对结果索引做一些位移,比如从右边界减去一秒以便更容易明白该时间戳到底表示的是哪个区间。只需通过loffset设置一个字符串或日期偏移量即可实现这个目的:

ts.resample('5min',closed='right',loffset='-1s',label='right').sum()
out
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了。如下:

ts.resample('5min',closed='right',label='right').sum().shift(-1,freq='1s')
#与上面的效果是一样的

OHLC重采样

金融领域中有一种无所不在的时间序列聚合方式,即计算各面元的四个值:第一个值(open,开盘)、最后一个值(close,收盘)、最大值(high,最高)以及最小值(low,最低)。传入how=‘ohlc‘即可得到一个含有这四种聚合值的DataFrame。整个过程很高效,只需一次扫描即可计算出结果:

ts.resample('5min').ohlc()
out:
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

通过groupby进行重采样

另一种降采样的办法是使用pandas的groupby功能。例如,你打算根据月份或星期几进行分组,只需传入一个能够访问时间序列的索引上的这些字段的函数即可:

rng=pd.date_range('1/1/2000',periods=100,freq='D')
ts = Series(np.arange(100),index=rng)
ts.groupby(lambda x:x.month).mean()
out:
1 15
2 45
3 75
4 95
dtype: int32

升采样和插值

在将数据从低频率转换到高频率时,就不需聚合。我们来看一个带有一些周型数据的DataFrame:

frame = 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[:5]
out :
Colorado Texas New York Ohio
2000-01-05 -0.058262 -0.171898 2.640883 0.424472
2000-01-12 -0.090311 -0.642417 1.531462 -0.387131

将其重采样到日频率,默认会引入缺失值:

df_daily = frame.resample('D')
df_daily
out :
DatetimeIndexResampler [freq=<Day>, axis=0, closed=left, label=left, convention=start, base=0]
df_daily .asfreq()[0:]
out:
Colorado Texas New York Ohio
2000-01-05 -0.058262 -0.171898 2.640883 0.424472
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.090311 -0.642417 1.531462 -0.387131

因为frame.resample返回的是一个 pandas.tseries.resample.DatetimeIndexResampler对象
所以想要获取其中的值可以通过 data_new.asfreq()[0:]获取。
假设你想要用前面的周型值填充“非星期三”。resample的填充和插值方式跟fillna和reindex的一样:

frame.resample('D').ffill()
#还可以添加limit=2这样来限制只有两行用之前值填充

通过时期进行重采样

对那些使用时期索引的数据进行重采样是件非常简单的事情:

frame=DataFrame(np.random.randn(24,4), index=pd.period_range('1-2000','12-2001', freq='M'), columns=['Colorado','Texas','New York','Ohio'])
frame.resample('A-DEC').mean()
out
Colorado Texas New York Ohio
2000 -0.252341 0.258722 -0.456961 0.079480
2001 -0.222091 0.055458 -0.025023 0.433796

升采样要稍微麻烦一些,因为你必须决定在新频率中各区间的哪端用于放置原来的值,就像asfreq方法那样.convention参数默认为‘end’,可设置为‘start‘。
由于时期指的是时间区间,所以升采样和降采样的规则就比较严格:
·在降采样中,目标频率必须是源频率的子时期(subperiod)。
·在升采样中,目标频率必须是源频率的超时期(superperiod)。
如果不满足这些条件,就会引发异常。这主要影响的是按季、年、周计算的频率。例如,由Q-MAR定义的时间区间只能升采样为A-MAR、A-JUN、A-SEP、A-DEC等:

移动窗口函数

在移动窗口(可以带有指数衰减权数)上计算的各种统计函数也是一类常见于时间序列的数组变换。它们被称为移动窗口函数(moving window function),其中还包括那些窗口不定长的函数(如指数加权移动平均)。跟其他统计函数一样,移动窗口函数也会自动排除缺失值。
rolling_mean是其中最简单的一个。它接受一个TimeSeries或DataFrame以及一个window(表示期数)(已经改为rolling().mean()):

frame.rolling(window=250,center=False).mean()
函数已改,仅做参考了
函数已改,仅做参考了

指数加权函数

另一种使用固定大小窗口及相等权数观测值的办法是,定义一个衰减因子(decayfactor)常量,以便使近期的观测值拥有更大的权数。用数学术语来讲,如果mat,是时间t的移动平均结果,x是时间序列,结果中的各个值可用


进行计算,其中a为衰减因子。衰减因子的定义方式有很多,比较流行的是使用时间间隔(span),它可以使结果兼容于窗口大小等于时间间隔的简单移动窗口(simple movingwindow)函数。由于指数加权统计会赋予近期的观测值更大的权数,因此相对于等权统计译注10,它能“适应”更快的变化。下面这个例子对比了苹果公司股价的60日移动平均和span=60的

二元移动窗口函数

有些统计运算(如相关系数和协方差)需要在两个时间序列上执行。例如,金融分析师常常对某只股票对某个参考指数(如标准普尔500指数)的相关系数感兴趣。我们可以通过计算百分数变化并使用rolling().corr()(以前是rolling_corr)的方式得到该结果(如图10-12所示):

用户定义的移动窗口函数

rolling_apply函数使你能够在移动窗口上应用自己设计的数组函数。唯一要求的就是:该函数要能从数组的各个片段中产生单个值(即约简)。比如说,当我们用rolling_quantile计算样本分位数时,可能对样本中特定值的百分等级感兴趣.scipy。stats.percentileofscore函数就能达到这个目的:

性能和内存使用方面的注意事项

Timestamp和Period都是以64位整数表示的(即NumPy的datetime64数据类型)。也就是说,对于每个数据点,其时间戳需要占用8字节的内存。因此,含有一百万个float64数据点的时间序列需要占用大约16MB的内存空间。由于pandas会尽量在多个时间序列之间共享索引,所以创建现有时间序列的视图不会占用更多内存译注11.此外,低频率索引(日以上)会被存放在一个中心缓存中,所以任何固定频率的索引都是该日期缓存的视图。所以,如果你有一个很大的低频率时间序列,索引所占用的内存空间将不会很大。性能方面,pandas对数据对齐(两个不同索引的ts1+ts2的幕后工作)和重采样运算进行了高度优化。

总结

时间序列这章到这结束,移动窗口函数没有详细贴,主要原因是自己暂时没用上,看不大懂。。。之后有机会补上。


今天看啥 - 高品质阅读平台
本文地址:http://www.jintiankansha.me/t/1Ks6Un1w23
Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/11912
 
517 次点击