一、Pandas时刻数据
时刻数据代表时间点,是pandas的数据类型,是将值与时间点相关联的最基本类型的时间序列数据
1.pd.Timestamp
date1 = datetime.datetime(2016,12,1,12,45,30) # 创建一个datetime.datetime date2 = '2017-12-21' # 创建一个字符串 t1 = pd.Timestamp(date1) t2 = pd.Timestamp(date2) print(t1,type(t1)) print(t2) # 直接生成pandas的时刻数据 → 时间戳 # 数据类型为 pandas的Timestamp print(pd.Timestamp('2017-12-21 15:00:22'))
2.pd.to_datetime
date1 = datetime.datetime(2016,12,1,12,45,30) date2 = '2017-12-21' # pd.to_datetime():如果是单个时间数据,转换成pandas的时刻数据,数据类型为Timestamp t1 = pd.to_datetime(date1) t2 = pd.to_datetime(date2) print(t1,type(t1),'\n') print(t2,type(t2),'\n') # 多个时间数据,将会转换为pandas的DatetimeIndex lst_date = [ '2017-12-21', '2017-12-22', '2017-12-23'] t3 = pd.to_datetime(lst_date) print(t3,type(t3))
3.pd.to_datetime(多时间数据转换)
# pd.to_datetime → 多个时间数据转换时间戳索引 from datetime import datetime # 多个时间数据转换为 DatetimeIndex date1 = [datetime(2015,6,1),datetime(2015,7,1),datetime(2015,8,1),datetime(2015,9,1),datetime(2015,10,1)] date2 = ['2017-2-1','2017-2-2','2017-2-3','2017-2-4','2017-2-5','2017-2-6'] print(date1) print(date2,'\n') t1 = pd.to_datetime(date2) t2 = pd.to_datetime(date2) print(t1) print(t2,'\n') # 当一组时间序列中夹杂其他格式数据,可用errors参数返回 # errors = 'ignore':不可解析时返回原始输入,这里就是直接生成一般数组 date3 = ['2017-2-1','2017-2-2','2017-2-3','hello world!','2017-2-5','2017-2-6'] t3 = pd.to_datetime(date3, errors = 'ignore') print(t3,type(t3),'\n') # errors = 'coerce':不可扩展,缺失值返回NaT(Not a Time),结果认为DatetimeIndex t4 = pd.to_datetime(date3, errors = 'coerce') print(t4,type(t4))
二、Pandas时间戳索引
1.时间序列
rng = pd.DatetimeIndex(['12/1/2017','12/2/2017','12/3/2017','12/4/2017','12/5/2017']) # 直接生成时间戳索引,支持str、datetime.datetime # 单个时间戳为Timestamp,多个时间戳为DatetimeIndex print(rng,type(rng)) print(rng[0],type(rng[0]),'\n') # 以DatetimeIndex为index的Series,为TimeSries,时间序列 st = pd.Series(np.random.rand(len(rng)), index = rng) print(st,type(st)) print(st.index)
2.时间范围
# normalize:时间参数值正则化到午夜时间戳(这里最后就直接变成0:00:00,并不是15:30:00) # name:索引对象名称 rng4 = pd.date_range(start = '1/1/2017 15:30', periods = 10, name = 'hello world!', normalize = True) print(rng4) print('='*50) # closed:默认为None的情况下,左闭右闭,left则左闭右开,right则左开右闭 print(pd.date_range('20170101','20170104')) # 20170101也可读取 print(pd.date_range('20170101','20170104',inclusive='right')) print(pd.date_range('20170101','20170104',inclusive='left')) print('='*50) # pd.bdate_range()默认频率为工作日 print(pd.bdate_range('20170101','20170107'),'\n') # 直接转化为list,元素为Timestamp print(list(pd.date_range(start = '1/1/2017', periods = 10)))
3.时间周期
# pd.date_range()-日期范围:频率(1) print(pd.date_range('2017/1/1','2017/1/4')) # 默认freq = 'D':每日历日 print(pd.date_range('2017/1/1','2017/1/4', freq = 'B')) # B:每工作日 print(pd.date_range('2017/1/1','2017/1/2', freq = 'H')) # H:每小时 print(pd.date_range('2017/1/1 12:00','2017/1/1 12:10', freq = 'T')) # T/MIN:每分 print(pd.date_range('2017/1/1 12:00:00','2017/1/1 12:00:10', freq = 'S')) # S:每秒 print(pd.date_range('2017/1/1 12:00:00','2017/1/1 12:00:10', freq = 'L')) # L:每毫秒(千分之一秒) print(pd.date_range('2017/1/1 12:00:00','2017/1/1 12:00:10', freq = 'U')) # U:每微秒(百万分之一秒) # W-MON:从指定星期几开始算起,每周 # 星期几缩写:MON/TUE/WED/THU/FRI/SAT/SUN print(pd.date_range('2017/1/1','2017/2/1', freq = 'W-MON')) # WOM-2MON:每月的第几个星期几开始算,这里是每月第二个星期一 print(pd.date_range('2017/1/1','2017/5/1', freq = 'WOM-2MON')) # pd.bdate_range()默认频率为工作日 print(pd.bdate_range('20170101','20170107'),'\n') # 直接转化为list,元素为Timestamp print(list(pd.date_range(start = '1/1/2017', periods = 10)))
4.时间周期2
# pd.date_range()-日期范围:频率(2) # M:每月最后一个日历日 # Q-月:指定月为季度末,每个季度末最后一月的最后一个日历日 # A-月:每年指定月份的最后一个日历日 # 月缩写:JAN/FEB/MAR/APR/MAY/JUN/JUL/AUG/SEP/OCT/NOV/DEC # 所以Q-月只有三种情况:1-4-7-10,2-5-8-11,3-6-9-12 print(pd.date_range('2017','2018', freq = 'M')) print(pd.date_range('2017','2020', freq = 'Q-DEC')) print(pd.date_range('2017','2020', freq = 'A-DEC')) print('='*70,'\n') # BM:每月最后一个工作日 # BQ-月:指定月为季度末,每个季度末最后一月的最后一个工作日 # BA-月:每年指定月份的最后一个工作日 print(pd.date_range('2017','2018', freq = 'BM')) print(pd.date_range('2017','2020', freq = 'BQ-DEC')) print(pd.date_range('2017','2020', freq = 'BA-DEC')) print('='*70,'\n') # M:每月第一个日历日 # Q-月:指定月为季度末,每个季度末最后一月的第一个日历日 # A-月:每年指定月份的第一个日历日 print(pd.date_range('2017','2018', freq = 'MS')) print(pd.date_range('2017','2020', freq = 'QS-DEC')) print(pd.date_range('2017','2020', freq = 'AS-DEC')) print('='*70,'\n') # BM:每月第一个工作日 # BQ-月:指定月为季度末,每个季度末最后一月的第一个工作日 # BA-月:每年指定月份的第一个工作日 print(pd.date_range('2017','2018', freq = 'BMS')) print(pd.date_range('2017','2020', freq = 'BQS-DEC')) print(pd.date_range('2017','2020', freq = 'BAS-DEC'))
5.复合周期
# pd.date_range()-日期范围:复合频率 print(pd.date_range('2017/1/1','2017/2/1', freq = '7D')) # 7天 print(pd.date_range('2017/1/1','2017/1/2', freq = '2h30min')) # 2小时30分钟 print(pd.date_range('2017','2018', freq = '2M')) # 2月,每月最后一个日历日
6.日期范围
# pd.date_range()-日期范围:超前/滞后数据 ts = pd.Series(np.random.rand(4), index = pd.date_range('20170101','20170104')) print(ts,'\n') # 正数:数值后移(滞后);负数:数值前移(超前) print(ts.shift(2)) print(ts.shift(-2)) print('='*60) # 计算变化百分比,这里计算:该时间戳与上一个时间戳相比,变化百分比 per = ts/ts.shift(1) - 1 print(per) print('='*60) # 加上freq参数:对时间戳进行位移,而不是对数值进行位移 print(ts.shift(2, freq = 'D')) print(ts.shift(2, freq = 'T'))
二、Pandas时期
1.创建日期
# pd.Period()创建时期 # 生成一个以2017-01开始,月为频率的时间构造器 # pd.Period()参数:一个时间戳 + freq 参数 → freq 用于指明该 period 的长度,时间戳则说明该 period 在时间轴上的位置 p = pd.Period('2017', freq = 'M') print(p, type(p)) # 通过加减整数,将周期整体移动 # 这里是按照 月、年 移动 print(p + 1) print(p - 2) print(pd.Period('2012', freq = 'A-DEC') - 1)
2.创建日期范围
# pd.period_range()创建时期范围 # 数据格式为PeriodIndex,单个数值为Period prng = pd.period_range('1/1/2011', '1/1/2012', freq='M') print(prng,type(prng)) print(prng[0],type(prng[0])) print('='*60) # 时间序列 ts = pd.Series(np.random.rand(len(prng)), index = prng) print(ts,type(ts)) print(ts.index) # Period('2011', freq = 'A-DEC')可以看成多个时间期的时间段中的游标 # Timestamp表示一个时间戳,是一个时间截面;Period是一个时期,是一个时间段!!但两者作为index时区别不大
3.周期转换
# 通过.asfreq(freq, method=None, how=None)方法转换成别的频率 p = pd.Period('2017','A-DEC') print(p) print(p.asfreq('M', how = 'start')) # 也可写 how = 's' print(p.asfreq('D', how = 'end')) # 也可写 how = 'e' print('='*60,'\n') # asfreq也可以转换TIMESeries的index prng = pd.period_range('2017','2018',freq = 'M') ts1 = pd.Series(np.random.rand(len(prng)), index = prng) ts2 = pd.Series(np.random.rand(len(prng)), index = prng.asfreq('D', how = 'start')) print(ts1.head(),len(ts1)) print(ts2.head(),len(ts2))
4.时间戳与时期周期的转换
# 时间戳与时期之间的转换:pd.to_period()、pd.to_timestamp() rng = pd.date_range('2017/1/1', periods = 10, freq = 'M') prng = pd.period_range('2017','2018', freq = 'M') # 每月最后一日,转化为每月 ts1 = pd.Series(np.random.rand(len(rng)), index = rng) print(ts1.head()) print(ts1.to_period().head()) print('='*60,'\n') # 每月,转化为每月第一天 ts2 = pd.Series(np.random.rand(len(prng)), index = prng) print(ts2.head()) print(ts2.to_timestamp().head())
三、时间序列
1.索引
from datetime import datetime rng = pd.date_range('2017/1','2017/3') ts = pd.Series(np.random.rand(len(rng)), index = rng) print(ts.head()) # print(ts[0]) print(ts[:2]) print('-----') # 时间序列由于按照时间先后排序,故不用考虑顺序问题 # 索引方法同样适用于Dataframe # 基本下标位置索引 print('='*60,'\n') print(ts['2017/1/2']) print(ts['20170103']) print(ts['1/10/2017']) print(ts[datetime(2017,1,20)])
2.切片
# 切片 rng = pd.date_range('2017/1','2017/3',freq = '12H') ts = pd.Series(np.random.rand(len(rng)), index = rng) # 和Series按照index索引原理一样,也是末端包含 print(ts['2017/1/5':'2017/1/10']) print('-----') # 传入月,直接得到一个切片 print(ts['2017/2'].head())
3.重复索引的时间序列
# 重复索引的时间序列 # index有重复,is_unique检查 → values唯一,index不唯一 dates = pd.DatetimeIndex(['1/1/2015','1/2/2015','1/3/2015','1/4/2015','1/1/2015','1/2/2015']) ts = pd.Series(np.random.rand(6), index = dates) print(ts) print(ts.is_unique,ts.index.is_unique) print('='*60,'\n') #index有重复的将返回多个值 print(ts['20150101'],type(ts['20150101'])) print(ts['20150104'],type(ts['20150104'])) print('='*60,'\n') # 通过groupby做分组,重复的值这里用平均值处理 print(ts.groupby(level = 0).mean())
四、时间采样
将时间序列从一个频率转换为另一个频率的过程,且会有数据的结合
降采样:高频数据 → 低频数据,eg.以天为频率的数据转为以月为频率的数据
升采样:低频数据 → 高频数据,eg.以年为频率的数据转为以月为频率的数据
1.重采样
# 重采样:.resample() # 创建一个以天为频率的TimeSeries,重采样为按2天为频率 rng = pd.date_range('20170101', periods = 12) ts = pd.Series(np.arange(12), index = rng) print(ts) print('='*60,'\n') # ts.resample('5D'):得到一个重采样构建器,频率改为5天 # ts.resample('5D').sum():得到一个新的聚合后的Series,聚合方式为求和 # freq:重采样频率 → ts.resample('5D') # .sum():聚合方法 ts_re = ts.resample('5D') ts_re2 = ts.resample('5D').sum() print(ts_re, type(ts_re)) print(ts_re2, type(ts_re2)) print('='*60,'\n') # OHLC:金融领域的时间序列聚合方式 → open开盘、high最大值、low最小值、close收盘 print(ts.resample('5D').mean(),'→ 求平均值\n') print(ts.resample('5D').max(),'→ 求最大值\n') print(ts.resample('5D').min(),'→ 求最小值\n') print(ts.resample('5D').median(),'→ 求中值\n') print(ts.resample('5D').first(),'→ 返回第一个值\n') print(ts.resample('5D').last(),'→ 返回最后一个值\n') print(ts.resample('5D').ohlc(),'→ OHLC重采样\n')
2.降采样
# 降采样 rng = pd.date_range('20170101', periods = 12) ts = pd.Series(np.arange(1,13), index = rng) print(ts,'\n') # closed:各时间段哪一端是闭合(即包含)的,默认 左闭右闭 # 详解:这里values为0-11,按照5D重采样 → [1,2,3,4,5],[6,7,8,9,10],[11,12] # left指定间隔左边为结束 → [1,2,3,4,5],[6,7,8,9,10],[11,12] # right指定间隔右边为结束 → [1],[2,3,4,5,6],[7,8,9,10,11],[12] print(ts.resample('5D').sum(),'→ 默认\n') print(ts.resample('5D', closed = 'left').sum(),'→ left\n') print(ts.resample('5D', closed = 'right').sum(),'→ right\n') print('='*60,'\n') # label:聚合值的index,默认为取左 # 值采样认为默认(这里closed默认) print(ts.resample('5D', label = 'left').sum(),'→ leftlabel\n') print(ts.resample('5D', label = 'right').sum(),'→ rightlabel\n')
3.升采样及插值
# 升采样及插值 rng = pd.date_range('2017/1/1 0:0:0', periods = 5, freq = 'H') ts = pd.DataFrame(np.arange(15).reshape(5,3), index = rng, columns = ['a','b','c']) print(ts,'\n') # 低频转高频,主要是如何插值 # .asfreq():不做填充,返回Nan # .ffill():向上填充 # .bfill():向下填充 print(ts.resample('15T').asfreq()) print(ts.resample('15T').ffill()) print(ts.resample('15T').bfill())
4.周期重采样
prng = pd.period_range('2016','2017',freq = 'M') ts = pd.Series(np.arange(len(prng)), index = prng) print(ts) print(ts.resample('3M').sum()) # 降采样 print(ts.resample('15D').ffill()) # 升采样