数据导入与预处理-拓展-pandas时间数据处理02

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 timesTimestampDatetimeIndexdatetime64[ns]
Time deltasTimedeltaTimedeltaIndextimedelta64[ns]
Time spansPeriodPeriodIndexperiod[freq]
Date offsetsDateOffsetNoneNone
1.Timedelta生成
1.通过pd.Timedelta来构造

时间差可以理解为两个时间戳的差,这里也可以通过pd.Timedelta来构造:
通过Timestamp构建时间差Timedelta

import numpy as np
import pandas as pd
pd.Timestamp('20220102 08:00:00')-pd.Timestamp('20220101 07:35:00')

输出为:

Timedelta('1 days 00:25:00')

通过Timedelta生成

pd.Timedelta(days=1, minutes=25) # 需要注意加s
# pd.Timedelta('1 days 25 minutes') # 字符串生成 同上一样

输出:

Timedelta('1 days 00:25:00')
2 to_timedelta生成

to_timedelta生成-精确到 20.5us

# 精确到 20.5us
pd.to_timedelta('20.5us')

输出为:

Timedelta('0 days 00:00:00.000020500')

to_timedelta生成-构建一个Timedelta序列

pd.to_timedelta(['2 days 04:06:10.00006', '15.5us', 'nan'])

输出为:

TimedeltaIndex(['2 days 04:06:10.000060', '0 days 00:00:00.000015500', NaT], dtype='timedelta64[ns]', freq=None)

to_timedelta生成-指定单位

pd.to_timedelta(np.arange(6), unit='d')

输出为:

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来生成,它们两者具有一致的参数:

import numpy as np
import pandas as pd
pd.timedelta_range(start='2 day', periods=5, freq='6H', closed='right')

输出为:

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的运算

时间差支持的常用运算有三类:与标量的乘法运算、与时间戳的加减法运算、与时间差的加减法与除法运算:

# 初始化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')

时间差序列计算:

# 定义时间差
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'],
     

时间差序列与标量计算:

td1 * 5
# TimedeltaIndex(['5 days', '10 days', '15 days', '20 days', '25 days'], dtype='timedelta64[ns]', freq='5D')

输出为:

TimedeltaIndex(['5 days', '10 days', '15 days', '20 days', '25 days'], dtype='timedelta64[ns]', freq='5D')

时间差序列与series计算

td1 * pd.Series(list(range(5))) # 逐个相乘

输出为:

0    0 days
1    2 days
2    6 days
3   12 days
4   20 days
dtype: timedelta64[ns]

时间差序列直接计算

td1 - td2

输出为:

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)

时间差序列与时间戳计算:

td1 + pd.Timestamp('20200101')

输出为:

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 timesTimestampDatetimeIndexdatetime64[ns]
Time deltasTimedeltaTimedeltaIndextimedelta64[ns]
Time spansPeriodPeriodIndexperiod[freq]
Date offsetsDateOffsetNoneNone
1. 通过Period生成
# 生成一个以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)

输出为:

2022-01 <class 'pandas._libs.tslibs.period.Period'>
period_d + 1的结果为: 2022-02
period_d - 2的结果为: 2021-11
2021
2. 通过period_range方法生成
# 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

输出为:

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

ts = pd.Series(np.arange(len(prng)), index = prng)
print(ts,type(ts))
print(ts.index)
# 时间序列

输出为:

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

输出为:

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 相互转换

时间戳与时期之间的转换

时间戳转时间段

# 时间戳与时期之间的转换: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'>

输出为:

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)

时间段转时间戳

# 每月,转化为每月第一天
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 timesTimestampDatetimeIndexdatetime64[ns]
Time deltasTimedeltaTimedeltaIndextimedelta64[ns]
Time spansPeriodPeriodIndexperiod[freq]
Date offsetsDateOffsetNoneNone

Offset对象
日期偏置是一种和日历相关的特殊时间差,例如回到第一节中的两个问题:如何求2020年9月第一个周一的日期,以及如何求2020年9月7日后的第30个工作日是哪一天。
求下一个月的第几周的周几,week=0表示为第1周,weekday=0表示为周日

# week=0表示为第1周,weekday=0表示为周日
pd.Timestamp('20220905') + pd.offsets.WeekOfMonth(week=0,weekday=0)

输出为:

Timestamp('2022-10-03 00:00:00')

偏移30天

pd.Timestamp('20220907') + pd.offsets.BDay(30)

输出为:

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指标可以如下写出:

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

输出为:

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
r = s.rolling('30D')
r

输出为:

Rolling [window=2592000000000000,min_periods=1,center=False,win_type=freq,axis=0]

可视化:

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单位进行滑动:

s.shift(freq='1D')

输出为:
在这里插入图片描述

2.重采样

重采样对象resample和分组对象groupby的用法类似,前者是针对时间序列的分组计算而设计的分组对象。

例如,对上面的序列计算每个月的均值:

s.resample('1M').mean()

输出为:

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
s1 = s.copy()
s1.index = s_month
s1

输出为:

1     -1
1     -2
1     -1
1     -1
1     -2
      ..
12    17
12    18
12    19
12    19
12    18
Length: 262, dtype: int32

采用分组的办法求均值

s1.reset_index().groupby(by='index').mean()

输出为:


同时,如果没有内置定义的处理函数,可以通过apply方法自定义:

s.resample('1M').apply(lambda x:x.max()-x.min()) # 极差

输出为

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IT从业者张某某

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值