数据导入与预处理-拓展-pandas时间数据处理02
- Pandas时序数据系列博客
- Pandas时间序列数据处理
- 1.好用的Python库
- 2.Pandas历史
- 3.时序数据处理
- 3.1 时序中的基本对象
- 3.2 python中的datetime模块
- 3.3. 时间戳(Date times)的构造与属性
- 3.4. 时间差(Timedelta)的构造与属性
- 1.Timedelta生成
- 1.通过pd.Timedelta来构造
- 2 to_timedelta生成
- 3. timedelta_range生成
- 4. dt对象
- 2. Timedelta的运算
- 1.Timedelta生成
- 3.5 时间段Time spans的构造与属性:Period - 1. 通过Period生成 - 2. 通过period_range方法生成 - 3. asfreq:频率转换
- 3.6 相互转换
- 3.7 日期偏置DateOffset的构造与属性
- 3.8 时序中的滑窗与分组
- 1. 滑动窗口
- 2.重采样
Pandas时序数据系列博客
数据导入与预处理-拓展-pandas时间数据处理01
数据导入与预处理-拓展-pandas时间数据处理02
数据导入与预处理-拓展-pandas时间数据处理03
备注:如果有帮助,欢迎点赞收藏评论一键三联哈~~
Pandas时间序列数据处理
1.好用的Python库
见系列博客1
2.Pandas历史
见系列博客1
3.时序数据处理
见系列博客1
本文部分内容来源为:joyful-pandas
3.1 时序中的基本对象
见系列博客1
3.2 python中的datetime模块
见系列博客1
3.3. 时间戳(Date times)的构造与属性
见系列博客1
3.4. 时间差(Timedelta)的构造与属性
概念 | 单元素类型 | 数组类型 | pandas数据类型 |
---|---|---|---|
Date times | Timestamp | DatetimeIndex | datetime64ns |
Time deltas | Timedelta | TimedeltaIndex | timedelta64ns |
Time spans | Period | PeriodIndex | periodfreq |
Date offsets | DateOffset | None | None |
1.Timedelta生成
1.通过pd.Timedelta来构造
时间差可以理解为两个时间戳的差,这里也可以通过pd.Timedelta来构造:
通过Timestamp构建时间差Timedelta
代码语言:javascript复制import numpy as np
import pandas as pd
pd.Timestamp('20220102 08:00:00')-pd.Timestamp('20220101 07:35:00')
输出为:
代码语言:javascript复制Timedelta('1 days 00:25:00')
通过Timedelta生成
代码语言:javascript复制pd.Timedelta(days=1, minutes=25) # 需要注意加s
# pd.Timedelta('1 days 25 minutes') # 字符串生成 同上一样
输出:
代码语言:javascript复制Timedelta('1 days 00:25:00')
2 to_timedelta生成
to_timedelta生成-精确到 20.5us
代码语言:javascript复制# 精确到 20.5us
pd.to_timedelta('20.5us')
输出为:
代码语言:javascript复制Timedelta('0 days 00:00:00.000020500')
to_timedelta生成-构建一个Timedelta序列
代码语言:javascript复制pd.to_timedelta(['2 days 04:06:10.00006', '15.5us', 'nan'])
输出为:
代码语言:javascript复制TimedeltaIndex(['2 days 04:06:10.000060', '0 days 00:00:00.000015500', NaT], dtype='timedelta64[ns]', freq=None)
to_timedelta生成-指定单位
代码语言:javascript复制pd.to_timedelta(np.arange(6), unit='d')
输出为:
代码语言:javascript复制TimedeltaIndex(['0 days', '1 days', '2 days', '3 days', '4 days', '5 days'], dtype='timedelta64[ns]', freq=None)
3. timedelta_range生成
与date_range一样,时间差序列也可以用timedelta_range来生成,它们两者具有一致的参数:
代码语言:javascript复制import numpy as np
import pandas as pd
pd.timedelta_range(start='2 day', periods=5, freq='6H', closed='right')
输出为:
代码语言:javascript复制TimedeltaIndex(['2 days 06:00:00', '2 days 12:00:00', '2 days 18:00:00','3 days 00:00:00'],
dtype='timedelta64[ns]', freq='6H')
4. dt对象
对于Timedelta序列,同样也定义了dt对象,上面主要定义了的属性包括days, seconds, mircroseconds, nanoseconds,它们分别返回了对应的时间差特征。
2. Timedelta的运算
时间差支持的常用运算有三类:与标量的乘法运算、与时间戳的加减法运算、与时间差的加减法与除法运算:
代码语言:javascript复制# 初始化Timedelta
td1 = pd.Timedelta(days=1) # Timedelta('1 days 00:00:00')
td2 = pd.Timedelta(days=3) # Timedelta('3 days 00:00:00')
# 与标量的计算
td1 * 2 # Timedelta('2 days 00:00:00')
# 与时间差的计算
td2 - td1 # Timedelta('2 days 00:00:00')
# 与时间戳的计算
ts = pd.Timestamp('20200101')
td1 = pd.Timedelta(days=1) # Timedelta('1 days 00:00:00')
ts td1 # Timestamp('2020-01-02 00:00:00')
时间差序列计算:
代码语言:javascript复制# 定义时间差
td1 = pd.timedelta_range(start='1 days', periods=5)
td1
"""
# TimedeltaIndex(['1 days', '2 days', '3 days', '4 days', '5 days'],
dtype='timedelta64[ns]', freq='D')
"""
td2 = pd.timedelta_range(start='12 hours', freq='2H', periods=5)
td2
"""
TimedeltaIndex(['0 days 12:00:00', '0 days 14:00:00', '0 days 16:00:00',
'0 days 18:00:00', '0 days 20:00:00'],
dtype='timedelta64[ns]', freq='2H')
"""
ts = pd.date_range('20200101', '20200105')
ts
"""
DatetimeIndex(['2020-01-01', '2020-01-02', '2020-01-03', '2020-01-04',
'2020-01-05'],
时间差序列与标量计算:
代码语言:javascript复制td1 * 5
# TimedeltaIndex(['5 days', '10 days', '15 days', '20 days', '25 days'], dtype='timedelta64[ns]', freq='5D')
输出为:
代码语言:javascript复制TimedeltaIndex(['5 days', '10 days', '15 days', '20 days', '25 days'], dtype='timedelta64[ns]', freq='5D')
时间差序列与series计算
代码语言:javascript复制td1 * pd.Series(list(range(5))) # 逐个相乘
输出为:
代码语言:javascript复制0 0 days
1 2 days
2 6 days
3 12 days
4 20 days
dtype: timedelta64[ns]
时间差序列直接计算
代码语言:javascript复制td1 - td2
输出为:
代码语言:javascript复制TimedeltaIndex(['0 days 12:00:00', '1 days 10:00:00', '2 days 08:00:00',
'3 days 06:00:00', '4 days 04:00:00'],
dtype='timedelta64[ns]', freq=None)
时间差序列与时间戳计算:
代码语言:javascript复制td1 pd.Timestamp('20200101')
输出为:
代码语言:javascript复制DatetimeIndex(['2020-01-02', '2020-01-03', '2020-01-04', '2020-01-05',
'2020-01-06'],
dtype='datetime64[ns]', freq='D')
3.5 时间段Time spans的构造与属性:Period
概念 | 单元素类型 | 数组类型 | pandas数据类型 |
---|---|---|---|
Date times | Timestamp | DatetimeIndex | datetime64ns |
Time deltas | Timedelta | TimedeltaIndex | timedelta64ns |
Time spans | Period | PeriodIndex | periodfreq |
Date offsets | DateOffset | None | None |
1. 通过Period生成
代码语言:javascript复制# 生成一个以2022-01开始,月为频率的时间构造器
# pd.Period()参数:一个时间戳 freq 参数 → freq 用于指明该 period 的长度,时间戳则说明该 period 在时间轴上的位置
period_d = pd.Period('2022', freq = 'M')
print(period_d, type(period_d))
# 通过加减整数,将周期整体移动
# 这里是按照 月、年 移动
print('period_d 1的结果为:',period_d 1)
print('period_d - 2的结果为:',period_d - 2)
print(pd.Period('2022', freq = 'A-DEC') - 1)
输出为:
代码语言:javascript复制2022-01 <class 'pandas._libs.tslibs.period.Period'>
period_d 1的结果为: 2022-02
period_d - 2的结果为: 2021-11
2021
2. 通过period_range方法生成
代码语言:javascript复制# pd.period_range()创建时期范围
prng = pd.period_range('1/1/2021', '1/1/2022', freq='M')
print(prng,type(prng))
print(prng[0],type(prng[0]))
# 数据格式为PeriodIndex,单个数值为Period
输出为:
代码语言:javascript复制PeriodIndex(['2021-01', '2021-02', '2021-03', '2021-04', '2021-05', '2021-06',
'2021-07', '2021-08', '2021-09', '2021-10', '2021-11', '2021-12',
'2022-01'],
dtype='period[M]', freq='M') <class 'pandas.core.indexes.period.PeriodIndex'>
2021-01 <class 'pandas._libs.tslibs.period.Period'>
构建series,指定索引为PeriodIndex
代码语言:javascript复制ts = pd.Series(np.arange(len(prng)), index = prng)
print(ts,type(ts))
print(ts.index)
# 时间序列
输出为:
代码语言:javascript复制2021-01 0
2021-02 1
2021-03 2
2021-04 3
2021-05 4
2021-06 5
2021-07 6
2021-08 7
2021-09 8
2021-10 9
2021-11 10
2021-12 11
2022-01 12
Freq: M, dtype: int32 <class 'pandas.core.series.Series'>
PeriodIndex(['2021-01', '2021-02', '2021-03', '2021-04', '2021-05', '2021-06',
'2021-07', '2021-08', '2021-09', '2021-10', '2021-11', '2021-12',
'2022-01'],
dtype='period[M]', freq='M')
3. asfreq:频率转换
代码语言:javascript复制# asfreq:频率转换
# Period('2020', freq = 'A-DEC')可以看成多个时间期的时间段中的游标
# Timestamp表示一个时间戳,是一个时间截面;Period是一个时期,是一个时间段!!但两者作为index时区别不大
p = pd.Period('2020','A-DEC')
print("p--->",p)
print("p--->",p.asfreq('M', how = 'start')) # 也可写 how = 's'
print("p--->",p.asfreq('D', how = 'end')) # 也可写 how = 'e'
# 通过.asfreq(freq, method=None, how=None)方法转换成别的频率
print('*'*10)
prng = pd.period_range('2020','2021',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
输出为:
代码语言:javascript复制p---> 2020
p---> 2020-01
p---> 2020-12-31
**********
2020-01 0.602249
2020-02 0.470631
2020-03 0.515769
2020-04 0.221421
2020-05 0.959175
Freq: M, dtype: float64 13
2020-01-01 0.115775
2020-02-01 0.309005
2020-03-01 0.738583
2020-04-01 0.785310
2020-05-01 0.574895
Freq: D, dtype: float64 13
3.6 相互转换
时间戳与时期之间的转换
时间戳转时间段
代码语言:javascript复制# 时间戳与时期之间的转换:pd.to_period()、pd.to_timestamp()
# 每月最后一日,转化为每月
rng = pd.date_range('2020/1/1', periods = 3, freq = 'M')
ts1 = pd.Series(np.arange(len(rng)), index = rng)
print(ts1.head())
print(ts1.to_period().head())
print(type(ts1.index),type(ts1.to_period().index))
# <class 'pandas.core.indexes.datetimes.DatetimeIndex'> <class 'pandas.core.indexes.period.PeriodIndex'>
输出为:
代码语言:javascript复制2020-01-31 0
2020-02-29 1
2020-03-31 2
Freq: M, dtype: int32
2020-01 0
2020-02 1
2020-03 2
Freq: M, dtype: int32
<class 'pandas.core.indexes.datetimes.DatetimeIndex'> <class 'pandas.core.indexes.period.PeriodIndex'>
print('*'*10)
时间段转时间戳
代码语言:javascript复制# 每月,转化为每月第一天
prng = pd.period_range('2020','2021', freq = 'M')
ts2 = pd.Series(np.arange(len(prng)), index = prng)
print(ts2.head())
print(ts2.to_timestamp().head())
print(type(ts2.index),type(ts2.to_timestamp().index))
3.7 日期偏置DateOffset的构造与属性
概念 | 单元素类型 | 数组类型 | pandas数据类型 |
---|---|---|---|
Date times | Timestamp | DatetimeIndex | datetime64ns |
Time deltas | Timedelta | TimedeltaIndex | timedelta64ns |
Time spans | Period | PeriodIndex | periodfreq |
Date offsets | DateOffset | None | None |
Offset对象
日期偏置是一种和日历相关的特殊时间差,例如回到第一节中的两个问题:如何求2020年9月第一个周一的日期,以及如何求2020年9月7日后的第30个工作日是哪一天。
求下一个月的第几周的周几,week=0表示为第1周,weekday=0表示为周日
代码语言:javascript复制# week=0表示为第1周,weekday=0表示为周日
pd.Timestamp('20220905') pd.offsets.WeekOfMonth(week=0,weekday=0)
输出为:
代码语言:javascript复制Timestamp('2022-10-03 00:00:00')
偏移30天
代码语言:javascript复制pd.Timestamp('20220907') pd.offsets.BDay(30)
输出为:
代码语言:javascript复制Timestamp('2022-10-19 00:00:00')
常用的日期偏置如下可以查阅这里的文档描述。在文档罗列的Offset中,需要介绍一个特殊的Offset对象CDay,其中的holidays, weekmask参数能够分别对自定义的日期和星期进行过滤,前者传入了需要过滤的日期列表,后者传入的是三个字母的星期缩写构成的星期字符串,其作用是只保留字符串中出现的星期。
3.8 时序中的滑窗与分组
1. 滑动窗口
所谓时序的滑窗函数,即把滑动窗口用freq关键词代替,下面给出一个具体的应用案例:在股票市场中有一个指标为BOLL指标,它由中轨线、上轨线、下轨线这三根线构成,具体的计算方法分别是N日均值线、N日均值加两倍N日标准差线、N日均值减两倍N日标准差线。利用rolling对象计算N=30的BOLL指标可以如下写出:
代码语言:javascript复制import matplotlib.pyplot as plt
idx = pd.date_range('20200101', '20201231', freq='B')
np.random.seed(2020)
data = np.random.randint(-1,2,len(idx)).cumsum() # 随机游动构造模拟序列
s = pd.Series(data,index=idx)
s
输出为:
代码语言:javascript复制2020-01-01 -1
2020-01-02 -2
2020-01-03 -1
2020-01-06 -1
2020-01-07 -2
..
2020-12-25 17
2020-12-28 18
2020-12-29 19
2020-12-30 19
2020-12-31 18
Freq: B, Length: 262, dtype: int32
代码语言:javascript复制r = s.rolling('30D')
r
输出为:
代码语言:javascript复制Rolling [window=2592000000000000,min_periods=1,center=False,win_type=freq,axis=0]
可视化:
代码语言:javascript复制plt.plot(s,label='30D')
plt.title('BOLL LINES')
plt.plot(r.mean(),label='mean')
plt.plot(r.mean() r.std()*2,label='mean std()*2')
plt.plot(r.mean()-r.std()*2,label='mean-std()*2')
plt.legend()
plt.show()
输出为:
对于shift函数而言,作用在datetime64为索引的序列上时,可以指定freq单位进行滑动:
代码语言:javascript复制s.shift(freq='1D')
输出为:
2.重采样
重采样对象resample和分组对象groupby的用法类似,前者是针对时间序列的分组计算而设计的分组对象。
例如,对上面的序列计算每个月的均值:
代码语言:javascript复制s.resample('1M').mean()
输出为:
代码语言:javascript复制2020-01-31 -3.000000
2020-02-29 -0.750000
2020-03-31 3.090909
2020-04-30 6.818182
2020-05-31 5.952381
2020-06-30 8.954545
2020-07-31 11.217391
2020-08-31 7.952381
2020-09-30 10.727273
2020-10-31 8.863636
2020-11-30 14.952381
2020-12-31 19.695652
Freq: M, dtype: float64
代码语言:javascript复制s1 = s.copy()
s1.index = s_month
s1
输出为:
代码语言:javascript复制1 -1
1 -2
1 -1
1 -1
1 -2
..
12 17
12 18
12 19
12 19
12 18
Length: 262, dtype: int32
采用分组的办法求均值
代码语言:javascript复制s1.reset_index().groupby(by='index').mean()
输出为:
同时,如果没有内置定义的处理函数,可以通过apply方法自定义:
代码语言:javascript复制s.resample('1M').apply(lambda x:x.max()-x.min()) # 极差
输出为
代码语言:javascript复制2020-01-31 4
2020-02-29 7
2020-03-31 5
2020-04-30 3
2020-05-31 5
2020-06-30 7
2020-07-31 5
2020-08-31 2
2020-09-30 5
2020-10-31 4
2020-11-30 10
2020-12-31 4
Freq: M, dtype: int32
在resample中要特别注意组边界值的处理情况,默认情况下起始值的计算方法是从最小值时间戳对应日期的午夜00:00:00开始增加freq,直到不超过该最小时间戳的最大时间戳,由此对应的时间戳为起始值,然后每次累加freq参数作为分割结点进行分组,区间情况为左闭右开。
基本知识描述完毕,系列博文中提供一个对应的案例,见系列文章3