序言:
今天不截图,尝试下纯代码编辑效果会不会看起来舒服一些
【课程2.7】 时间模块:datetime
datetime模块,主要掌握:datetime.date(), datetime.datetime(), datetime.timedelta()
日期解析方法:parser.parse
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)
# (年,月,日) -> 直接得到当时日期
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
parser.parse:日期字符串转换
from dateutil.parser import parse
date = "13-03-2018"
t = parse(date)
print(t, type(t))
# 直接将str转化成datetime.datetime
print(parse("2000-1-1"), "\n",
parse("5/1/2014"), "\n",
parse("5/1/2014", dayfirst = True), "\n", # 国际通用格式中,月/日/年,可以通过dayfirst来设置
parse("22/1/2014"), "\n",
parse("Jan 31, 1997 10:45 PM"))
# 各种格式可以解析,但无法支持中文
【课程2.8】 Pandas时刻数据:Timestamp
时刻数据代表时间点,是pandas的数据类型,是将值与时间点相关联的最基本类型的时间序列数据
pandas.Timestamp()
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, type(t2))
print(pd.Timestamp("2017-12-21 15:00:22"))
# 直接生成pandas的时刻数据 -> 时间戳
# 数据类型为 pandas的Timestamp
pd.to_datetime
from datetime import datetime
date1 = datetime(2016,12,1,12,45,30)
date2 = "2018-03-14"
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
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 = ['2018-2-1','2018-2-2','2018-2-3','2018-2-4','2018-2-5','2018-2-6']
print(date1)
print(date2)
t1 = pd.to_datetime(date1)
t2 = pd.to_datetime(date2)
print(t1)
print(t2)
# 多个时间数据转换为 DatetimeIndex
date3 = ['2018-2-1','2018-2-2','2018-2-3', 'hello world!', '2018-2-4','2018-2-5','2018-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
【课程2.9】 Pandas时间戳索引:DatetimeIndex
核心:pd.date_range()
pd.DatetimeIndex()与TimeSeries时间序列
rng = pd.DatetimeIndex(['2018-2-1','2018-2-2','2018-2-3', '2018-2-4', "2018-2-5"])
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,为TimeSeries,时间序列
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
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", "2017/1/1 12:00:10", freq = "S")) # S:每秒
print(pd.date_range("2017/1/1 12:00", "2017/1/1 12:00:10", freq = "L")) # L:每毫秒(千分之一秒)
print(pd.date_range("2017/1/1 12:00", "2017/1/1 12:00:10", freq = "U")) # L:每微秒(百万分之一秒)
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:每月的第几个星期几开始算,这里是每月第二个星期一
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-月:每年指定月份的第一个工作日
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月,每月最后一个日历日
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用之后值填充
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))
# 正数:数值后移(滞后);负数:数值前移(超前)
per = ts/ts.shift(1) - 1
print(per)
print("------------")
# 计算变化百分比,这里计算:该时间戳与上一个时间戳相比,变化百分
print(ts.shift(2, freq = "D"))
print(ts.shift(2, freq = "T"))
# 加上freq参数:对时间戳进行位移,而不是对数值进行位移
【课程2.10】 Pandas时期:Period
核心:pd.Period()
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)
# 通过加减整数,将周期整体移动
# 这里按照 月、年 移动
# Period('2012', freq = 'A-DEC')可以看成多个时间期的时间段中的游标
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)
# 时间序列
# Timestamp表示一个时间戳,是一个时间截面;Period是一个时期,是一个时间段!!但两者作为index时区别不大
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
时间戳与时期之间的转换: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())
# 每月,转化为每月第一天
【课程2.11】 时间序列 - 索引及切片
TimeSeries是Series的一个子类,所以Series索引及数据选取方面的方法基本一样
同时TimeSeries通过时间序列有更便捷的方法做索引和切片
索引
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
切片
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())
# 传入月,直接得到一个切片
重复索引的时间序列
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(len(dates)), 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做分组,重复的值这里用平均值处理
【课程2.12】 时间序列 - 重采样
将时间序列从一个频率转换为另一个频率的过程,且会有数据的结合
降采样:高频数据 → 低频数据,eg.以天为频率的数据转为以月为频率的数据
升采样:低频数据 → 高频数据,eg.以年为频率的数据转为以月为频率的数据
重采样:.resample()
创建一个以天为频率的TimeSeries,重采样为按2天为频率
rng = pd.date_range("20170101", periods = 12)
ts = pd.Series(np.arange(len(rng)), index = rng)
print(ts)
print("\n")
ts_re = ts.resample("5D")
ts_re2 = ts.resample("5D").sum()
print(ts_re, type(ts_re))
print("\n")
print(ts_re2, type(ts_re2))
print("---------")
# ts.resample("5D"):得到一个重采样构建器,频率改为5天
# ts.resample("5d").sum():得到一个新的聚合后的Series,聚合方式为求和
# freq:重采样频率 -> ts.resample("5D")
# .sum():聚合方法
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')
# OHLC:金融领域的时间序列聚合方式 → open开盘、high最大值、low最小值、close收盘
降采样
rng = pd.date_range("20170101", periods = 12)
ts = pd.Series(np.arange(1,13), index = rng)
print(ts)
print("-------")
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('-----')
# 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', label = 'left').sum(),'→ leftlabel\n')
print(ts.resample('5D', label = 'right').sum(),'→ rightlabel\n')
# label:聚合值的index,默认为取左
# 值采样认为默认(这里closed默认)
升采样及插值
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)
print(ts.resample('15T').asfreq())
print(ts.resample('15T').ffill())
print(ts.resample('15T').bfill())
# 低频转高频,主要是如何插值
# .asfreq():不做填充,返回Nan
# .ffill():向上填充
# .bfill():向下填充
时期重采样 - Period
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()) # 升采样
最后:
Pandas课程作业
Pandas课程作业答案
以上完整代码