• 数据导入与预处理-拓展-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')
    
    • 1
    • 2
    • 3

    输出为:

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

    通过Timedelta生成

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

    输出:

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

    to_timedelta生成-精确到 20.5us

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

    输出为:

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

    to_timedelta生成-构建一个Timedelta序列

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

    输出为:

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

    to_timedelta生成-指定单位

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

    输出为:

    TimedeltaIndex(['0 days', '1 days', '2 days', '3 days', '4 days', '5 days'], dtype='timedelta64[ns]', freq=None)
    
    • 1
    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')
    
    • 1
    • 2
    • 3

    输出为:

    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')
    
    • 1
    • 2
    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')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    时间差序列计算:

    # 定义时间差
    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'],
         
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    时间差序列与标量计算:

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

    输出为:

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

    时间差序列与series计算

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

    输出为:

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

    时间差序列直接计算

    td1 - td2
    
    • 1

    输出为:

    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)
    
    • 1
    • 2
    • 3

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

    td1 + pd.Timestamp('20200101')
    
    • 1

    输出为:

    DatetimeIndex(['2020-01-02', '2020-01-03', '2020-01-04', '2020-01-05',
                   '2020-01-06'],
                  dtype='datetime64[ns]', freq='D')
    
    • 1
    • 2
    • 3

    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)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    输出为:

    2022-01 <class 'pandas._libs.tslibs.period.Period'>
    period_d + 1的结果为: 2022-02
    period_d - 2的结果为: 2021-11
    2021
    
    • 1
    • 2
    • 3
    • 4
    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
    
    • 1
    • 2
    • 3
    • 4
    • 5

    输出为:

    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'>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    构建series,指定索引为PeriodIndex

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

    输出为:

    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')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    输出为:

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    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))
    #  
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    输出为:

    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)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 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))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    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)
    
    • 1
    • 2

    输出为:

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

    偏移30天

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

    输出为:

    Timestamp('2022-10-19 00:00:00')
    
    • 1

    常用的日期偏置如下可以查阅这里的文档描述。在文档罗列的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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    输出为:

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    r = s.rolling('30D')
    r
    
    • 1
    • 2

    输出为:

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

    可视化:

    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()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

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

    对于shift函数而言,作用在datetime64为索引的序列上时,可以指定freq单位进行滑动:

    s.shift(freq='1D')
    
    • 1

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

    2.重采样

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

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

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

    输出为:

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    s1 = s.copy()
    s1.index = s_month
    s1
    
    • 1
    • 2
    • 3

    输出为:

    1     -1
    1     -2
    1     -1
    1     -1
    1     -2
          ..
    12    17
    12    18
    12    19
    12    19
    12    18
    Length: 262, dtype: int32
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    采用分组的办法求均值

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

    输出为:


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

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

    输出为

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    在resample中要特别注意组边界值的处理情况,默认情况下起始值的计算方法是从最小值时间戳对应日期的午夜00:00:00开始增加freq,直到不超过该最小时间戳的最大时间戳,由此对应的时间戳为起始值,然后每次累加freq参数作为分割结点进行分组,区间情况为左闭右开。

    基本知识描述完毕,系列博文中提供一个对应的案例,见系列文章3

  • 相关阅读:
    Talk | 清华大学陈晓宇&苏黎世联邦理工黄嘉伟 :基于实际应用的强化学习
    API接口文档1688阿里巴巴获取跨境属性数据
    脚本自动更新、关闭、启动服务器【BAT、SHELL、SVN,NPM】
    毕业设计 基于单片机的交通安全车辆测速系统 - 嵌入式 物联网
    【MySQL从入门到精通】【高级篇】(三)MySQL用户的创建_修改_删除以及密码的设置
    C语言内存函数
    CAS部署使用以及登录成功跳转地址
    linux系统编程 (四) gdb调试与makefile
    VMware认证考试科目及课程内容
    tensorflow的tensor
  • 原文地址:https://blog.csdn.net/m0_38139250/article/details/127456806