CH02数据分析工具:Pandas__Part02

3 篇文章 0 订阅
3 篇文章 0 订阅

第二部分介绍

该部分主要介绍pandas的时间模块。

【课程2.8】 Python中时间相关库

time 模块

暂时未整理

datetime模块

主要掌握:

  • datetime.date() - 表示日期的类,常用属性:year, month, day
  • datetime.datetime() - 表示时间的类,常用属性:hour, minute, second, microsecond, tzinfo
  • datetime.timedelta() - 表示时间间隔,即两个时间点(date,time,datetime)之间的长度
# 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)
# (年,月,日) → 直接得到当时日期
2021-12-11 <class 'datetime.date'>
2021-12-11 <class 'str'>
2016-06-01
# datetime.datetime:datetime对象

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

t1 = datetime.datetime(2021,10,20)
t2 = datetime.datetime(2021,12,11,12,44,33)  # (年,月,日,时,分,秒),至少输入年月日
print(t1,t2)
t2-t1 # 日期可做差,无法做加
# 相减得到时间差 —— timedelta
2021-12-11 12:55:10.256432 <class 'datetime.datetime'>
2021-12-11 12:55:10.256432 <class 'str'>
2021-10-20 00:00:00 2021-12-11 12:44:33





datetime.timedelta(days=52, seconds=45873)
# datetime.timedelta:时间差

today = datetime.datetime.today()  # datetime.datetime也有today()方法
yestoday = today - datetime.timedelta(1)  # 
print(today)
print(yestoday)
print(today - datetime.timedelta(7))
# 时间差主要用作时间的加减法,相当于可被识别的时间“差值”
2021-12-11 12:55:10.280433
2021-12-10 12:55:10.280433
2021-12-04 12:55:10.280433
dateutil模块
日期解析方法:dateutil.parser.parse()
import dateutil
dateutil.parser.parse( '12-21-2017')  # <class 'datetime.datetime'>

计算时间差方法:dateutil.rrule.rrule()
dateutil.rrule.rrule(
    freq,#"YEARLY", "MONTHLY", "WEEKLY", "DAILY","HOURLY", "MINUTELY", "SECONDLY" 采样跨度
    dtstart=None,#开始
    interval=1,#间隔
    wkst=None,
    count=None,#次数
    until=None, #结束
    bysetpos=None,
    bymonth=None,
    bymonthday=None,
    byyearday=None,
    byeaster=None,
    byweekno=None,
    byweekday=None,
    byhour=None,
    byminute=None,
    bysecond=None,
    cache=False,
)```


```python
# parser.parse:日期字符串转换
from dateutil.parser import parse
# 直接将str转化成datetime.datetime
date = '12-21-2017'
t = parse(date)
print(t,type(t))
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'))
# 各种格式可以解析,但无法支持中文
2017-12-21 00:00:00 <class 'datetime.datetime'>
2000-01-01 00:00:00 
 2014-05-01 00:00:00 
 2014-01-05 00:00:00 
 2014-01-22 00:00:00 
 1997-01-31 22:45:00
from dateutil.parser import parse
from dateutil.rrule import *
import dateutil
a = list(dateutil.rrule.rrule(DAILY, dtstart=parse('2021.12.9'), until=parse('2021.12.19')))  # 按天打印
a
[datetime.datetime(2021, 12, 9, 0, 0),
 datetime.datetime(2021, 12, 10, 0, 0),
 datetime.datetime(2021, 12, 11, 0, 0),
 datetime.datetime(2021, 12, 12, 0, 0),
 datetime.datetime(2021, 12, 13, 0, 0),
 datetime.datetime(2021, 12, 14, 0, 0),
 datetime.datetime(2021, 12, 15, 0, 0),
 datetime.datetime(2021, 12, 16, 0, 0),
 datetime.datetime(2021, 12, 17, 0, 0),
 datetime.datetime(2021, 12, 18, 0, 0),
 datetime.datetime(2021, 12, 19, 0, 0)]
tp1=datetime.datetime.now()
print(str(tp))
from dateutil.parser import parser
tp2=parse('1997/07/15 12:30:00')
tp=tp1-tp2
# datetime.timedelta(days=1000)
print(type(tp))
# 倒计时程序
#给定未来一个时间,计算此时此刻距离给定时刻的差值
import time
future=parse('2022/01/01 12:00:00')
split=datetime.datetime.now()
future_timestamp=int(time.mktime(future.timetuple()))
now_timestamp= int(time.mktime(split.timetuple()))
for i,x in enumerate(range(future_timestamp-now_timestamp)):
    split=datetime.datetime.now()
    time.sleep(1)
    print(type(future))
    print(future -split)
    if i >5:
        break
dt = '2018-01-01 10:40:30'
time.strptime(dt, "%Y-%m-%d %H:%M:%S")

######## 本节课有作业,请查看 “课程作业.docx” ########

【课程2.9】 Pandas时刻数据:Timestamp

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

  • pandas.Timestamp(date) # 可传入时间格式的字符串,time对象 不能是容器

  • pandas.to_datetime(date)# date可传入时间格式的字符串,time对象 或以上类型的容器

pandas.Timestamp(date)
# pd.Timestamp()

import numpy as np
import pandas as pd

date1 = datetime.datetime(2016,12,1,12,45,30)  # 创建一个datetime.datetime
date2 = '2021-12-30'  # 创建一个字符串
t1 = pd.Timestamp(date1)
t2 = pd.Timestamp(date2)
print(t1,type(t1))
print(t2,type(t2))
print(pd.Timestamp('2021-12-21 15:00:22'))
# 直接生成pandas的时刻数据 → 时间戳
# 数据类型为 pandas的Timestamp
pandas.to_datetime(date)
# pd.to_datetime

from datetime import datetime

date1 = datetime(2016,12,1,12,45,30)
date2 = '2021-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 = [ '2021-12-21', '2021-12-22', '2021-12-23']
t3 = pd.to_datetime(lst_date)
print(t3,type(t3))
# print(pd.Timestamp(lst_date)) # 会报错!
# 多个时间数据,将会转换为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 = ['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

######## 本节课有作业,请查看 “课程作业.docx” ########

【课程2.10】 Pandas时间戳索引:DatetimeIndex

  • pd.DatetimeIndex(date) # date,date_item
  • pd.date_range(start , end) 或pd.date_range(start|end,periods)
pd.DatetimeIndex()
# 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,时间序列
pd.date_range 详解

pd.date_range(start=None, end=None, periods=None, freq=‘D’, tz=None, normalize=False, name=None, closed=None, …)

  • 2种生成方式:①start + end; ②start/end + period
  • start:开始时间
  • end:结束时间
  • periods:偏移量
  • freq:频率,默认天,pd.date_range()默认频率为日历日,pd.bdate_range()默认频率为工作日
  • tz:时区
  • closed:left则左闭右开,right则左开右闭,默认左闭右闭
# pd.date_range()-日期范围:生成日期范围
# 2种生成方式:①start + end; ②start/end + periods
# 默认频率:day

rng1 = pd.date_range('1/1/2021','1/10/2021', normalize=True)
rng2 = pd.date_range(start = '1/1/2021', periods = 10)
rng3 = pd.date_range(end = '1/30/2021 15:00:00', periods = 10)  # 增加了时、分、秒
print(rng1,type(rng1))
print(rng2)
print(rng3)
print('-------')
# 直接生成DatetimeIndex

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: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:每月的第几个星期几开始算,这里是每月第二个星期一
# 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))
print('------')
# 正数:数值后移(滞后);负数:数值前移(超前)

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

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

######## 本节课有作业,请查看 “课程作业.docx” ########

【课程2.11】 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)
# 通过加减整数,将周期整体移动
# 这里是按照 月、年 移动
# 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时区别不大
# 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())
# 每月,转化为每月第一天

######## 本节课有作业,请查看 “课程作业.docx” ########

【课程2.12】 时间序列 - 索引及切片

  • 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(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做分组,重复的值这里用平均值处理

######## 本节课有作业,请查看 “课程作业.docx” ########

【课程2.13】 时间序列 - 重采样

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

  • 降采样:高频数据 → 低频数据,eg.以天为频率的数据转为以月为频率的数据
  • 升采样:低频数据 → 高频数据,eg.以年为频率的数据转为以月为频率的数据
重采样
# 重采样:.resample()
# 创建一个以天为频率的TimeSeries,重采样为按2天为频率

rng = pd.date_range('20170101', periods = 12)
ts = pd.Series(np.arange(12), index = rng)
print(ts.head())
ts_re2 = ts.resample('5D').sum()
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').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(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())  # 升采样

######## 本节课有作业,请查看 “课程作业.docx” ########

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值