[Python for Data Analysis] Chapter10 时间序列
2016-05-19 00:14
896 查看
1 日期和时间数据类型及工具
datetime 里面有 datetime, time 以及 calendar 模块,其中 datetime 用得最多datetime 模块中的数据类型:
date:以公历形式存储日历日期(年、月、日)
time:将时间存储为时、分、秒、毫秒
datetime:存储日期和时间,相当于 date 与 time 的结合
timedelta:两个 datetime 值的差(天数+毫秒数)
1.1 字符串和 datetime 的相互转换
1.1.1 datetime –>字符串: datetime.strftime
In [17]: from datetime import datetime In [18]: now = datetime.now() In [19]: str(now) Out[19]: '2016-05-18 22:52:07.185000' In [20]: stamp = datetime(2011,1,3) In [21]: str(stamp) Out[21]: '2011-01-03 00:00:00' In [22]: stamp.strftime('%Y-%m-%d') Out[22]: '2011-01-03'
datetime.strftime:把标准格式的日期转化为字符串
1.1.2 字符串–> datetime: datetime.strptime, dateutil.parser.parse, pandas.to_datetime
In [23]: value = '2011-01-03' In [24]: datetime.strptime(value, '%Y-%m-%d') Out[24]: datetime.datetime(2011, 1, 3, 0, 0)
datetime.strptime:把字符串转化为标准格式的日期,但每次都需要指定格式,为了省去麻烦,可以使用 dateutil 包的 parser.parse 方法。
In [25]: from dateutil.parser import parse In [26]: parse('2011-01-03') Out[26]: datetime.datetime(2011, 1, 3, 0, 0) In [27]: parse('Jan 31, 1997 10:45 PM') Out[27]: datetime.datetime(1997, 1, 31, 22, 45) In [28]: parse('6/12/2011', dayfirst=True) #通过 dayfirst 来指定日是否位于月前面 Out[28]: datetime.datetime(2011, 12, 6, 0, 0)
dateutil.parser.parse:几乎可以解析人类能理解的所有日期格式(除了中文)
In [30]: import pandas as pd In [31]: datestrs = ['7/6/2011', '8/6/2011'] In [32]: pd.to_datetime(datestrs) Out[32]: DatetimeIndex(['2011-07-06', '2011-08-06'], dtype='datetime64[ns]', freq=None, tz=None) In [34]: idx = pd.to_datetime(datestrs+[None]) #可以处理缺失值(None、空字符串等) In [35]: idx Out[35]: DatetimeIndex(['2011-07-06', '2011-08-06', 'NaT'], dtype='datetime64[ns]', freq=None, tz=None) #NaT表示Not a Time,是pandas中时间戳数据的 NA 值 In [36]: pd.isnull(idx) Out[36]: array([False, False, True], dtype=bool)
pandas.to_datetime:也不需要指定格式
1.1.3 datetime 完整的格式化编码如下:
%Y:4位数的年%y:2位数的年
%m:2位数的月[01-12]
%d:2位数的日[01-31]
%H:24小时制的时[00-23]
%I:12小时制的时[01-12]
%M:2位数的分[00-59]
%S:秒[00-61](秒 60 和 61 用于闰秒)
%w:整数表示的星期几[0(星期天)-6]
%U:每年的第几周[00-53](星期天被认为是每周的第一天,每年的第一个星期天之前的那几天被认为是第0周
%W:每年的第几周[00-53](星期一被认为是每周的第一天,每年的第一个星期一之间的那几天被认为是第0周
%z:以+HHMM或-HHMM表示的UTC时区偏移量,如果时区为naive,则返回空字符串
%F:%Y-%m-%d简写形式,如2012-04-18
%D:%m/%d/%y简写形式,如04/18/12
2 时间序列基础
pandas 里 TimeSeries 是索引为 DatetimeIndex 的 DataFrame,索引各标量值是 Timestamp 对象,只要有需要,Timestamp 可以随时自动转换为 datetime 对象。2.1 索引、选取、子集构造
索引、切片可以传入的参数有字符串日期、datetime和Timestamp,切片所产生的是源时间序列的视图,以下对 Series 和 DataFrame 都可行。In [11]: dates = [datetime(2011,1,2), datetime(2011,1,5), datetime(2011,1,7), datetime(2011,1,8), datetime(2011,1,10)] In [12]: ts = Series(np.random.randn(5), index=dates) In [13]: ts Out[13]: 2011-01-02 -0.229374 2011-01-05 0.019728 2011-01-07 -0.970264 2011-01-08 0.510564 2011-01-10 -0.362988 dtype: float64 In [14]: ts['1/10/2011'] Out[14]: -0.36298849884900225 In [15]: ts['20110110'] Out[15]: -0.36298849884900225
索引为日期的字符串
In [17]: longer_ts = Series(np.random.randn(1000), index=pd.date_range('1/1/2000', periods=1000)) In [18]: longer_ts['2001'] #按年来切片 Out[18]: 2001-01-01 -0.708689 2001-01-02 0.413011 2001-01-03 0.691649 2001-01-04 -1.618438 ... 2001-12-28 1.797995 2001-12-29 0.523404 2001-12-30 -1.009356 2001-12-31 -1.727535 Freq: D, dtype: float64 In [19]: longer_ts['2002-05'] #按年月来切片 Out[19]: 2002-05-01 -0.268770 2002-05-02 0.258283 2002-05-03 0.585388 2002-05-04 0.288742 ... 2002-05-28 -0.763912 2002-05-29 0.025560 2002-05-30 0.610600 2002-05-31 0.134653 Freq: D, dtype: float64
索引为年或年月来切片
In [20]: ts[datetime(2011,1,7):] Out[20]: 2011-01-07 -0.970264 2011-01-08 0.510564 2011-01-10 -0.362988 dtype: float64 In [21]: ts[datetime(2011,1,7):datetime(2011,1,10)] Out[21]: 2011-01-07 -0.970264 2011-01-08 0.510564 2011-01-10 -0.362988 dtype: float64 In [22]: ts['1/6/2011':'1/11/2011'] #ts里没有'1/6/2011''1/11/2011'这2个时间戳,但仍然可以使用其作索引,表示范围! Out[22]: 2011-01-07 -0.970264 2011-01-08 0.510564 2011-01-10 -0.362988 dtype: float64
索引为日期范围:范围查询,可以使用不存在的时间戳,以表示范围
In [23]: ts.truncate(after='1/9/2011') Out[23]: 2011-01-02 -0.229374 2011-01-05 0.019728 2011-01-07 -0.970264 2011-01-08 0.510564 dtype: float64
特定函数和参数来切片
2.2 带有重复索引的时间序列
In [28]: dup_ts = Series(np.arange(4), index=pd.DatetimeIndex(['1/1/2000','1/2/2000','1/2/2000','1/3/2000'])) In [29]: dup_ts Out[29]: 2000-01-01 0 2000-01-02 1 2000-01-02 2 2000-01-03 3 dtype: int64 In [30]: dup_ts['1/3/2000'] Out[30]: 3 In [31]: dup_ts['1/2/2000'] #产生切片的效果! Out[31]: 2000-01-02 1 2000-01-02 2 dtype: int64 In [32]: grouped = dup_ts.groupby(level=0) #level=0表示可使把相同的索引聚合在一起 In [33]: grouped.count() Out[33]: 2000-01-01 1 2000-01-02 2 2000-01-03 1 dtype: int64
3 日期的范围、频率以及移动
pandas 中的时间序列一般是不规则的,但它常常需要以某种相对固定的频率进行分析,可以使用 resample().mean 等函数。In [36]: ts.resample('D').mean() Out[36]: 2011-01-02 -0.229374 2011-01-03 NaN 2011-01-04 NaN 2011-01-05 0.019728 2011-01-06 NaN 2011-01-07 -0.970264 2011-01-08 0.510564 2011-01-09 NaN 2011-01-10 -0.362988 2011-01-11 NaN 2011-01-12 -1.215119 Freq: D, dtype: float64
3.1 生成日期范围
使用 pd.date_range 函数In [38]: pd.date_range('4/1/2012', '6/1/2012', freq='5D') #每5天生成一个日期 Out[38]: DatetimeIndex(['2012-04-01', '2012-04-06', '2012-04-11', '2012-04-16', '2012-04-21', '2012-04-26', '2012-05-01', '2012-05-06', '2012-05-11', '2012-05-16', '2012-05-21', '2012-05-26', '2012-05-31'], dtype='datetime64[ns]', freq='5D') In [39]: pd.date_range(start='4/1/2012', periods=20) #默认每1天生成一个日期 Out[39]: DatetimeIndex(['2012-04-01', '2012-04-02', '2012-04-03', '2012-04-04', ... '2012-04-17', '2012-04-18', '2012-04-19', '2012-04-20'], dtype='datetime64[ns]', freq='D') In [40]: pd.date_range(end='6/1/2012', periods=20) Out[40]: DatetimeIndex(['2012-05-13', '2012-05-14', '2012-05-15', '2012-05-16', ... '2012-05-29', '2012-05-30', '2012-05-31', '2012-06-01'], dtype='datetime64[ns]', freq='D')
start:开始日期
end:结束日期
periods:日期范围内日期的个数,periods*freq 等于日期范围的长度
freq:每多少天或其他明确时间频率的方式,默认为D,即1天
normalize:把日期规范化到午夜时间戳,即把时间规范化为 00:00:00
3.2 频率和日期偏移量
pd.date_range 函数里的参数 freq,可以是 4h、2h30min、3d6h 这样的字符串!In [44]: pd.date_range('1/1/2000', periods=10, freq='1d6h20min') Out[44]: DatetimeIndex(['2000-01-01 00:00:00', '2000-01-02 06:20:00', '2000-01-03 12:40:00', '2000-01-04 19:00:00', '2000-01-06 01:20:00', '2000-01-07 07:40:00', '2000-01-08 14:00:00', '2000-01-09 20:20:00', '2000-01-11 02:40:00', '2000-01-12 09:00:00'], dtype='datetime64[ns]', freq='1820T')
日期锚点偏移量代码部分如下,详见书本
D:每日历日
B:每工作日
H:每小时
T或min:每分钟
S:每秒
M:每月最后一个日历日
BM:每月最后一个工作日
MS:每月第一个日历日
BMS:每月第一个工作日
W-MON、W-TUE……:从指定的星期几开始算起,每周
WOM-3FRI:每月第3个星期五
BAS-JAN、BAS-FEB……:每年指定月份的第一个工作日
3.3 移动(超前和滞后)数据
TimeSeries.shift 函数,可以实现对数据或者时间戳的位移In [46]: ts = Series(np.random.randn(4), index=pd.date_range('1/1/2000',periods=4,freq='M')) In [47]: ts Out[47]: 2000-01-31 0.769623 2000-02-29 1.007727 2000-03-31 -0.408647 2000-04-30 1.852691 Freq: M, dtype: float64 In [48]: ts.shift(2) #此时只位移数据,时间戳不变,会产生NaN Out[48]: 2000-01-31 NaN 2000-02-29 NaN 2000-03-31 0.769623 2000-04-30 1.007727 Freq: M, dtype: float64 In [49]: ts.shift(-2) Out[49]: 2000-01-31 -0.408647 2000-02-29 1.852691 2000-03-31 NaN 2000-04-30 NaN Freq: M, dtype: float64 In [52]: ts.shift(periods=3, freq='D') #此时只位移时间戳,数据不变,所以不会产生NaN Out[52]: 2000-02-03 0.769623 2000-03-03 1.007727 2000-04-03 -0.408647 2000-05-03 1.852691 dtype: float64 In [53]: ts.shift(periods=1, freq='3D') Out[53]: 2000-02-03 0.769623 2000-03-03 1.007727 2000-04-03 -0.408647 2000-05-03 1.852691 dtype: float64
指定 freq 时,是对时间戳进行位移,其本质上是对每个时间戳加上 periods*freq 偏移量,只要 periods*freq 相同,结果就一样。
3.3.1 通过偏移量对日期进行位移
pandas 的日期偏移量也可以用在 datetime 或 Timestamp 对象上。In [55]: from pandas.tseries.offsets import Day, MonthEnd In [56]: now = datetime(2011, 11, 17) In [57]: now + 3*Day() #向前偏移3天 Out[57]: Timestamp('2011-11-20 00:00:00') In [58]: now + MonthEnd() #向前偏移到当月月末 Out[58]: Timestamp('2011-11-30 00:00:00') In [59]: now + MonthEnd(2) #向前偏移到下月月末 Out[59]: Timestamp('2011-12-31 00:00:00') In [60]: offset = MonthEnd() In [61]: offset.rollforward(now) #向前偏移到当月月末 Out[61]: Timestamp('2011-11-30 00:00:00') In [62]: offset.rollback(now) #向后偏移到上月月末 Out[62]: Timestamp('2011-10-31 00:00:00')
4 时区处理
待续……4.1 本地化和转换
4.2 操作时区意识型 Timestamp 对象
4.3 不同时区之间的运算
5 时期及其算术运算
In [2]: p = pd.Period(2007, freq='A-DEC') In [3]: p Out[3]: Period('2007', 'A-DEC') In [4]: p+5 Out[4]: Period('2012', 'A-DEC') In [5]: pd.Period('2014', freq='A-DEC')-p Out[5]: 7
period 表示的是时间区间,如数日、数月、数季、数年等。
In [6]: rng = pd.period_range('1/1/2000', '6/30/2000', freq='M') In [7]: rng Out[7]: PeriodIndex(['2000-01', '2000-02', '2000-03', '2000-04', '2000-05', '2000-06'], dtype='int64', freq='M') In [8]: Series(np.random.randn(6), index=rng) Out[8]: 2000-01 -0.416612 2000-02 -0.174900 2000-03 -0.712479 2000-04 -1.538616 2000-05 0.525344 2000-06 -0.553198 Freq: M, dtype: float64
period_range 用于创建规则的时期范围,为 PeriodIndex 类,可以作为 pandas 数据结构的轴索引
In [13]: values = ['200103','200202','200301'] In [14]: pd.PeriodIndex(values, freq='Q-DEC') Out[14]: PeriodIndex(['2003Q1', '2002Q1', '2001Q1'], dtype='int64', freq='Q-DEC')
PeriodIndex 的创造函数可以直接使用日期类型的字符串
5.1 时期的频率转换
Period.asfreq 和 PeriodIndex.asfreq 函数可以进行频率转换,其实本质上更像是对原来时期的扩大或缩小,超时期<-->子时期In [18]: p = pd.Period('2007', freq='A-DEC') In [19]: p.asfreq('M', how='start') Out[19]: Period('2007-01', 'M') In [20]: p.asfreq('M', how='end') Out[20]: Period('2007-12', 'M') In [21]: p = pd.Period('2007', freq='A-JUN') #截至到2007年6月30号的一整年时期区间,即p表示2006年7月1号至2007年6月30号这一年的时期!此时2007年7月-12月其实是属于周期“2008年”的 In [22]: p.asfreq('M', 'start') Out[22]: Period('2006-07', 'M') In [23]: p.asfreq('M', 'end') Out[23]: Period('2007-06', 'M') In [25]: p = pd.Period('2007-08', 'M') #2007年8月这一个月 In [26]: p.asfreq('A-JUN') Out[26]: Period('2008', 'A-JUN') #子时期位于频率后面,所以超时期为截至到2008年6月30号的这一年区间 In [27]: p.asfreq('A-SEP') Out[27]: Period('2007', 'A-SEP') #子时期位于频率前面,所以超时期为截至到2007年9月30号的这一年区间
如上所示,当高频率(每月)转换为低频率(每年)时,看子时期(2007年8月)位于频率指定日期(A-JUN)的前面还是后面
In [28]: rng = pd.period_range('2006', '2009', freq='A-DEC') In [29]: ts = Series(np.random.randn(len(rng)), index=rng) In [30]: ts Out[30]: 2006 0.333219 2007 0.923277 2008 -0.476524 2009 -1.014863 Freq: A-DEC, dtype: float64 In [31]: ts.asfreq('M', how='start') Out[31]: 2006-01 0.333219 2007-01 0.923277 2008-01 -0.476524 2009-01 -1.014863 Freq: M, dtype: float64 In [32]: ts.asfreq('B', how='end') Out[32]: 2006-12-29 0.333219 2007-12-31 0.923277 2008-12-31 -0.476524 2009-12-31 -1.014863 Freq: B, dtype: float64
PeriodIndex 和 TimeSeries 频率转换同样如此。
5.2 按季度计算的时期频率
In [35]: p = pd.Period('2012Q3', freq='Q-JAN') #以1月(JAN)结束的年度(即2011年2月1号至2012年1月31号这一年)的第3季度(即2011年8月1号至2011年10月31号这三个月) In [36]: p Out[36]: Period('2012Q3', 'Q-JAN') In [37]: p.asfreq('D', 'start') Out[37]: Period('2011-08-01', 'D') In [38]: p.asfreq('D', 'end') Out[38]: Period('2011-10-31', 'D') In [42]: p4pm = (p.asfreq('D','end')-1).asfreq('T','start') + 16*60 #获得该季度倒数第2个工作日下午4点的时间戳 In [43]: p4pm Out[43]: Period('2011-10-30 16:00', 'T') In [44]: p4pm.to_timestamp() Out[44]: Timestamp('2011-10-30 16:00:00')
period_range 类型的同样可以如此运算
5.3 将 Timestamp 转换为 Period(及其反向过程)
TimeSeries 的 to_period 和 to_timestamp 方法In [50]: rng = pd.date_range('1/1/2000', periods=3, freq='M') In [51]: ts = Series(np.random.randn(3), index=rng) In [52]: ts Out[52]: 2000-01-31 0.139556 2000-02-29 1.085592 2000-03-31 0.846197 Freq: M, dtype: float64 In [53]: pts = ts.to_period() #没有指定频率,此时为了让新的时期不重叠,新的频率默认从时间戳推断出来 In [54]: pts #为保证时间不重叠,新的频率为月 Out[54]: 2000-01 0.139556 2000-02 1.085592 2000-03 0.846197 Freq: M, dtype: float64 In [55]: pts.to_timestamp(how='end') #重新转换为时间戳,方式是之前时期的最后1天 Out[55]: 2000-01-31 0.139556 2000-02-29 1.085592 2000-03-31 0.846197 Freq: M, dtype: float64 In [56]: rng = pd.date_range('1/29/2000', periods=6, freq='D') In [57]: ts2 = Series(np.random.randn(6), index=rng) In [58]: ts2.to_period('M') #指定频率为月,此时存在重复时期 Out[58]: 2000-01 1.226179 2000-01 -1.177125 2000-01 -0.484311 2000-02 -0.312755 2000-02 0.410706 2000-02 -0.059527 Freq: M, dtype: float64
5.4 通过数组创建 PeriodIndex
利用 pd.PeriodIndex 函数可以把分开的 year 和 quarter 两组数组数据合并一起形成新的轴索引In [59]: index = pd.PeriodIndex(year=data.year, quarter=data.quarter, freq='Q-DEC')
PeriodIndex 里同样可以指定 month, day, hour, minute, second 等参数
6 重采样及频率转换
降采样 downsampling:高频率数据聚合到低频率数据升采样 upsampling:低频率数据转换到高频率数据
pandas对象都带有一个 resample 方法
6.1 降采样
In [11]: ts Out[11]: 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 In [12]: ts.resample('5min', how='sum') #这三个结果一样,closed和label默认都是left,书上写错了!这种默认值使用起来最舒服!最好理解! In [13]: ts.resample('5min', how='sum', closed='left') In [14]: ts.resample('5min', how='sum', closed='left', label='left') Out[14]: 2000-01-01 00:00:00 10 #0-4min的结果,closed='left':原时间戳0min为区间的左边界且闭合,即(0,5)-->[0,5)-->[0,4],label='left':以区间(0,5)的左边界(0min)为标签 2000-01-01 00:05:00 35 #(5,10)-->[5,10)-->[5,9] 2000-01-01 00:10:00 21 Freq: 5T, dtype: int32 In [15]: ts.resample('5min', how='sum', closed='left', label='right') Out[15]: 2000-01-01 00:05:00 10 #0-4min的结果,closed='left':(0,5)-->[0,5)-->[0,4],label='right':以区间(0,5)的右边界(5min)为标签 2000-01-01 00:10:00 35 #(5,10)-->[5,10)-->[5,9] 2000-01-01 00:15:00 21 Freq: 5T, dtype: int32 In [16]: ts.resample('5min', how='sum', closed='right') #这两个结果一样! In [17]: ts.resample('5min', how='sum', closed='right', label='left') Out[17]: 1999-12-31 23:55:00 0 #56-0min的结果,closed='right':原时间戳0min为区间的右边界且闭合,即(55,0)-->(55,0]-->[56,0] 2000-01-01 00:00:00 15 #(0,5)-->(0,5]-->[1,5] 2000-01-01 00:05:00 40 2000-01-01 00:10:00 11 Freq: 5T, dtype: int32 In [18]: ts.resample('5min', how='sum', closed='right', label='right') Out[18]: 2000-01-01 00:00:00 0 #56-0min的结果 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
注意: resample 的参数 closed 和 label 默认的都是 left,书上是错误的!这种默认值使用起来最舒服!最好理解!要么 left+left 搭配,要么 right+right 搭配,其他搭配都不方便理解。BUT!!! 有时候默认值又都是 right,看样子 resample 比较智能,可以用最好理解的方式展示结果!
6.1.1 OHLC 重采样
金融领域一个常用的时间序列聚合方式是求各面元的4个值:第1个值(open,开盘),最后1个值(close,收盘),最大值(hight,最高)和最小值(low,最低),传入how=’ohlc’即可In [19]: ts.resample('5min', how='ohlc') Out[19]: 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
6.1.2 通过 groupby 进行重采样
使用 pandas 的 groupby 功能,可以方便聚合即降采样!In [20]: rng = pd.date_range('1/1/2000', periods=100, freq='D') In [21]: ts = Series(np.arange(100), index=rng) In [22]: ts.groupby(lambda x: x.month).mean() Out[22]: 1 15 2 45 3 75 4 95 dtype: int32 In [23]: ts.resample('M', how='mean', kind='period') #与上面结果类似 Out[23]: 2000-01 15 2000-02 45 2000-03 75 2000-04 95 Freq: M, dtype: int32 In [24]: ts.groupby(lambda x: x.weekday).mean() Out[24]: 0 47.5 1 48.5 2 49.5 3 50.5 4 51.5 5 49.0 6 50.0 dtype: float64
6.2 升采样和插值
In [5]: frame Out[5]: C T N O 2000-01-05 -0.164698 -0.156805 0.613622 -0.046056 2000-01-12 1.146673 2.268121 0.786021 -1.792799 In [7]: frame.resample('D') Out[7]: C T N O 2000-01-05 -0.164698 -0.156805 0.613622 -0.046056 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 1.146673 2.268121 0.786021 -1.792799 In [8]: frame.resample('D', fill_method='ffill', limit=2) Out[8]: C T N O 2000-01-05 -0.164698 -0.156805 0.613622 -0.046056 2000-01-06 -0.164698 -0.156805 0.613622 -0.046056 2000-01-07 -0.164698 -0.156805 0.613622 -0.046056 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 1.146673 2.268121 0.786021 -1.792799
6.3 通过时期进行重采样
In [9]: frame = DataFrame(np.random.randn(24,4), index=pd.period_range('1-2000','12-2001',freq='M'), columns=['C','T','N','O']) In [10]: frame[:5] Out[10]: C T N O 2000-01 -1.160273 1.912955 0.987896 -1.270885 2000-02 -1.094754 -0.914040 -0.262379 -0.840917 2000-03 -0.384724 -1.448646 0.092836 1.249594 2000-04 -0.603648 1.061497 0.751424 0.080474 2000-05 -0.549866 0.334767 1.438030 -0.037338 In [11]: annual_frame = frame.resample('A-DEC', how='mean') In [12]: annual_frame Out[12]: C T N O 2000 -0.581455 0.361708 0.477365 -0.143055 2001 -0.215801 0.001828 0.072425 0.162908 In [14]: annual_frame.resample('Q-DEC', fill_method='ffill') #默认convention是start!而非书上写的end! Out[14]: C T N O 2000Q1 -0.581455 0.361708 0.477365 -0.143055 2000Q2 -0.581455 0.361708 0.477365 -0.143055 2000Q3 -0.581455 0.361708 0.477365 -0.143055 2000Q4 -0.581455 0.361708 0.477365 -0.143055 2001Q1 -0.215801 0.001828 0.072425 0.162908 2001Q2 -0.215801 0.001828 0.072425 0.162908 2001Q3 -0.215801 0.001828 0.072425 0.162908 2001Q4 -0.215801 0.001828 0.072425 0.162908 In [16]: annual_frame.resample('Q-DEC', fill_method='ffill', convention='end') Out[16]: C T N O 2000Q4 -0.581455 0.361708 0.477365 -0.143055 2001Q1 -0.581455 0.361708 0.477365 -0.143055 2001Q2 -0.581455 0.361708 0.477365 -0.143055 2001Q3 -0.581455 0.361708 0.477365 -0.143055 2001Q4 -0.215801 0.001828 0.072425 0.162908
7 时间序列绘图
In [20]: close_px Out[20]: AAPL MSFT XOM 2003-01-02 7.40 21.11 29.22 2003-01-03 7.45 21.14 29.24 2003-01-06 7.45 21.52 29.96 …… 2011-10-12 402.19 26.96 77.16 2011-10-13 408.43 27.18 76.37 2011-10-14 422.00 27.27 78.11 [2292 rows x 3 columns] In [21]: close_px.plot()
如上所示,所有时间序列都会被绘制在同一个 subplot 上并用一个图例来说明哪个是哪个。
In [25]: close_px['AAPL'].ix['01-2011':'03-2011'].plot()
In [27]: close_px['AAPL'].resample('Q-DEC', fill_method='ffill').ix['2009':].plot()
8 移动窗口函数
In [13]: close_px.AAPL.plot() In [14]: pd.rolling_mean(close_px.AAPL, 250).plot()
In [17]: pd.rolling_mean(close_px, 60).plot()
8.1 指数加权函数
下面是苹果公司股份的60日移动平均和 span=60 的指数加权移动平均的对比。In [25]: fig, axes = plt.subplots(nrows=2, ncols=1, sharex=True, sharey=True, figsize=(12,7)) In [26]: aapl_px = close_px.AAPL['2005':'2009'] In [27]: ma60 = pd.rolling_mean(aapl_px, 60, min_periods=50) In [28]: ewma60 = pd.ewma(aapl_px, span=60) In [29]: aapl_px.plot(style='k-', ax=axes[0]) In [30]: ma60.plot(style='k--', ax=axes[0]) In [31]: aapl_px.plot(style='k-', ax=axes[1]) In [32]: ewma60.plot(style='k--', ax=axes[1]) In [33]: axes[0].set_title('Simple MA') In [34]: axes[1].set_title('Exponentially-weighted MA')
8.2 二元移动窗口函数
有些统计运算(如相关系数和协方差)需要在两个时间序列上执行。下面是金融分析师对某只股票对某个参数指数的相关系数感兴趣从而做的分析。In [35]: spx_px = close_px_all['SPX'] In [36]: spx_rets = spx_px/spx_px.shift(1)-1 In [37]: returns = close_px.pct_change() In [38]: corrs = pd.rolling_corr(returns, spx_rets, 125, min_periods=100) In [39]: corrs.plot()
8.3 用户定义的移动窗口函数
rolling_apply 函数能够在移动窗口上应用自己设计的数组函数,唯一的要求是该函数要能从数组的各个片段中产生单个值。下面是使用 scipy.stats.percentitleofscore 函数来用 rolling_quantitle 计算样本中特定值的百分等级。In [43]: from scipy.stats import percentileofscore In [44]: score_at_2percent = lambda x: percentileofscore(x, 0.02) In [45]: result = pd.rolling_apply(returns.AAPL, 250, score_at_2percent) In [46]: result.plot()
9 性能和内存使用方面的注意事项
省略相关文章推荐
- Python动态类型的学习---引用的理解
- Python3写爬虫(四)多线程实现数据爬取
- 垃圾邮件过滤器 python简单实现
- 下载并遍历 names.txt 文件,输出长度最长的回文人名。
- install and upgrade scrapy
- Scrapy的架构介绍
- Centos6 编译安装Python
- 使用Python生成Excel格式的图片
- 让Python文件也可以当bat文件运行
- [Python]推算数独
- Python中zip()函数用法举例
- Python中map()函数浅析
- Python将excel导入到mysql中
- Python在CAM软件Genesis2000中的应用
- 使用Shiboken为C++和Qt库创建Python绑定
- FREEBASIC 编译可被python调用的dll函数示例
- Python 七步捉虫法