• pandas教程:Date Ranges, Frequencies, and Shifting 日期范围,频度,和位移


    11.3 Date Ranges, Frequencies, and Shifting(日期范围,频度,和位移)

    普通的时间序列通常是不规律的,但我们希望能有一个固定的频度,比如每天,每月,或没15分钟,即使有一些缺失值也没关系。幸运的是,pandas中有一套方法和工具来进行重采样,推断频度,并生成固定频度的日期范围。例如,我们可以把样本时间序列变为固定按日的频度,需要调用resample

    import pandas as pd
    import numpy as np
    from datetime import datetime
    
    
    dates = [datetime(2011, 1, 2), datetime(2011, 1, 5),
             datetime(2011, 1, 7), datetime(2011, 1, 8), 
             datetime(2011, 1, 10), datetime(2011, 1, 12)]
    
    ts = pd.Series(np.random.randn(6), index=dates)
    ts
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    2011-01-02    2.005739
    2011-01-05   -0.265967
    2011-01-07   -0.353966
    2011-01-08   -0.646626
    2011-01-10    1.599440
    2011-01-12   -0.407854
    dtype: float64
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    resampler = ts.resample('D')
    
    • 1

    这里的’D’表示按日的频度(daily frequency)。

    关于频度(frequency)和重采样(resampling)的转换,会在11.6进行具体介绍,这里我们展示一些基本的用法。

    1 Generating Date Ranges(生成日期范围)

    之前虽然用过,但没有做解释,其实pandas.date_range是用来生成DatetimeIndex的,使用时要根据频度来指明长度:

    index = pd.date_range('2012-04-01', '2012-06-01')
    index
    
    • 1
    • 2
    DatetimeIndex(['2012-04-01', '2012-04-02', '2012-04-03', '2012-04-04',
                   '2012-04-05', '2012-04-06', '2012-04-07', '2012-04-08',
                   '2012-04-09', '2012-04-10', '2012-04-11', '2012-04-12',
                   '2012-04-13', '2012-04-14', '2012-04-15', '2012-04-16',
                   '2012-04-17', '2012-04-18', '2012-04-19', '2012-04-20',
                   '2012-04-21', '2012-04-22', '2012-04-23', '2012-04-24',
                   '2012-04-25', '2012-04-26', '2012-04-27', '2012-04-28',
                   '2012-04-29', '2012-04-30', '2012-05-01', '2012-05-02',
                   '2012-05-03', '2012-05-04', '2012-05-05', '2012-05-06',
                   '2012-05-07', '2012-05-08', '2012-05-09', '2012-05-10',
                   '2012-05-11', '2012-05-12', '2012-05-13', '2012-05-14',
                   '2012-05-15', '2012-05-16', '2012-05-17', '2012-05-18',
                   '2012-05-19', '2012-05-20', '2012-05-21', '2012-05-22',
                   '2012-05-23', '2012-05-24', '2012-05-25', '2012-05-26',
                   '2012-05-27', '2012-05-28', '2012-05-29', '2012-05-30',
                   '2012-05-31', '2012-06-01'],
                  dtype='datetime64[ns]', freq='D')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    默认,date_range会生成按日频度的时间戳。如果我们只传入一个开始或一个结束时间,还必须传入一个数字来表示时期:

    pd.date_range(start='2012-04-01', periods=20)
    
    • 1
    DatetimeIndex(['2012-04-01', '2012-04-02', '2012-04-03', '2012-04-04',
                   '2012-04-05', '2012-04-06', '2012-04-07', '2012-04-08',
                   '2012-04-09', '2012-04-10', '2012-04-11', '2012-04-12',
                   '2012-04-13', '2012-04-14', '2012-04-15', '2012-04-16',
                   '2012-04-17', '2012-04-18', '2012-04-19', '2012-04-20'],
                  dtype='datetime64[ns]', freq='D')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    pd.date_range(end='2012-06-01', periods=20)
    
    • 1
    DatetimeIndex(['2012-05-13', '2012-05-14', '2012-05-15', '2012-05-16',
                   '2012-05-17', '2012-05-18', '2012-05-19', '2012-05-20',
                   '2012-05-21', '2012-05-22', '2012-05-23', '2012-05-24',
                   '2012-05-25', '2012-05-26', '2012-05-27', '2012-05-28',
                   '2012-05-29', '2012-05-30', '2012-05-31', '2012-06-01'],
                  dtype='datetime64[ns]', freq='D')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    开始和结束的日期,严格指定了用于生成日期索引(date index)的边界。例如,如果我们希望日期索引包含每个月的最后一个工作日,我们要设定频度为’BM’(business end of month,每个月的最后一个工作日,更多频度可以看下面的表格),而且只有在这个日期范围内的日期会被包含进去:

    pd.date_range('2000-01-01', '2000-12-01', freq='BM')
    
    • 1
    DatetimeIndex(['2000-01-31', '2000-02-29', '2000-03-31', '2000-04-28',
                   '2000-05-31', '2000-06-30', '2000-07-31', '2000-08-31',
                   '2000-09-29', '2000-10-31', '2000-11-30'],
                  dtype='datetime64[ns]', freq='BM')
    
    • 1
    • 2
    • 3
    • 4

    date_range会默认保留开始或结束的时间戳:

    pd.date_range('2012-05-02 12:56:31', periods=5)
    
    • 1
    DatetimeIndex(['2012-05-02 12:56:31', '2012-05-03 12:56:31',
                   '2012-05-04 12:56:31', '2012-05-05 12:56:31',
                   '2012-05-06 12:56:31'],
                  dtype='datetime64[ns]', freq='D')
    
    • 1
    • 2
    • 3
    • 4

    有些时候我们的时间序列数据带有小时,分,秒这样的信息,但我们想要让这些时间戳全部归一化到午夜(normalized to midnight, 即晚上0点),这个时候要用到normalize选项:

    nor_date = pd.date_range('2012-05-02 12:56:31', periods=5, normalize=True)
    nor_date
    
    • 1
    • 2
    DatetimeIndex(['2012-05-02', '2012-05-03', '2012-05-04', '2012-05-05',
                   '2012-05-06'],
                  dtype='datetime64[ns]', freq='D')
    
    • 1
    • 2
    • 3
    nor_date[0]
    
    • 1
    Timestamp('2012-05-02 00:00:00', offset='D')
    
    • 1

    可以看到小时,分,秒全部变为0

    2 Frequencies and Date Offsets(频度和日期偏移)

    pandas中的频度由一个基本频度(base frequency)和一个乘法器(multiplier)组成。基本频度通常用一个字符串别名(string alias)来代表,比如’M’表示月,'H’表示小时。对每一个基本频度,还有一个被称之为日期偏移(date offset)的对象。例如,小时频度能用Hour类来表示:

    from pandas.tseries.offsets import Hour, Minute
    
    • 1
    hour = Hour()
    hour
    
    • 1
    • 2
    
    
    • 1

    通过传入一个整数,我们可以定义一个乘以偏移的乘法(a multiple of an offset):

    four_hours = Hour(4)
    four_hours
    
    • 1
    • 2
    <4 * Hours>
    
    • 1

    在很多情况下,我们不需要创建这些对象,而是使用字符串别名,比如’H’或’4H’。在频度前加一个整数,就能作为一个乘法器:

    pd.date_range('2000-01-01', '2000-01-03 23:59', freq='4H')
    
    • 1
    DatetimeIndex(['2000-01-01 00:00:00', '2000-01-01 04:00:00',
                   '2000-01-01 08:00:00', '2000-01-01 12:00:00',
                   '2000-01-01 16:00:00', '2000-01-01 20:00:00',
                   '2000-01-02 00:00:00', '2000-01-02 04:00:00',
                   '2000-01-02 08:00:00', '2000-01-02 12:00:00',
                   '2000-01-02 16:00:00', '2000-01-02 20:00:00',
                   '2000-01-03 00:00:00', '2000-01-03 04:00:00',
                   '2000-01-03 08:00:00', '2000-01-03 12:00:00',
                   '2000-01-03 16:00:00', '2000-01-03 20:00:00'],
                  dtype='datetime64[ns]', freq='4H')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    很多偏移(offset)还能和加法结合:

    Hour(2) + Minute(30)
    
    • 1
    <150 * Minutes>
    
    • 1

    同样的,我们可以传入频度字符串,比如’1h30min’,这种表达也能被解析:

    pd.date_range('2000-01-01', periods=10, freq='1h30min')
    
    • 1
    DatetimeIndex(['2000-01-01 00:00:00', '2000-01-01 01:30:00',
                   '2000-01-01 03:00:00', '2000-01-01 04:30:00',
                   '2000-01-01 06:00:00', '2000-01-01 07:30:00',
                   '2000-01-01 09:00:00', '2000-01-01 10:30:00',
                   '2000-01-01 12:00:00', '2000-01-01 13:30:00'],
                  dtype='datetime64[ns]', freq='90T')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    Week of month dates(月中的第几周日期)

    一个有用的类(class)是月中的第几周(Week of month),用WOM表示。丽日我们想得到每个月的第三个星期五:

    rng = pd.date_range('2012-01-01', '2012-09-01', freq='WOM-3FRI')
    rng
    
    • 1
    • 2
    DatetimeIndex(['2012-01-20', '2012-02-17', '2012-03-16', '2012-04-20',
                   '2012-05-18', '2012-06-15', '2012-07-20', '2012-08-17'],
                  dtype='datetime64[ns]', freq='WOM-3FRI')
    
    • 1
    • 2
    • 3
    list(rng)
    
    • 1
    [Timestamp('2012-01-20 00:00:00', offset='WOM-3FRI'),
     Timestamp('2012-02-17 00:00:00', offset='WOM-3FRI'),
     Timestamp('2012-03-16 00:00:00', offset='WOM-3FRI'),
     Timestamp('2012-04-20 00:00:00', offset='WOM-3FRI'),
     Timestamp('2012-05-18 00:00:00', offset='WOM-3FRI'),
     Timestamp('2012-06-15 00:00:00', offset='WOM-3FRI'),
     Timestamp('2012-07-20 00:00:00', offset='WOM-3FRI'),
     Timestamp('2012-08-17 00:00:00', offset='WOM-3FRI')]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    3 Shifting (Leading and Lagging) Data (偏移(提前与推后)数据)

    偏移(shifting)表示按照时间把数据向前或向后推移。SeriesDataFrame都有一个shift方法实现偏移,索引(index)不会被更改:

    ts = pd.Series(np.random.randn(4),
                   index=pd.date_range('1/1/2000', periods=4, freq='M'))
    ts
    
    • 1
    • 2
    • 3
    2000-01-31   -0.050276
    2000-02-29    0.080201
    2000-03-31    1.548324
    2000-04-30    0.510664
    Freq: M, dtype: float64
    
    • 1
    • 2
    • 3
    • 4
    • 5
    ts.shift(2)
    
    • 1
    2000-01-31         NaN
    2000-02-29         NaN
    2000-03-31   -0.050276
    2000-04-30    0.080201
    Freq: M, dtype: float64
    
    • 1
    • 2
    • 3
    • 4
    • 5
    ts.shift(-2)
    
    • 1
    2000-01-31    1.548324
    2000-02-29    0.510664
    2000-03-31         NaN
    2000-04-30         NaN
    Freq: M, dtype: float64
    
    • 1
    • 2
    • 3
    • 4
    • 5

    当我们进行位移的时候,就像上面这样会引入缺失值。

    shift的一个普通的用法是计算时间序列的百分比变化,可以表示为:

    ts / ts.shift(1) - 1
    
    • 1
    2000-01-31          NaN
    2000-02-29    -2.595227
    2000-03-31    18.305554
    2000-04-30    -0.670183
    Freq: M, dtype: float64
    
    • 1
    • 2
    • 3
    • 4
    • 5

    因为普通的shift不会对index进行修改,一些数据会被丢弃。因此如果频度是已知的,可以把频度传递给shift,这样的话时间戳会自动变化:

    ts
    
    • 1
    2000-01-31   -0.050276
    2000-02-29    0.080201
    2000-03-31    1.548324
    2000-04-30    0.510664
    Freq: M, dtype: float64
    
    • 1
    • 2
    • 3
    • 4
    • 5
    ts.shift(2)
    
    • 1
    2000-01-31         NaN
    2000-02-29         NaN
    2000-03-31   -0.050276
    2000-04-30    0.080201
    Freq: M, dtype: float64
    
    • 1
    • 2
    • 3
    • 4
    • 5
    ts.shift(2, freq='M')
    
    • 1
    2000-03-31   -0.050276
    2000-04-30    0.080201
    2000-05-31    1.548324
    2000-06-30    0.510664
    Freq: M, dtype: float64
    
    • 1
    • 2
    • 3
    • 4
    • 5

    其他一些频度也可以导入,能让我们前后移动数据:

    ts.shift(3, freq='D')
    
    • 1
    2000-02-03   -0.050276
    2000-03-03    0.080201
    2000-04-03    1.548324
    2000-05-03    0.510664
    dtype: float64
    
    • 1
    • 2
    • 3
    • 4
    • 5
    ts.shift(1, freq='90T')
    
    • 1
    2000-01-31 01:30:00   -0.050276
    2000-02-29 01:30:00    0.080201
    2000-03-31 01:30:00    1.548324
    2000-04-30 01:30:00    0.510664
    Freq: M, dtype: float64
    
    • 1
    • 2
    • 3
    • 4
    • 5

    T表示分钟。

    Shifting dates with offsets(用偏移量来移动日期)

    pandas的日期偏移(date offset)能被用于datetimeTimestamp对象:

    from pandas.tseries.offsets import Day, MonthEnd
    
    • 1
    now = datetime(2011, 11, 17)
    
    • 1
    now + 3 * Day()
    
    • 1
    Timestamp('2011-11-20 00:00:00')
    
    • 1

    如果我们添加一个像MonthEnd这样的anchored offset(依附偏移;锚点位置),日期会根据频度规则进行递增:

    now + MonthEnd()
    
    • 1
    Timestamp('2011-11-30 00:00:00')
    
    • 1
    now + MonthEnd(2)
    
    • 1
    Timestamp('2011-12-31 00:00:00')
    
    • 1

    依附偏移可以让日期向前或向后滚动,利用rollforwardrollback方法:

    offset = MonthEnd()
    
    • 1
    offset.rollforward(now)
    
    • 1
    Timestamp('2011-11-30 00:00:00')
    
    • 1
    offset.rollback(now)
    
    • 1
    Timestamp('2011-10-31 00:00:00')
    
    • 1

    一个比较创造性的日期偏移(date offset)用法是配合groupby一起用:

    ts = pd.Series(np.random.randn(20),
                   index=pd.date_range('1/15/2000', periods=20, freq='4d'))
    ts
    
    • 1
    • 2
    • 3
    2000-01-15    0.362927
    2000-01-19   -1.107020
    2000-01-23   -0.629370
    2000-01-27   -0.730651
    2000-01-31    0.251607
    2000-02-04    0.002611
    2000-02-08   -0.049611
    2000-02-12   -0.170408
    2000-02-16   -1.512385
    2000-02-20    1.335117
    2000-02-24   -0.393943
    2000-02-28    0.087478
    2000-03-03    0.441593
    2000-03-07   -0.940983
    2000-03-11   -1.399163
    2000-03-15    0.901478
    2000-03-19    0.392408
    2000-03-23   -0.512613
    2000-03-27    0.026952
    2000-03-31    1.200684
    Freq: 4D, dtype: float64
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    ts.groupby(offset.rollforward).mean()
    
    • 1
    2000-01-31   -0.370501
    2000-02-29   -0.100163
    2000-03-31    0.013794
    dtype: float64
    
    • 1
    • 2
    • 3
    • 4

    一个简单且快捷的方式是用resample(11.6会进行更详细的介绍):

    ts.resample('M').mean()
    
    • 1
    2000-01-31   -0.370501
    2000-02-29   -0.100163
    2000-03-31    0.013794
    Freq: M, dtype: float64
    
    • 1
    • 2
    • 3
    • 4
  • 相关阅读:
    第三章:Qt Creator 之 3.1 Qt Creator特色
    USB设备枚举
    [ 常用工具篇 ] 解决 kali 下载速度软件慢的问题 -- kali换源
    【图书阅读】《Aditya Bhargava-算法图解:像小说一样有趣的算法入门书》
    windows10家庭版如何开启组策略/地平线4Teredo服务器限定
    Kafka分区策略
    HCIE-storage-lab 考试注意事项,实验考试细节及问题等
    【web前端开发】数据库MySQL在开发环境的操作
    S7-1500 PLC之间进行TCP通信的具体方法和步骤详解(图文)
    NoSQL 数据库之redis键值设计、批处理优化、服务端优化、集群配置优化
  • 原文地址:https://blog.csdn.net/weixin_46530492/article/details/134487563