datetime 里面有 datetime, time 以及 calendar 模块,其中 datetime 用得最多
datetime 模块中的数据类型:
date:以公历形式存储日历日期(年、月、日)
time:将时间存储为时、分、秒、毫秒
datetime:存储日期和时间,相当于 date 与 time 的结合
timedelta:两个 datetime 值的差(天数+毫秒数)
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:把标准格式的日期转化为字符串
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:也不需要指定格式
%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
pandas 里 TimeSeries 是索引为 DatetimeIndex 的 DataFrame,索引各标量值是 Timestamp 对象,只要有需要,Timestamp 可以随时自动转换为 datetime 对象。
索引、切片可以传入的参数有字符串日期、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
特定函数和参数来切片
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
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
使用 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
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……:每年指定月份的第一个工作日
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 相同,结果就一样。
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')
待续……
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 的创造函数可以直接使用日期类型的字符串
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 频率转换同样如此。
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 类型的同样可以如此运算
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
利用 pd.PeriodIndex 函数可以把分开的 year 和 quarter 两组数组数据合并一起形成新的轴索引
In [59]: index = pd.PeriodIndex(year=data.year, quarter=data.quarter, freq='Q-DEC')
PeriodIndex 里同样可以指定 month, day, hour, minute, second 等参数
降采样 downsampling:高频率数据聚合到低频率数据
升采样 upsampling:低频率数据转换到高频率数据
pandas对象都带有一个 resample 方法
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 比较智能,可以用最好理解的方式展示结果!
金融领域一个常用的时间序列聚合方式是求各面元的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
使用 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
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
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
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()
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()
下面是苹果公司股份的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')
有些统计运算(如相关系数和协方差)需要在两个时间序列上执行。下面是金融分析师对某只股票对某个参数指数的相关系数感兴趣从而做的分析。
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()
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()
省略