pandas学习笔记三时间序列

Posted 周虽旧邦其命维新

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了pandas学习笔记三时间序列相关的知识,希望对你有一定的参考价值。

1、时间模块

import datetime

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

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

d = datetime.date(2021, 10, 18)
print(d)
# (年,月,日) → 直接得到当时日期

# datetime.datetime:datetime对象

d = datetime.datetime.now()
print(d, type(d))
# .now()方法,输出当前时间
# 输出格式为 datetime类

t1 = datetime.datetime(2021, 10, 18)
t2 = datetime.datetime(2021, 10, 18, 17, 59)
print(t1, t2)
# (年,月,日,时,分,秒),至少输入年月日

print(t2-t1, type(t2-t1))
# 相减得到时间差 —— timedelta

# datetime.timedelta:时间差

t1 = datetime.datetime(2021, 10, 18)
dt = datetime.timedelta(100)
print(t1 + dt)
print(t1 - dt)
dt2 = datetime.timedelta(100, 7200)
print(t1 + dt2)

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

from dateutil.parser import parse

print(parse('2022, 12, 11'))
# 直接将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、时间模块作业

import datetime

# 作业1:请调用datetime模块,输出以下时间信息

print(datetime.datetime.now())
print(datetime.datetime(2022, 10, 12, 10, 12))
print(datetime.datetime(2022, 10, 12))

# 作业2:请创建时间变量‘2000年5月1日’,求出1000天之后是哪年哪月哪日?

d = datetime.date(2000, 5, 1)
dt = datetime.timedelta(1000)
print(d + dt)

3、pandas时间戳Timestamp

import datetime

import numpy as np
import pandas as pd

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

d = pd.Timestamp('20020101')
print(d, type(d))
d = pd.Timestamp(datetime.datetime(2022, 9, 11, 17, 25))
print(d)
# 直接生成pandas的时刻数据 → 时间戳
# 数据类型为 pandas的Timestamp

# pd.to_datetime
from datetime import datetime

d = pd.to_datetime('20020101')
print(d, type(d))
d = pd.to_datetime(datetime(2022, 9, 11, 17, 25))
print(d, type(d))
# pd.to_datetime():如果是单个时间数据,转换成pandas的时刻数据,数据类型为Timestamp

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

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

print('--------------------------------------------------------')
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

4、pandas时间戳Timestamp作业

import numpy as np
import pandas as pd
import datetime

# 作业1:请通过迭代创建一个时间列表(如图,时间区间为任意一个月,这里可以用for语句),然后转化成DatetimeIndex,并print月中是多少号

arr = []
d = datetime.date(2022, 10, 1)
dt = datetime.timedelta(1)
for i in range(31):
    arr.append(str(d))
    d = d + dt
print(arr)
dr = pd.to_datetime(arr)
print(dr)

# 作业2:请如图创建一个包含时间日期的txt文件,通过open语句读取后转化成DatetimeIndex

arr = []
file_handle = open("c:\\\\lyz\\\\data.txt", mode="r")
lines = file_handle.readlines()
file_handle.close()
for line in lines:
    words = line.split(',')
    for word in words:
        arr.append(word)
print(arr)
dr = pd.to_datetime(arr)
print(dr)

# 参考答案比我写的简洁,贴在下面

# 作业1

datelst = []
for i in range(1,32):
    datelst.append('2017-12-%i' %i)
print('创建时间列表为:\\n',datelst,'\\n------')
t = pd.to_datetime(datelst)
print('转化成DatetimeIndex为:\\n',t,'\\n------')
n = (len(t) + 1)/2 - 1
print('月中日期为:\\n',t[int(n)],'\\n------')

# 作业2

f = open('C:/Users/Hjx/Desktop/date.txt','r')
s = f.readline()
datelst = s.split(',')
print('读取txt文件为:\\n',datelst,'\\n------')
t = pd.to_datetime(datelst)
print('转化成DatetimeIndex为:\\n',t,'\\n------')

5、pandas时间序列

import numpy as np
import pandas as pd
import datetime

# Pandas时间戳索引:DatetimeIndex
# 核心:pd.date_range()

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

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

# pd.date_range()-日期范围:生成日期范围
# 2种生成方式:①start + end; ②start/end + periods
# 默认频率:day

dr1 = pd.date_range('1/10/2022', '12/10/2022', normalize=True)
dr2 = pd.date_range(start='1/10/2022', periods=10)
dr3 = pd.date_range(end='12/10/2022', periods=10)
print(dr1, type(dr1))
print(dr2)
print(dr3)

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

print(pd.date_range(start='10/12/2022', end='10/22/2022'))
print(pd.date_range(start='10/12/2022', end='10/22/2022', closed='right'))
print(pd.date_range(start='10/12/2022', end='10/22/2022', closed='left'))
# closed:默认为None的情况下,左闭右闭,left则左闭右开,right则左开右闭

print('=======================================================')
print(pd.bdate_range(start='10/12/2022', end='10/22/2022'))
# pd.bdate_range()默认频率为工作日,b代表business,使用方法与pd.date_range相同

print(list(pd.date_range(start='10/12/2022', end='10/22/2022')))
# 直接转化为list,元素为Timestamp

print('===================================================================')
# 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('10/11/2022', '10/14/2022'))
print(ts)
ts2 = ts.asfreq('3H', method='ffill')
print(ts2)
# 改变频率,这里是D改为4H
# method:插值模式,None不插值,ffill用之前值填充,bfill用之后值填充

print('----------------------------------------------------------------------')
ts = pd.Series(np.random.rand(4), index=pd.date_range('10/11/2022', '10/14/2022'))
print(ts)
print(ts.shift(2))
print(ts.shift(-2))
# 正数:数值后移(滞后);负数:数值前移(超前)

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

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

6、pandas时间序列作业

import numpy as np
import pandas as pd

# 作业1:请输出以下时间序列

ts = pd.Series(np.random.rand(5), pd.date_range('1/1/2017', '1/5/2017'))
print(ts)
print(pd.date_range('2017', '2017-12', freq='Q-JAN'))
ts2 = pd.Series(np.random.rand(4), pd.date_range('2017', '2017-12', freq='Q-JAN'))
print(ts2)
print(pd.date_range(start='12/1/2017', periods=4, freq='10T'))
dr = pd.DataFrame(np.random.rand(16).reshape(4, 4),
                  index=pd.date_range(start='12/1/2017', periods=4, freq='10T'),
                  columns=['value1', 'value2', 'value3', 'value4'])
print(dr)

# 作业2:按要求创建时间序列ts1,并转换成ts2

print(pd.date_range(start='5/1/2017 12:00', end='5/1/2017 12:40', freq='10T'))
ts = pd.Series(np.random.rand(5), index=pd.date_range(start='5/1/2017 12:00', end='5/1/2017 12:40', freq='10T'))
print(ts)
ts2 = ts.asfreq(freq='5T', method='ffill')
print(ts2)

7、pandas时间序列Period

import numpy as np
import pandas as pd

# 核心:pd.Period()

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

print(p + 1)
print(p - 2)

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

pr = pd.period_range(start='10/13/2022', end='12/31/2022', freq='M')
print(pr)
ts = pd.Series(np.random.rand(len(pr)), index=pr)
print(ts, type(ts))
print(type(ts.index))
# 时间序列

# Period('2011', freq = 'A-DEC')可以看成多个时间期的时间段中的游标
# Timestamp表示一个时间戳,是一个时间截面;Period是一个时期,是一个时间段!!但两者作为index时区别不大

# asfreq:频率转换

p = pd.Period('2022', freq='A-DEC')
print(p, type(p))
print(p.asfreq('M', how='start'))
print(p.asfreq('D', how='end'))
# 通过.asfreq(freq, method=None, how=None)方法转换成别的频率

pr = pd.period_range('2021', '2022', freq='M')
print(pr)
ts = pd.Series(np.random.rand(len(pr)), index=pr)
print(ts)
ts = pd.Series(np.random.rand(len(pr)), index=pr.asfreq('D', how='start'))
print(ts)
print(ts.head())

# 时间戳与时期之间的转换:pd.to_period()、pd.to_timestamp()

dr = pd.date_range('1/1/2022', '1/1/2023', freq='M')
print(dr)
pr = pd.period_range('1/1/2022', '1/1/2023', freq='M')
print(pr)
ts = pd.Series(np.random.rand(len(dr)), index=dr)
print(ts)
print(ts.to_period())
# 每月最后一日,转化为每月

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

8、pandas时间序列Period作业

import numpy as np
import pandas as pd

# 作业1:请输出以下时间序列,使用pd.period_range()
pr = pd.period_range('1/1/2022', periods=5, freq='M')
print(pr)
ts = pd.Series(np.random.rand(len(pr)), index=pr)
print(ts)

pr = pd.period_range('1/1/2022', periods=5, freq='2H')
ts = pd.Series(np.random.rand(len(pr)), index=pr)
print(ts)

9、pandas时间序列索引及切片

import numpy as np
import pandas as pd
from datetime import datetime

# TimeSeries是Series的一个子类,所以Series索引及数据选取方面的方法基本一样
# 同时TimeSeries通过时间序列有更便捷的方法做索引和切片

dr = pd.date_range('2022/1', '2022/3', freq='D')
ts = pd.Series(np.random.rand(len(dr)), index=dr)
print(ts.head())

print(ts[0])
print(ts[:2])
# 基本下标位置索引

print(ts['20220102'])
print(ts['1/2/2022'])
print(ts[datetime(2022, 1, 2)])
# 时间序列标签索引,支持各种时间字符串,以及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'])
# 传入月,直接得到一个切片

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

print(ts['1/1/2015'])
# index有重复的将返回多个值

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

10、pandas时间序列索引及切片作业

import numpy as np
import pandas as pd

# 作业1:如图创建时间序列(10*3,值为0-100的随机数),通过索引得到以下值
# ① 索引得到前4行的所有值
# ② 索引得到2017-12-4 12:00:00的数据
# ③ 索引得到2017-12-4 - 2017-12-5的数据

dr = pd.date_range(start='12/1/2017', freq='12H', periods=10)
print(dr)
df = pd.DataFrame(np.random.rand(len(dr) * 3).reshape(10, 3) * 100, index=dr, columns=['value1', 'value2', 'value3'])
print(df)
print(df.iloc[:4])

print(df.loc['2017-12-4 12'])
print(df.loc['2017-12-4 00': '2017-12-5 12'])

11、pandas时间序列重采样

import numpy as np
import pandas as pd

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

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

# 重采样:.resample()
# 创建一个以天为频率的TimeSeries,重采样为按2天为频率

dr = pd.date_range('20221013', periods=12)
print(dr)
ts = pd.Series(np.random.rand(len(dr)), index=dr)
s = ts.resample('2D')
print(s, type(s))
print(s.sum())
# 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收盘

print('=========================================')
print(ts.resample('6D', closed='left').sum())
print(ts.resample('6D', closed='right').sum())
# 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默认)

# 升采样及插值

print('=======================================================')
print(ts)
print(ts.resample('6H').asfreq())
print(ts.resample('6H').ffill())
print(ts.resample('6H').bfill())
# 低频转高频,主要是如何插值
# .asfreq():不做填充,返回Nan
# .ffill():向上填充
# .bfill():向下填充

# 时期重采样 - Period

prng = pd.period_range('2016','2018',freq = 'M')
ts = pd.Series(np.arange(len(prng)), index = prng)
print(ts)

# 降采样会发生报错,需要将PeriodIndex转为DateTimeIndex
# IncompatibleFrequency: Frequency <MonthEnd> cannot be resampled to <3 * MonthEnds>, as they are not sub or super periods

ts.index = ts.index.astype('datetime64[ns]')
print(ts.resample('5M').sum())  # 降采样
print(ts.resample('15D').ffill())  # 升采样

12、pandas时间序列重采样作业

import numpy as np
import pandas as pd

# 作业1:按要求创建时间序列ts1,通过降采样和升采样,转换成ts2,ts3

dr = pd.date_range('1/1/2022', periods=10)
print(dr)
ts = pd.Series(np.random.rand(len(dr)), index=dr)
print(ts)
print(ts.resample('3D').mean())
print(ts.resample('12H').ffill())

以上是关于pandas学习笔记三时间序列的主要内容,如果未能解决你的问题,请参考以下文章

Python 之 Pandas 生成时间戳范围Pandas 的时期函数 Period() 和时间序列 - 重采样 resample

pandas group 日期到季度和总销售额列

下采样到季度级别并在 Pandas 中获取季度结束日期值

Python/Pandas:查找将假期考虑在内的日期时间的自定义业务季度结束

pandas 将 datetimeindex 格式转换为季度

pandas基于日期信息(time or date)生成季度信息(quarter)实战:pandas基于日期信息列生成季度信息列dt.quarter生成季度信息dt.to_period生成季度信息