数据分析三剑客之Pandas时间序列

Posted lee-xingxing

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据分析三剑客之Pandas时间序列相关的知识,希望对你有一定的参考价值。

一、时间模块:datetime

datetime模块,主要掌握:datetime.date(), datetime.datetime(), datetime.timedelta(),日期解析方法:parser.parse

1.datetime.date:date对象

import datetime  # 也可以写 from datetime import date

today = datetime.date.today()
print(today,type(today))
print(str(today),type(str(today)))
# datetime.date.today 返回今日
# 输出格式为 date类

t = datetime.date(2016,6,1)
print(t)
# (年,月,日) → 直接得到当时日期

2.datetime.datetime:datetime对象

now = datetime.datetime.now()
print(now,type(now))
print(str(now),type(str(now))) 
# .now()方法,输出当前时间
# 输出格式为 datetime类
# 可通过str()转化为字符串

t1 = datetime.datetime(2016,6,1)
t2 = datetime.datetime(2014,1,1,12,44,33)
print(t1,t2)
# (年,月,日,时,分,秒),至少输入年月日

t2-t1
# 相减得到时间差 —— timedelta

3.datetime.timedelta:时间差

today = datetime.datetime.today()  # datetime.datetime也有today()方法
yestoday = today - datetime.timedelta(1)  # 
print(today)
print(yestoday)
print(today - datetime.timedelta(7))
# 时间差主要用作时间的加减法,相当于可被识别的时间“差值”

4.parser.parse:日期字符串转换

from dateutil.parser import parse

date = 12-21-2017
t = parse(date)
print(t,type(t))
# 直接将str转化成datetime.datetime

print(parse(2000-1-1),
,
     parse(5/1/2014),
,
     parse(5/1/2014, dayfirst = True),
,  # 国际通用格式中,日在月之前,可以通过dayfirst来设置
     parse(22/1/2014),
,
     parse(Jan 31, 1997 10:45 PM))
# 各种格式可以解析,但无法支持中文

二、Pandas时刻数据:Timestamp

时刻数据代表时间点,是pandas的数据类型,是将值与时间点相关联的最基本类型的时间序列数据:pandas.Timestamp()

1.pd.Timestamp()

import numpy as np
import pandas as pd

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)
print(pd.Timestamp(2017-12-21 15:00:22))
# 直接生成pandas的时刻数据 → 时间戳
# 数据类型为 pandas的Timestamp

2.pd.to_datetime

from datetime import datetime

date1 = datetime(2016,12,1,12,45,30)
date2 = 2017-12-21
t1 = pd.to_datetime(date1)
t2 = pd.to_datetime(date2)
print(t1,type(t1))
print(t2,type(t2))
# pd.to_datetime():如果是单个时间数据,转换成pandas的时刻数据,数据类型为Timestamp

lst_date = [ 2017-12-21, 2017-12-22, 2017-12-23]
t3 = pd.to_datetime(lst_date)
print(t3,type(t3))
# 多个时间数据,将会转换为pandas的DatetimeIndex

3.pd.to_datetime → 多个时间数据转换时间戳索引

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)
t1 = pd.to_datetime(date2)
t2 = pd.to_datetime(date2)
print(t1)
print(t2)
# 多个时间数据转换为 DatetimeIndex

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))
# 当一组时间序列中夹杂其他格式数据,可用errors参数返回
# errors = ‘ignore‘:不可解析时返回原始输入,这里就是直接生成一般数组

t4 = pd.to_datetime(date3, errors = coerce)
print(t4,type(t4))
# errors = ‘coerce‘:不可扩展,缺失值返回NaT(Not a Time),结果认为DatetimeIndex

三、Pandas时间戳索引:DatetimeIndex

核心:pd.date_range()

1.pd.DatetimeIndex()与TimeSeries时间序列

rng = pd.DatetimeIndex([12/1/2017,12/2/2017,12/3/2017,12/4/2017,12/5/2017])
print(rng,type(rng))
print(rng[0],type(rng[0]))
# 直接生成时间戳索引,支持str、datetime.datetime
# 单个时间戳为Timestamp,多个时间戳为DatetimeIndex

st = pd.Series(np.random.rand(len(rng)), index = rng)
print(st,type(st))
print(st.index)
# 以DatetimeIndex为index的Series,为TimeSries,时间序列

2.pd.date_range()-日期范围:生成日期范围

# 2种生成方式:①start + end; ②start/end + periods
# 默认频率:day

rng1 = pd.date_range(1/1/2017,1/10/2017, normalize=True)
rng2 = pd.date_range(start = 1/1/2017, periods = 10)
rng3 = pd.date_range(end = 1/30/2017 15:00:00, periods = 10)  # 增加了时、分、秒
print(rng1,type(rng1))
print(rng2)
print(rng3)
print(-------)
# 直接生成DatetimeIndex
# pd.date_range(start=None, end=None, periods=None, freq=‘D‘, tz=None, normalize=False, name=None, closed=None, **kwargs)
# start:开始时间
# end:结束时间
# periods:偏移量
# freq:频率,默认天,pd.date_range()默认频率为日历日,pd.bdate_range()默认频率为工作日
# tz:时区

rng4 = pd.date_range(start = 1/1/2017 15:30, periods = 10, name = hello world!, normalize = True)
print(rng4)
print(-------)
# normalize:时间参数值正则化到午夜时间戳(这里最后就直接变成0:00:00,并不是15:30:00)
# name:索引对象名称

print(pd.date_range(20170101,20170104))  # 20170101也可读取
print(pd.date_range(20170101,20170104,closed = right))
print(pd.date_range(20170101,20170104,closed = left))
print(-------)
# closed:默认为None的情况下,左闭右闭,left则左闭右开,right则左开右闭

print(pd.bdate_range(20170101,20170107))
# pd.bdate_range()默认频率为工作日

print(list(pd.date_range(start = 1/1/2017, periods = 10)))
# 直接转化为list,元素为Timestamp

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:每微秒(百万分之一秒)

print(pd.date_range(2017/1/1,2017/2/1, freq = W-MON))  
# W-MON:从指定星期几开始算起,每周
# 星期几缩写:MON/TUE/WED/THU/FRI/SAT/SUN

print(pd.date_range(2017/1/1,2017/5/1, freq = WOM-2MON))  
# WOM-2MON:每月的第几个星期几开始算,这里是每月第二个星期一

4.pd.date_range()-日期范围:频率(2)

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(------)
# 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 = BM))  
print(pd.date_range(2017,2020, freq = BQ-DEC))  
print(pd.date_range(2017,2020, freq = BA-DEC)) 
print(------)
# BM:每月最后一个工作日
# BQ-月:指定月为季度末,每个季度末最后一月的最后一个工作日
# BA-月:每年指定月份的最后一个工作日

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(------)
# M:每月第一个日历日
# Q-月:指定月为季度末,每个季度末最后一月的第一个日历日
# A-月:每年指定月份的第一个日历日

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)) 
print(------)
# BM:每月第一个工作日
# BQ-月:指定月为季度末,每个季度末最后一月的第一个工作日
# BA-月:每年指定月份的第一个工作日

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.asfreq:时期频率转换

ts = pd.Series(np.random.rand(4),
              index = pd.date_range(20170101,20170104))
print(ts)
print(ts.asfreq(4H,method = ffill))
# 改变频率,这里是D改为4H
# method:插值模式,None不插值,ffill用之前值填充,bfill用之后值填充

7.pd.date_range()-日期范围:超前/滞后数据

ts = pd.Series(np.random.rand(4),
              index = pd.date_range(20170101,20170104))
print(ts)

print(ts.shift(2))
print(ts.shift(-2))
print(------)
# 正数:数值后移(滞后);负数:数值前移(超前)

per = ts/ts.shift(1) - 1
print(per)
print(------)
# 计算变化百分比,这里计算:该时间戳与上一个时间戳相比,变化百分比

print(ts.shift(2, freq = D))
print(ts.shift(2, freq = T))
# 加上freq参数:对时间戳进行位移,而不是对数值进行位移

四、Pandas时期:Period

核心:pd.Period()

1.pd.Period()创建时期

p = pd.Period(2017, freq = M)
print(p, type(p))
# 生成一个以2017-01开始,月为频率的时间构造器
# pd.Period()参数:一个时间戳 + freq 参数 → freq 用于指明该 period 的长度,时间戳则说明该 period 在时间轴上的位置

print(p + 1)
print(p - 2)
print(pd.Period(2012, freq = A-DEC) - 1)
# 通过加减整数,将周期整体移动
# 这里是按照 月、年 移动

2.pd.period_range()创建时期范围

prng = pd.period_range(1/1/2011, 1/1/2012, freq=M)
print(prng,type(prng))
print(prng[0],type(prng[0]))
# 数据格式为PeriodIndex,单个数值为Period

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:频率转换

p = pd.Period(2017,A-DEC)
print(p)
print(p.asfreq(M, how = start))  # 也可写 how = ‘s‘
print(p.asfreq(D, how = end))  # 也可写 how = ‘e‘
# 通过.asfreq(freq, method=None, how=None)方法转换成别的频率

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))
# asfreq也可以转换TIMESeries的index

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())
# 每月最后一日,转化为每月

ts2 = pd.Series(np.random.rand(len(prng)), index = prng)
print(ts2.head())
print(ts2.to_timestamp().head())
# 每月,转化为每月第一天

五、时间序列 - 索引及切片

TimeSeries是Series的一个子类,所以Series索引及数据选取方面的方法基本一样

同时TimeSeries通过时间序列有更便捷的方法做索引和切片

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(-----)
# 基本下标位置索引

print(ts[2017/1/2])
print(ts[20170103])
print(ts[1/10/2017])
print(ts[datetime(2017,1,20)])
print(-----)
# 时间序列标签索引,支持各种时间字符串,以及datetime.datetime

# 时间序列由于按照时间先后排序,故不用考虑顺序问题
# 索引方法同样适用于Dataframe

2.切片

rng = pd.date_range(2017/1,2017/3,freq = 12H)
ts = pd.Series(np.random.rand(len(rng)), index = rng)

print(ts[2017/1/5:2017/1/10])
print(-----)
# 和Series按照index索引原理一样,也是末端包含

print(ts[2017/2].head())
# 传入月,直接得到一个切片

3.重复索引的时间序列

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(-----)
# index有重复,is_unique检查 → values唯一,index不唯一

print(ts[20150101],type(ts[20150101]))
print(ts[20150104],type(ts[20150104]))
print(-----)
# index有重复的将返回多个值

print(ts.groupby(level = 0).mean())
# 通过groupby做分组,重复的值这里用平均值处理

六、时间序列 - 重采样

将时间序列从一个频率转换为另一个频率的过程,且会有数据的结合

降采样:高频数据 → 低频数据,eg.以天为频率的数据转为以月为频率的数据
升采样:低频数据 → 高频数据,eg.以年为频率的数据转为以月为频率的数据

1.

 

以上是关于数据分析三剑客之Pandas时间序列的主要内容,如果未能解决你的问题,请参考以下文章

数据分析三剑客之pandas

数据分析三剑客之pandas

Python之Pandas学习

Pandas系列教程:盛大开篇了!

Pandas系列教程:盛大开篇了!

Python知识点复习之科研休闲篇