# Python 数据分析三剑客之 Pandas（九）：时间序列

TRHX

2020-06-25

Python 数据分析 / Pandas

字数统计:

9,987字

阅读时长≈

51分

Pandas 系列文章：

- Python 数据分析三剑客之 Pandas（一）：认识 Pandas 及其 Series、DataFrame 对象
- Python 数据分析三剑客之 Pandas（二）：Index 索引对象以及各种索引操作
- Python 数据分析三剑客之 Pandas（三）：算术运算与缺失值的处理
- Python 数据分析三剑客之 Pandas（四）：函数应用、映射、排序和层级索引
- Python 数据分析三剑客之 Pandas（五）：统计计算与统计描述
- Python 数据分析三剑客之 Pandas（六）：GroupBy 数据分裂、应用与合并
- Python 数据分析三剑客之 Pandas（七）：合并数据集
- Python 数据分析三剑客之 Pandas（八）：数据重塑、重复数据处理与数据替换
- Python 数据分析三剑客之 Pandas（九）：时间序列
- Python 数据分析三剑客之 Pandas（十）：数据读写

专栏：

【NumPy 专栏】【Pandas 专栏】【Matplotlib 专栏】

推荐学习资料与网站：

【NumPy 中文网】【Pandas 中文网】【Matplotlib 中文网】【NumPy、Matplotlib、Pandas 速查表】

    1
    2
    3
    4
    5

    这里是一段防爬虫文本，请读者忽略。
    本文原创首发于 CSDN，作者 TRHX。
    博客首页：https://itrhx.blog.csdn.net/
    本文链接：https://itrhx.blog.csdn.net/article/details/106947061
    未经授权，禁止转载！恶意转载，后果自负！尊重原创，远离剽窃！

## 【01x00】时间序列

官网对于时间序列的介绍：https://pandas.pydata.org/pandas-docs/stable/user_guide/timeseries.html

时间序列（time series）是一种重要的结构化数据形式，应用于多个领域，包括金融学、经济学、生态学、神经科学、物理学等。在多个时间点观察或测量到的任何事物都可以形成一段时间序列。很多时间序列是固定频率的，也就是说，数据点是根据某种规律定期出现的（比如每15秒、每5分钟、每月出现一次）。时间序列也可以是不定期的，没有固定的时间单位或单位之间的偏移量。时间序列数据的意义取决于具体的应用场景，主要有以下几种：

- 时间戳（timestamp），表示某个具体的时间点，例如 2020-6-24 15:30；
- 固定周期（period），表示某个时间周期，例如 2020-01；
- 时间间隔（timedelta），持续时间，即两个日期或时间之间的差异。
- 针对时间戳数据，Pandas 提供了 Timestamp 类型。它本质上是 Python 的原生 datetime 类型的替代品，但是在性能更好的 numpy.datetime64 类型的基础上创建。对应的索引数据结构是 DatetimeIndex。
- 针对时间周期数据，Pandas 提供了 Period 类型。这是利用 numpy.datetime64 类型将固定频率的时间间隔进行编码。对应的索引数据结构是 PeriodIndex。
- 针对时间增量或持续时间，Pandas 提供了 Timedelta 类型。Timedelta 是一种代替 Python 原生datetime.timedelta 类型的高性能数据结构，同样是基于 numpy.timedelta64 类型。对应的索引数据结构是 TimedeltaIndex。

## 【02x00】Timestamp 时间戳

### 【02x01】pandas.Timestamp

在 pandas 中，`pandas.Timestamp` 方法用来代替 Python 中的 `datetime.datetime` 方法。

Timestamp 与 Python 的 Datetime 等效，在大多数情况下都可以互换。 此类型用于组成 DatetimeIndex 以及 Pandas 中其他面向时间序列的数据结构。

官方文档：https://pandas.pydata.org/docs/reference/api/pandas.Timestamp.html

基本语法：

    1
    2
    3
    4
    5

    class pandas.Timestamp(ts_input=<object object>,
    					   freq=None, tz=None, unit=None,
    					   year=None, month=None, day=None,
    					   hour=None, minute=None, second=None,
    					   microsecond=None, nanosecond=None, tzinfo=None)

常用参数：

参数 | 描述
--- | ---
ts_input | 要转换为时间戳的对象，可以是 datetime-like，str，int，float 类型
freq | 时间戳将具有的偏移量，可以是 str，日期偏移量类型，取值参见【02x02】freq 频率部分取值
tz | 时间戳将具有的时区
unit | 如果 ts_input 是整数或浮点数，该参数用于设置其单位（D、s、ms、us、ns）

简单示例：

    1
    2
    3

    >>> import pandas as pd
    >>> pd.Timestamp('2017-01-01T12')
    Timestamp('2017-01-01 12:00:00')

设置 `unit='s'`，即待转换对象单位为秒：

    1
    2
    3

    >>> import pandas as pd
    >>> pd.Timestamp(1513393355.5, unit='s')
    Timestamp('2017-12-16 03:02:35.500000')

使用 `tz` 参数设置时区：

    1
    2
    3

    >>> import pandas as pd
    >>> pd.Timestamp(1513393355, unit='s', tz='US/Pacific')
    Timestamp('2017-12-15 19:02:35-0800', tz='US/Pacific')

单独设置年月日：

    1
    2
    3

    >>> import pandas as pd
    >>> pd.Timestamp(year=2020, month=6, day=24, hour=12)
    Timestamp('2020-06-24 12:00:00')

### 【02x02】freq 频率部分取值

完整取值参见官方文档：https://pandas.pydata.org/docs/user_guide/timeseries.html#timeseries-offset-aliases

参数 | 类型 | 描述
--- | --- | ---
D | Day | 每日历日
B | BusinessDay | 每工作日
H | Hour | 每小时
T 或 min | Minute | 每分
S | Second | 每秒
L 或 ms | Milli | 每毫秒（即每千分之一秒）
U | Micro | 每微秒（即每百万分之一秒）
M | MonthEnd | 每月最后一个日历日
BM | BusinessMonthEnd | 每月最后一个工作日
MS | MonthBegin | 每月第一个日历日
BMS | BusinessMonthBegin | 每月第一个工作日
W-MON、W-TUE… | Week | 从指定的星期几（MON、TUE、 WED、THU、FR、SAT、SUN）开始算起，每周
WoM-1MON、WOM-2MON… | WeekOfMonth | 产生每月第一、第二、第三或第四周的星期几。例如，WoM-3FRI 表示每月第3个星期五
Q-JAN、Q-FEB… | QuarterEnd | 对于以指定月份（JAN、FEB、MAR、APR、MAY、JUN、JUL、AUG、SEP、OCT、NOV、DEC）结束的年度，每季度最后一月的最后个日历日
BQ-JAN、BQ-FEB… | BusinessQuarterEnd | 对于以指定月份结束的年度，每季度最后一月的最后一个工作日
QS-JAN、QS-FEB… | QuarterBegin | 对于以指定月份结束的年度，每季度最后一月的第一个日历日
BQS-JAN、 BQS-FEB… | BusinessQuarterBegin | 对于以指定月份结束的年度，每季度最后一月的第一个工作日
A-JAN、A-FEB… | YearEnd | 每年指定月份（JAN、FEB、MAR、APR、MAY、JUN、JUL、AUG、SEP、 OCT、NOV、DEC）的最后一个日历日
BA-JAN、BA-FEB… | BusinessYearEnd | 每年指定月份的最后一个工作日
AS-JAN、AS-FEB… | YearBegin | 每年指定月份的第一个历日日
BAS-JAN、BAS-FEB… | BusinessYearBegin | 每年指定月份的第一个工作日

### 【02x03】to_datetime

在 Python 中，datetime 库提供了日期和时间处理方法，利用 `str` 或 `strftime` 方法可以将 datetime 对象转化成字符串，具体用法可参见【Python 标准库学习】日期和时间处理库 — datetime。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

    >>> from datetime import datetime
    >>> stamp = datetime(2020, 6, 24)
    >>> stamp
    datetime.datetime(2020, 6, 24, 0, 0)
    >>>
    >>> str(stamp)
    '2020-06-24 00:00:00'
    >>>
    >>> stamp.strftime('%Y-%m-%d')
    '2020-06-24'

在 pandas 中 to_datetime 方法可以将字符串解析成多种不同的 Timestamp（时间戳） 对象：

    1
    2
    3
    4
    5
    6
    7

    >>> import pandas as pd
    >>> datestrs = '2011-07-06 12:00:00'
    >>> type(datestrs)
    <class 'str'>
    >>>
    >>> pd.to_datetime(datestrs)
    Timestamp('2011-07-06 12:00:00')

基本语法：

    1
    2
    3
    4

    pandas.to_datetime(arg, errors='raise', dayfirst=False,
    				   yearfirst=False, utc=None, format=None,
    				   exact=True, unit=None, infer_datetime_format=False,
    				   origin='unix', cache=True)

官方文档：https://pandas.pydata.org/docs/reference/api/pandas.to_datetime.html

常用参数：

参数 | 描述
--- | ---
arg | 要转换为日期时间的对象，可以接受 int, float, str, datetime, list, tuple, 1-d array, Series DataFrame/dict-like 类型
errors | 如果字符串不满足时间戳的形式，是否会发生异常 `ignore`：不引发异常，返回原始输入；`raise`：无效解析将引发异常（默认）；`coerce`：无效解析将被设置为NaT
dayfirst | bool 类型，默认 False，如果 arg 是 str 或列表，是否首先解析为日期 例如 dayfirst 为 True，`10/11/12` 被解析为 `2012-11-10`，为 False 则解析为 `2012-10-11`
yearfirst | bool 类型，默认 False，如果 arg 是 str 或列表，是否首先解析为年份 例如 dayfirst 为 True，`10/11/12` 被解析为 `2010-11-12`，为 False 则解析为 `2012-10-11` 如果 dayfirst 和 yearfirst 都为 True，则优先 yearfirst
utc | bool 类型，是否转换为协调世界时，默认 None
format | 格式化时间，如 `21/2/20 16:10` 使用 `%d/%m/%y %H:%M` 会被解析为 `2020-02-21 16:10:00` 符号含义常见文章：【Python 标准库学习】日期和时间处理库 — datetime 或者官方文档
exact | 如果为 True，则需要精确的格式匹配。如果为 False，则允许格式与目标字符串中的任何位置匹配
unit | 如果 arg 是整数或浮点数，该参数用于设置其单位（D、s、ms、us、ns）

简单应用：

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

    >>> import pandas as pd
    >>> obj = pd.DataFrame({'year': [2015, 2016], 'month': [2, 3], 'day': [4, 5]})
    >>> obj
       year  month  day
    0  2015      2    4
    1  2016      3    5
    >>>
    >>> pd.to_datetime(obj)
    0   2015-02-04
    1   2016-03-05
    dtype: datetime64[ns]

设置 `format` 和 `errors` 参数：

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

    >>> import pandas as pd
    >>> pd.to_datetime('13000101', format='%Y%m%d', errors='ignore')
    datetime.datetime(1300, 1, 1, 0, 0)
    >>>
    >>> pd.to_datetime('13000101', format='%Y%m%d', errors='coerce')
    NaT
    >>>
    >>> pd.to_datetime('13000101', format='%Y%m%d', errors='raise')
    Traceback (most recent call last):
    ...
    pandas._libs.tslibs.np_datetime.OutOfBoundsDatetime: Out of bounds nanosecond timestamp: 1300-01-01 00:00:00

设置 `unit` 参数：

    1
    2
    3
    4
    5
    6

    >>> import pandas as pd
    >>> pd.to_datetime(1490195805, unit='s')
    Timestamp('2017-03-22 15:16:45')
    >>>
    >>> pd.to_datetime(1490195805433502912, unit='ns')
    Timestamp('2017-03-22 15:16:45.433502912')

### 【02x04】date_range

`pandas.date_range` 方法可用于根据指定的频率生成指定长度的 DatetimeIndex。

基本语法：

    1
    2
    3

    pandas.date_range(start=None, end=None, periods=None, freq=None,
    				  tz=None, normalize=False, name=None, closed=None,
    				  **kwargs) → pandas.core.indexes.datetimes.DatetimeIndex

官方文档：https://pandas.pydata.org/docs/reference/api/pandas.date_range.html

参数 | 描述
--- | ---
start | 开始日期
end | 结束日期
periods | int 类型，要生成的时段数（天）
freq | 频率字符串，即按照某种特定的频率来生成日期，取值参见【02x02】freq 频率部分取值
tz | 设置时区，例如 “Asia/Hong_Kong”
normalize | bool 类型，默认 False，是否在生成日期之前对其进行规范化（仅保留年月日）
name | 结果 DatetimeIndex 的名称
closed | `None`：默认值，同时保留开始日期和结束日期 `'left'`：保留开始日期，不保留结束日期 `'right'`：保留结束日期，不保留开始日期

简单示例：

    1
    2
    3
    4
    5

    >>> import pandas as pd
    >>> pd.date_range(start='1/1/2018', end='1/08/2018')
    DatetimeIndex(['2018-01-01', '2018-01-02', '2018-01-03', '2018-01-04',
                   '2018-01-05', '2018-01-06', '2018-01-07', '2018-01-08'],
                  dtype='datetime64[ns]', freq='D')

指定 `periods` 参数：

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23

    >>> import pandas as pd
    >>> pd.date_range(start='2012-04-01', periods=20)
    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')
    >>>
    >>> pd.date_range(end='2012-06-01', periods=20)
    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')
    >>>
    >>> pd.date_range(start='2018-04-24', end='2018-04-27', periods=3)
    DatetimeIndex(['2018-04-24 00:00:00', '2018-04-25 12:00:00', '2018-04-27 00:00:00'],
                  dtype='datetime64[ns]', freq=None)
    >>>
    >>> pd.date_range(start='2018-04-24', end='2018-04-28', periods=3)
    DatetimeIndex(['2018-04-24', '2018-04-26', '2018-04-28'], dtype='datetime64[ns]', freq=None)

指定 `freq='M'` 会按照每月最后一个日历日的频率生成日期，指定 `freq='3M'` 会每隔3个月按照每月最后一个日历日的频率生成日期：

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

    >>> import pandas as pd
    >>> pd.date_range(start='1/1/2018', periods=5, freq='M')
    DatetimeIndex(['2018-01-31', '2018-02-28', '2018-03-31', '2018-04-30',
                   '2018-05-31'],
                  dtype='datetime64[ns]', freq='M')
    >>>
    >>> pd.date_range(start='1/1/2018', periods=5, freq='3M')
    DatetimeIndex(['2018-01-31', '2018-04-30', '2018-07-31', '2018-10-31',
                   '2019-01-31'],
                  dtype='datetime64[ns]', freq='3M')
    >>>

使用 `tz` 参数设置时区：

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12

    >>> import pandas as pd
    >>> pd.date_range(start='1/1/2018', periods=5, tz='Asia/Tokyo')
    DatetimeIndex(['2018-01-01 00:00:00+09:00', '2018-01-02 00:00:00+09:00',
                   '2018-01-03 00:00:00+09:00', '2018-01-04 00:00:00+09:00',
                   '2018-01-05 00:00:00+09:00'],
                  dtype='datetime64[ns, Asia/Tokyo]', freq='D')
    >>>
    >>> pd.date_range(start='6/24/2020', periods=5, tz='Asia/Hong_Kong')
    DatetimeIndex(['2020-06-24 00:00:00+08:00', '2020-06-25 00:00:00+08:00',
                   '2020-06-26 00:00:00+08:00', '2020-06-27 00:00:00+08:00',
                   '2020-06-28 00:00:00+08:00'],
                  dtype='datetime64[ns, Asia/Hong_Kong]', freq='D')

设置 `normalize` 参数，在生成时间戳之前对其进行格式化操作：

    1
    2
    3
    4
    5

    >>> import pandas as pd
    >>> pd.date_range('2020-06-24 12:56:31', periods=5, normalize=True)
    DatetimeIndex(['2020-06-24', '2020-06-25', '2020-06-26', '2020-06-27',
                   '2020-06-28'],
                  dtype='datetime64[ns]', freq='D')

设置 `closed` 参数：

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

    >>> import pandas as pd
    >>> pd.date_range(start='2020-06-20', end='2020-06-24', closed=None)
    DatetimeIndex(['2020-06-20', '2020-06-21', '2020-06-22', '2020-06-23',
                   '2020-06-24'],
                  dtype='datetime64[ns]', freq='D')
    >>>
    >>> pd.date_range(start='2020-06-20', end='2020-06-24', closed='left')
    DatetimeIndex(['2020-06-20', '2020-06-21', '2020-06-22', '2020-06-23'], dtype='datetime64[ns]', freq='D')
    >>>
    >>> pd.date_range(start='2020-06-20', end='2020-06-24', closed='right')
    DatetimeIndex(['2020-06-21', '2020-06-22', '2020-06-23', '2020-06-24'], dtype='datetime64[ns]', freq='D')

### 【02x05】索引与切片

Pandas 最基本的时间序列类型就是以时间戳（通常以 Python 字符串或 datatime 对象表示）为索引的Series，这些 datetime 对象实际上是被放在 DatetimeIndex 中的，可以使用类似 pandas.Series 对象的切片方法对其进行索引：

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26

    >>> import pandas as pd
    >>> import numpy as np
    >>> 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)]
    >>> obj = pd.Series(np.random.randn(6), index=dates)
    >>>
    >>> obj
    2011-01-02   -0.407110
    2011-01-05   -0.186661
    2011-01-07   -0.731080
    2011-01-08    0.860970
    2011-01-10    1.929973
    2011-01-12   -0.168599
    dtype: float64
    >>>
    >>> obj.index
    DatetimeIndex(['2011-01-02', '2011-01-05', '2011-01-07', '2011-01-08',
                   '2011-01-10', '2011-01-12'],
                  dtype='datetime64[ns]', freq=None)
    >>>
    >>> obj.index[0]
    Timestamp('2011-01-02 00:00:00')
    >>>
    >>> obj.index[0:3]
    DatetimeIndex(['2011-01-02', '2011-01-05', '2011-01-07'], dtype='datetime64[ns]', freq=None)

另外还可以传入一个可以被解释为日期的字符串，或者只需传入“年”或“年月”即可轻松选取数据的切片：

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72

    >>> import pandas as pd
    >>> import numpy as np
    >>> obj = pd.Series(np.random.randn(1000), index=pd.date_range('1/1/2000', periods=1000))
    >>> obj
    2000-01-01   -1.142284
    2000-01-02    1.198785
    2000-01-03    2.466909
    2000-01-04   -0.086728
    2000-01-05   -0.978437
                    ...
    2002-09-22   -0.252240
    2002-09-23    0.148561
    2002-09-24   -1.330409
    2002-09-25   -0.673471
    2002-09-26   -0.253271
    Freq: D, Length: 1000, dtype: float64
    >>>
    >>> obj['26/9/2002']
    -0.25327100684233356
    >>>
    >>> obj['2002']
    2002-01-01    1.058715
    2002-01-02    0.900859
    2002-01-03    1.993508
    2002-01-04   -0.103211
    2002-01-05   -0.950090
                    ...
    2002-09-22   -0.252240
    2002-09-23    0.148561
    2002-09-24   -1.330409
    2002-09-25   -0.673471
    2002-09-26   -0.253271
    Freq: D, Length: 269, dtype: float64
    >>>
    >>> obj['2002-09']
    2002-09-01   -0.995528
    2002-09-02    0.501528
    2002-09-03   -0.486753
    2002-09-04   -1.083906
    2002-09-05    1.458975
    2002-09-06   -1.331685
    2002-09-07    0.195338
    2002-09-08   -0.429613
    2002-09-09    1.125823
    2002-09-10    1.607051
    2002-09-11    0.530387
    2002-09-12   -0.015938
    2002-09-13    1.781043
    2002-09-14   -0.277123
    2002-09-15    0.344569
    2002-09-16   -1.010810
    2002-09-17    0.463001
    2002-09-18    1.883636
    2002-09-19    0.274520
    2002-09-20    0.624184
    2002-09-21   -1.203057
    2002-09-22   -0.252240
    2002-09-23    0.148561
    2002-09-24   -1.330409
    2002-09-25   -0.673471
    2002-09-26   -0.253271
    Freq: D, dtype: float64
    >>>
    >>> obj['20/9/2002':'26/9/2002']
    2002-09-20    0.624184
    2002-09-21   -1.203057
    2002-09-22   -0.252240
    2002-09-23    0.148561
    2002-09-24   -1.330409
    2002-09-25   -0.673471
    2002-09-26   -0.253271
    Freq: D, dtype: float64

### 【02x06】移动数据与数据偏移

移动（shifting）指的是沿着时间轴将数据前移或后移。Series 和 DataFrame 都有一个 shift 方法用于执行单纯的前移或后移操作，保持索引不变：

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24

    >>> import pandas as pd
    >>> import numpy as np
    >>> obj = pd.Series(np.random.randn(4),
    		    index=pd.date_range('1/1/2000', periods=4, freq='M'))
    >>> obj
    2000-01-31   -0.100217
    2000-02-29    1.177834
    2000-03-31   -0.644353
    2000-04-30   -1.954679
    Freq: M, dtype: float64
    >>>
    >>> obj.shift(2)
    2000-01-31         NaN
    2000-02-29         NaN
    2000-03-31   -0.100217
    2000-04-30    1.177834
    Freq: M, dtype: float64
    >>>
    >>> obj.shift(-2)
    2000-01-31   -0.644353
    2000-02-29   -1.954679
    2000-03-31         NaN
    2000-04-30         NaN
    Freq: M, dtype: float64

因为简单的移位操作不会修改索引，所以部分数据会被丢弃并引入 NaN（缺失值）。因此，如果频率已知，则可以将其传给 shift 以便实现对时间戳进行位移而不是对数据进行简单位移：

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17

    >>> import pandas as pd
    >>> import numpy as np
    >>> obj = pd.Series(np.random.randn(4),
    		    index=pd.date_range('1/1/2000', periods=4, freq='M'))
    >>> obj
    2000-01-31   -0.100217
    2000-02-29    1.177834
    2000-03-31   -0.644353
    2000-04-30   -1.954679
    Freq: M, dtype: float64
    >>>
    >>> obj.shift(2, freq='M')
    2000-03-31   -0.100217
    2000-04-30    1.177834
    2000-05-31   -0.644353
    2000-06-30   -1.954679
    Freq: M, dtype: float64

Pandas 中的频率是由一个基础频率（base frequency）和一个乘数组成的。基础频率通常以一个字符串别名表示，比如 `"M"` 表示每月，`"H"` 表示每小时。对于每个基础频率，都有一个被称为日期偏移量（date offset）的对象与之对应。例如，按小时计算的频率可以用 `Hour` 类表示：

    1
    2
    3
    4
    5
    6
    7
    8

    >>> from pandas.tseries.offsets import Hour, Minute
    >>> hour = Hour()
    >>> hour
    <Hour>
    >>>
    >>> four_hours = Hour(4)
    >>> four_hours
    <4 * Hours>

一般来说，无需明确创建这样的对象，只需使用诸如 `"H"` 或 `"4H"` 这样的字符串别名即可。在基础频率前面放上一个整数即可创建倍数：

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12

    >>> import pandas as pd
    >>> pd.date_range('2000-01-01', '2000-01-03 23:59', freq='4h')
    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

    >>> from pandas.tseries.offsets import Hour, Minute
    >>> Hour(2) + Minute(30)
    <150 * Minutes>

对于 `freq` 参数也可以传入频率字符串（如 `"2h30min"`），这种字符串可以被高效地解析为等效的表达式：

    1
    2
    3
    4
    5
    6
    7
    8

    >>> import pandas as pd
    >>> pd.date_range('2000-01-01', periods=10, freq='1h30min')
    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')

这种偏移量还可以用在 datetime 或 Timestamp 对象上：

    1
    2
    3
    4

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

如果加的是锚点偏移量，比如 MonthEnd，第一次增量会将原日期向前滚动到符合频率规则的下一个日期：

    1
    2
    3
    4
    5
    6

    >>> from pandas.tseries.offsets import Day, MonthEnd
    >>> now = datetime(2011, 11, 17)
    >>> now + MonthEnd()
    Timestamp('2011-11-30 00:00:00')
    >>> now + MonthEnd(2)
    Timestamp('2011-12-31 00:00:00')

通过锚点偏移量的 rollforward 和 rollback 方法，可明确地将日期向前或向后滚动：

    1
    2
    3
    4
    5
    6
    7

    >>> from pandas.tseries.offsets import Day, MonthEnd
    >>> now = datetime(2011, 11, 17)
    >>> offset = MonthEnd()
    >>> offset.rollforward(now)
    Timestamp('2011-11-30 00:00:00')
    >>> offset.rollback(now)
    Timestamp('2011-10-31 00:00:00')

与 `groupby` 方法结合使用：

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34

    >>> import pandas as pd
    >>> import numpy as np
    >>> from pandas.tseries.offsets import Day, MonthEnd
    >>> obj = pd.Series(np.random.randn(20),
    		    index=pd.date_range('1/15/2000', periods=20, freq='4d'))
    >>> obj
    2000-01-15   -0.591729
    2000-01-19   -0.775844
    2000-01-23   -0.745603
    2000-01-27   -0.076439
    2000-01-31    1.796417
    2000-02-04   -0.500349
    2000-02-08    0.515851
    2000-02-12   -0.344171
    2000-02-16    0.419657
    2000-02-20    0.307288
    2000-02-24    0.115113
    2000-02-28   -0.362585
    2000-03-03    1.074892
    2000-03-07    1.111366
    2000-03-11    0.949910
    2000-03-15   -1.535727
    2000-03-19    0.545944
    2000-03-23   -0.810139
    2000-03-27   -1.260627
    2000-03-31   -0.128403
    Freq: 4D, dtype: float64
    >>>
    >>> offset = MonthEnd()
    >>> obj.groupby(offset.rollforward).mean()
    2000-01-31   -0.078640
    2000-02-29    0.021543
    2000-03-31   -0.006598
    dtype: float64

### 【02x07】时区处理

在 Python 中，时区信息来自第三方库 pytz，使用 `pytz.common_timezones` 方法可以查看所有的时区名称，使用 `pytz.timezone` 方法从 pytz 中获取时区对象：

    1
    2
    3
    4
    5
    6
    7

    >>> import pytz
    >>> pytz.common_timezones
    ['Africa/Abidjan', 'Africa/Accra', 'Africa/Addis_Ababa', ..., 'UTC']
    >>>
    >>> tz = pytz.timezone('Asia/Shanghai')
    >>> tz
    <DstTzInfo 'Asia/Shanghai' LMT+8:06:00 STD>  # 表示与 UTC 时间相差8小时6分

在 `date_range` 方法中，`tz` 参数用于指定时区，默认为 None，可以使用 `tz_localize` 方法将其进行本地化时区转换，如下示例中，将无时区转本地化 UTC 时区：

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31

    >>> import pandas as pd
    >>> import numpy as np
    >>> rng = pd.date_range('3/9/2012 9:30', periods=6, freq='D')
    >>> ts = pd.Series(np.random.randn(len(rng)), index=rng)
    >>> ts
    2012-03-09 09:30:00   -1.527913
    2012-03-10 09:30:00   -1.116101
    2012-03-11 09:30:00    0.359358
    2012-03-12 09:30:00   -0.475920
    2012-03-13 09:30:00   -0.336570
    2012-03-14 09:30:00   -1.075952
    Freq: D, dtype: float64
    >>>
    >>> print(ts.index.tz)
    None
    >>>
    >>> ts_utc = ts.tz_localize('UTC')
    >>> ts_utc
    2012-03-09 09:30:00+00:00   -1.527913
    2012-03-10 09:30:00+00:00   -1.116101
    2012-03-11 09:30:00+00:00    0.359358
    2012-03-12 09:30:00+00:00   -0.475920
    2012-03-13 09:30:00+00:00   -0.336570
    2012-03-14 09:30:00+00:00   -1.075952
    Freq: D, dtype: float64
    >>>
    >>> ts_utc.index
    DatetimeIndex(['2012-03-09 09:30:00+00:00', '2012-03-10 09:30:00+00:00',
                   '2012-03-11 09:30:00+00:00', '2012-03-12 09:30:00+00:00',
                   '2012-03-13 09:30:00+00:00', '2012-03-14 09:30:00+00:00'],
                  dtype='datetime64[ns, UTC]', freq='D')

时间序列被本地化到某个特定时区后，就可以用 `tz_convert` 方法将其转换到别的时区了：

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21

    >>> import pandas as pd
    >>> import numpy as np
    >>> rng = pd.date_range('3/9/2012 9:30', periods=6, freq='D')
    >>> ts = pd.Series(np.random.randn(len(rng)), index=rng)
    >>> ts
    2012-03-09 09:30:00    0.480303
    2012-03-10 09:30:00   -1.461039
    2012-03-11 09:30:00   -1.512749
    2012-03-12 09:30:00   -2.185421
    2012-03-13 09:30:00    1.657845
    2012-03-14 09:30:00    0.175633
    Freq: D, dtype: float64
    >>>
    >>> ts.tz_localize('UTC').tz_convert('Asia/Shanghai')
    2012-03-09 17:30:00+08:00    0.480303
    2012-03-10 17:30:00+08:00   -1.461039
    2012-03-11 17:30:00+08:00   -1.512749
    2012-03-12 17:30:00+08:00   -2.185421
    2012-03-13 17:30:00+08:00    1.657845
    2012-03-14 17:30:00+08:00    0.175633
    Freq: D, dtype: float64

    1
    2
    3
    4
    5

    这里是一段防爬虫文本，请读者忽略。
    本文原创首发于 CSDN，作者 TRHX。
    博客首页：https://itrhx.blog.csdn.net/
    本文链接：https://itrhx.blog.csdn.net/article/details/106947061
    未经授权，禁止转载！恶意转载，后果自负！尊重原创，远离剽窃！

## 【03x00】period 固定时期

### 【03x01】pandas.Period

固定时期（period）表示的是时间区间，比如数日、数月、数季、数年等。Period 类所表示的就是这种数据类型，其构造函数需要用到一个字符串或整数。

基本语法：

    1
    2
    3

    class pandas.Period(value=None, freq=None, ordinal=None,
    					year=None, month=None, quarter=None,
    					day=None, hour=None, minute=None, second=None)

官方文档：https://pandas.pydata.org/docs/reference/api/pandas.Period.html

常用参数：

参数 | 描述
--- | ---
value | 时间段
freq | 时间戳将具有的偏移量，可以是 str，日期偏移量类型，取值参见【02x02】freq 频率部分取值

以下示例中，Period 对象表示的是从2020年1月1日到2020年12月31日之间的整段时间

    1
    2
    3

    >>> import pandas as pd
    >>> pd.Period(2020, freq='A-DEC')
    Period('2020', 'A-DEC')

利用加减法对其按照频率进行位移：

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

    >>> import pandas as pd
    >>> obj = pd.Period(2020, freq='A-DEC')
    >>> obj
    Period('2020', 'A-DEC')
    >>>
    >>> obj + 5
    Period('2025', 'A-DEC')
    >>>
    >>> obj - 5
    Period('2015', 'A-DEC')

PeriodIndex 类保存了一组 Period，它可以在任何 pandas 数据结构中被用作轴索引：

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16

    >>> import pandas as pd
    >>> import numpy as np
    >>> rng = [pd.Period('2000-01'), pd.Period('2000-02'), pd.Period('2000-03'),
    		   pd.Period('2000-04'), pd.Period('2000-05'), pd.Period('2000-06')]
    >>> obj = pd.Series(np.random.randn(6), index=rng)
    >>> obj
    2000-01    0.229092
    2000-02    1.515498
    2000-03   -0.334401
    2000-04   -0.492681
    2000-05   -2.012818
    2000-06    0.338804
    Freq: M, dtype: float64
    >>>
    >>> obj.index
    PeriodIndex(['2000-01', '2000-02', '2000-03', '2000-04', '2000-05', '2000-06'], dtype='period[M]', freq='M')

    1
    2
    3
    4
    5
    6

    >>> import pandas as pd
    >>> values = ['2001Q3', '2002Q2', '2003Q1']
    >>> index = pd.PeriodIndex(values, freq='Q-DEC')
    >>> index
    PeriodIndex(['2001Q3', '2002Q2', '2003Q1'], dtype='period[Q-DEC]', freq='Q-DEC')
    >>>

### 【03x02】period_range

`pandas.period_range` 方法可根据指定的频率生成指定长度的 PeriodIndex。

基本语法：

`pandas.period_range(start=None, end=None, periods=None, freq=None, name=None) → pandas.core.indexes.period.PeriodIndex`

官方文档：https://pandas.pydata.org/docs/reference/api/pandas.period_range.html

常用参数：

参数 | 描述
--- | ---
start | 起始日期
end | 结束日期
periods | 要生成的时段数
freq | 时间戳将具有的偏移量，可以是 str，日期偏移量类型，取值参见【02x02】freq 频率部分取值
name | 结果 PeriodIndex 对象名称

简单应用：

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

    >>> import pandas as pd
    >>> pd.period_range(start='2019-01-01', end='2020-01-01', freq='M')
    PeriodIndex(['2019-01', '2019-02', '2019-03', '2019-04', '2019-05', '2019-06',
                 '2019-07', '2019-08', '2019-09', '2019-10', '2019-11', '2019-12',
                 '2020-01'],
                dtype='period[M]', freq='M')
    >>>
    >>> pd.period_range(start=pd.Period('2017Q1', freq='Q'),
                    	end=pd.Period('2017Q2', freq='Q'), freq='M')
    PeriodIndex(['2017-03', '2017-04', '2017-05', '2017-06'], dtype='period[M]', freq='M')

### 【03x03】asfreq 时期频率转换

Period 和 PeriodIndex 对象都可以通过 asfreq 方法被转换成别的频率。

基本语法：`PeriodIndex.asfreq(self, *args, **kwargs)`

常用参数：

参数 | 描述
--- | ---
freq | 新的频率（偏移量），取值参见【02x02】freq 频率部分取值
how | 按照开始或者结束对齐，`'E'` or `'END'` or `'FINISH'`；`'S'` or `'START'` or `'BEGIN'`

应用示例：

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

    >>> import pandas as pd
    >>> pidx = pd.period_range('2010-01-01', '2015-01-01', freq='A')
    >>> pidx
    PeriodIndex(['2010', '2011', '2012', '2013', '2014', '2015'], dtype='period[A-DEC]', freq='A-DEC')
    >>>
    >>> pidx.asfreq('M')
    PeriodIndex(['2010-12', '2011-12', '2012-12', '2013-12', '2014-12', '2015-12'], dtype='period[M]', freq='M')
    >>>
    >>> pidx.asfreq('M', how='S')
    PeriodIndex(['2010-01', '2011-01', '2012-01', '2013-01', '2014-01', '2015-01'], dtype='period[M]', freq='M')

### 【03x04】to_period 与 to_timestamp()

`to_period` 方法可以将 Timestamp（时间戳） 转换为 Period（固定时期）；

`to_timestamp` 方法可以将 Period（固定时期）转换为 Timestamp（时间戳） 。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31

    >>> import pandas as pd
    >>> rng = pd.date_range('2000-01-01', periods=3, freq='M')
    >>> ts = pd.Series(np.random.randn(3), index=rng)
    >>> ts
    2000-01-31    0.220759
    2000-02-29   -0.108221
    2000-03-31    0.819433
    Freq: M, dtype: float64
    >>>
    >>> pts = ts.to_period()
    >>> pts
    2000-01    0.220759
    2000-02   -0.108221
    2000-03    0.819433
    Freq: M, dtype: float64
    >>>
    >>> pts2 = pts.to_timestamp()
    >>> pts2
    2000-01-01    0.220759
    2000-02-01   -0.108221
    2000-03-01    0.819433
    Freq: MS, dtype: float64
    >>>
    >>> ts.index
    DatetimeIndex(['2000-01-31', '2000-02-29', '2000-03-31'], dtype='datetime64[ns]', freq='M')
    >>>
    >>> pts.index
    PeriodIndex(['2000-01', '2000-02', '2000-03'], dtype='period[M]', freq='M')
    >>>
    >>> pts2.index
    DatetimeIndex(['2000-01-01', '2000-02-01', '2000-03-01'], dtype='datetime64[ns]', freq='MS')

## 【04x00】timedelta 时间间隔

### 【04x01】pandas.Timedelta

Timedelta 表示持续时间，即两个日期或时间之间的差。

Timedelta 相当于 Python 的 datetime.timedelta，在大多数情况下两者可以互换。

基本语法：`class pandas.Timedelta(value=<object object>, unit=None, **kwargs)`

官方文档：https://pandas.pydata.org/docs/reference/api/pandas.Timedelta.html

常用参数：

参数 | 描述
--- | ---
value | 传入的值，可以是 Timedelta，timedelta，np.timedelta64，string 或 integer 对象
unit | 用于设置 value 的单位，具体取值参见官方文档

表示两个 datetime 对象之间的时间差：

    1
    2
    3

    >>> import pandas as pd
    >>> pd.to_datetime('2020-6-24') - pd.to_datetime('2016-1-1')
    Timedelta('1636 days 00:00:00')

通过字符串传递参数：

    1
    2
    3

    >>> import pandas as pd
    >>> pd.Timedelta('3 days 3 hours 3 minutes 30 seconds')
    Timedelta('3 days 03:03:30')

通过整数传递参数：

    1
    2
    3

    >>> import pandas as pd
    >>> pd.Timedelta(5,unit='h')
    Timedelta('0 days 05:00:00')

获取属性：

    1
    2
    3
    4
    5
    6
    7
    8
    9

    >>> import pandas as pd
    >>> obj = pd.Timedelta('3 days 3 hours 3 minutes 30 seconds')
    >>> obj
    Timedelta('3 days 03:03:30')
    >>>
    >>> obj.days
    3
    >>> obj.seconds
    11010

### 【04x02】to_timedelta

to_timedelta 方法可以将传入的对象转换成 timedelta 对象。

基本语法：`pandas.to_timedelta(arg, unit='ns', errors='raise')`

官方文档：https://pandas.pydata.org/docs/reference/api/pandas.to_timedelta.html

常用参数：

参数 | 描述
--- | ---
arg | 要转换为 timedelta 的对象，可以是 str，timedelta，list-like 或 Series 对象
unit | 用于设置 arg 的单位，具体取值参见官方文档
errors | 如果 arg 不满足时间戳的形式，是否会发生异常 `ignore`：不引发异常，返回原始输入；`raise`：无效解析将引发异常（默认）；`coerce`：无效解析将被设置为NaT

将单个字符串解析为 timedelta 对象：

    1
    2
    3
    4
    5
    6

    >>> import pandas as pd
    >>> pd.to_timedelta('1 days 06:05:01.00003')
    Timedelta('1 days 06:05:01.000030')
    >>>
    >>> pd.to_timedelta('15.5us')
    Timedelta('0 days 00:00:00.000015')

将字符串列表或数组解析为 timedelta 对象：

    1
    2
    3

    >>> import pandas as pd
    >>> pd.to_timedelta(['1 days 06:05:01.00003', '15.5us', 'nan'])
    TimedeltaIndex(['1 days 06:05:01.000030', '0 days 00:00:00.000015', NaT], dtype='timedelta64[ns]', freq=None)

指定 `unit` 参数：

    1
    2
    3
    4
    5
    6

    >>> import pandas as pd
    >>> pd.to_timedelta(np.arange(5), unit='s')
    TimedeltaIndex(['00:00:00', '00:00:01', '00:00:02', '00:00:03', '00:00:04'], dtype='timedelta64[ns]', freq=None)
    >>>
    >>> pd.to_timedelta(np.arange(5), unit='d')
    TimedeltaIndex(['0 days', '1 days', '2 days', '3 days', '4 days'], dtype='timedelta64[ns]', freq=None)

### 【04x03】timedelta_range

`timedelta_range` 方法可根据指定的频率生成指定长度的 TimedeltaIndex。

基本语法：

    1
    2

    pandas.timedelta_range(start=None, end=None, periods=None,
    					   freq=None, name=None, closed=None) → pandas.core.indexes.timedeltas.TimedeltaIndex

官方文档：https://pandas.pydata.org/docs/reference/api/pandas.timedelta_range.html

常用参数：

参数 | 描述
--- | ---
start | 开始日期
end | 结束日期
periods | int 类型，要生成的时段数
freq | 频率字符串，即按照某种特定的频率来生成日期，取值参见【02x02】freq 频率部分取值
name | 结果 TimedeltaIndex 的名称
closed | `None`：默认值，同时保留开始日期和结束日期 `'left'`：保留开始日期，不保留结束日期 `'right'`：保留结束日期，不保留开始日期

应用示例：

    1
    2
    3

    >>> import pandas as pd
    >>> pd.timedelta_range(start='1 day', periods=4)
    TimedeltaIndex(['1 days', '2 days', '3 days', '4 days'], dtype='timedelta64[ns]', freq='D')

closed 参数指定保留哪个端点。默认保留两个端点：

    1
    2
    3

    >>> import pandas as pd
    >>> pd.timedelta_range(start='1 day', periods=4, closed='right')
    TimedeltaIndex(['2 days', '3 days', '4 days'], dtype='timedelta64[ns]', freq='D')

freq 参数指定 TimedeltaIndex 的频率。只接受固定频率，非固定频率如 `'M'` 将会报错：

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

    >>> import pandas as pd
    >>> pd.timedelta_range(start='1 day', end='2 days', freq='6H')
    TimedeltaIndex(['1 days 00:00:00', '1 days 06:00:00', '1 days 12:00:00',
                    '1 days 18:00:00', '2 days 00:00:00'],
                   dtype='timedelta64[ns]', freq='6H')
    >>>
    >>> pd.timedelta_range(start='1 day', end='2 days', freq='M')
    Traceback (most recent call last):
    ...
    ValueError: <MonthEnd> is a non-fixed frequency

## 【05x00】重采样及频率转换

重采样（resampling）指的是将时间序列从一个频率转换到另一个频率的处理过程。将高频率数据聚合到低频率称为降采样（downsampling），而将低频率数据转换到高频率则称为升采样（upsampling）。并不是所有的重采样都能被划分到这两个大类中。例如，将 W-WED（每周三）转换为 W-FRI 既不是降采样也不是升采样。

Pandas 中提供了 resample 方法来帮助我们实现重采样。Pandas 对象都带有一个 resample 方法，它是各种频率转换工作的主力函数。

基本语法：

    1
    2
    3
    4
    5
    6
    7

    Series.resample(self, rule, axis=0,
    				closed: Union[str, NoneType] = None,
    				label: Union[str, NoneType] = None,
    				convention: str = 'start',
    				kind: Union[str, NoneType] = None,
    				loffset=None, base: int = 0,
    				on=None, level=None)

    1
    2
    3
    4
    5
    6
    7

    DataFrame.resample(self, rule, axis=0,
    				   closed: Union[str, NoneType] = None,
    				   label: Union[str, NoneType] = None,
    				   convention: str = 'start',
    				   kind: Union[str, NoneType] = None,
    				   loffset=None, base: int = 0,
    				   on=None, level=None)

常用参数：

参数 | 描述
--- | ---
rule
axis | 重采样的轴，默认 0
closed | 在重采样中，各时间段的哪一端是闭合（即包含）的， 除 `'M'`、`'A'`、`'Q'`、`'BM'`、`'BA'`、`'BQ'` 和 `'W'` 默认值为 ‘right’ 外，其他默认值为 ‘left‘
label | 在重采样中，如何设置聚合值的标签， right 或 left，默认为 None， 例如，9:30 到 9:35 之间的这 5 分钟会被标记为 9:30 或 9:35
convention | 仅用于 PeriodIndex（固定时期），对周期进行重采样，`'start'` or `'s'`，`'end'` or `'e'`
on | 对于 DataFrame 对象，可用该参数指定重采样后的数据的 index（行索引） 为原数据中的某列
level | 对于具有层级索引（MultiIndex）的 DataFrame 对象，可以使用该参数来指定需要在哪个级别上进行重新采样

将序列重采样到三分钟的频率，并将每个频率的值相加：

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20

    >>> import pandas as pd
    >>> index = pd.date_range('1/1/2000', periods=9, freq='T')
    >>> series = pd.Series(range(9), index=index)
    >>> series
    2000-01-01 00:00:00    0
    2000-01-01 00:01:00    1
    2000-01-01 00:02:00    2
    2000-01-01 00:03:00    3
    2000-01-01 00:04:00    4
    2000-01-01 00:05:00    5
    2000-01-01 00:06:00    6
    2000-01-01 00:07:00    7
    2000-01-01 00:08:00    8
    Freq: T, dtype: int64
    >>>
    >>> series.resample('3T').sum()
    2000-01-01 00:00:00     3
    2000-01-01 00:03:00    12
    2000-01-01 00:06:00    21
    Freq: 3T, dtype: int64

设置 `label='right'`，即每个索引 index 会使用靠右侧（较大值）的标签：

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20

    >>> import pandas as pd
    >>> index = pd.date_range('1/1/2000', periods=9, freq='T')
    >>> series = pd.Series(range(9), index=index)
    >>> series
    2000-01-01 00:00:00    0
    2000-01-01 00:01:00    1
    2000-01-01 00:02:00    2
    2000-01-01 00:03:00    3
    2000-01-01 00:04:00    4
    2000-01-01 00:05:00    5
    2000-01-01 00:06:00    6
    2000-01-01 00:07:00    7
    2000-01-01 00:08:00    8
    Freq: T, dtype: int64
    >>>
    >>> series.resample('3T', label='right').sum()
    2000-01-01 00:03:00     3
    2000-01-01 00:06:00    12
    2000-01-01 00:09:00    21
    Freq: 3T, dtype: int64

设置 `closed='right'`，即结果中会包含原数据中最右侧（较大）的值：

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21

    >>> import pandas as pd
    >>> index = pd.date_range('1/1/2000', periods=9, freq='T')
    >>> series = pd.Series(range(9), index=index)
    >>> series
    2000-01-01 00:00:00    0
    2000-01-01 00:01:00    1
    2000-01-01 00:02:00    2
    2000-01-01 00:03:00    3
    2000-01-01 00:04:00    4
    2000-01-01 00:05:00    5
    2000-01-01 00:06:00    6
    2000-01-01 00:07:00    7
    2000-01-01 00:08:00    8
    Freq: T, dtype: int64
    >>>
    >>> series.resample('3T', label='right', closed='right').sum()
    2000-01-01 00:00:00     0
    2000-01-01 00:03:00     6
    2000-01-01 00:06:00    15
    2000-01-01 00:09:00    15
    Freq: 3T, dtype: int64

以下示例将序列重采样到30秒的频率，`asfreq()[0:5]` 用于选择前5行数据：

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22

    >>> import pandas as pd
    >>> index = pd.date_range('1/1/2000', periods=9, freq='T')
    >>> series = pd.Series(range(9), index=index)
    >>> series
    2000-01-01 00:00:00    0
    2000-01-01 00:01:00    1
    2000-01-01 00:02:00    2
    2000-01-01 00:03:00    3
    2000-01-01 00:04:00    4
    2000-01-01 00:05:00    5
    2000-01-01 00:06:00    6
    2000-01-01 00:07:00    7
    2000-01-01 00:08:00    8
    Freq: T, dtype: int64
    >>>
    >>> series.resample('30S').asfreq()[0:5]
    2000-01-01 00:00:00    0.0
    2000-01-01 00:00:30    NaN
    2000-01-01 00:01:00    1.0
    2000-01-01 00:01:30    NaN
    2000-01-01 00:02:00    2.0
    Freq: 30S, dtype: float64

使用 `pad` 方法向后填充缺失值（NaN）：

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22

    >>> import pandas as pd
    >>> index = pd.date_range('1/1/2000', periods=9, freq='T')
    >>> series = pd.Series(range(9), index=index)
    >>> series
    2000-01-01 00:00:00    0
    2000-01-01 00:01:00    1
    2000-01-01 00:02:00    2
    2000-01-01 00:03:00    3
    2000-01-01 00:04:00    4
    2000-01-01 00:05:00    5
    2000-01-01 00:06:00    6
    2000-01-01 00:07:00    7
    2000-01-01 00:08:00    8
    Freq: T, dtype: int64
    >>>
    >>> series.resample('30S').pad()[0:5]
    2000-01-01 00:00:00    0
    2000-01-01 00:00:30    0
    2000-01-01 00:01:00    1
    2000-01-01 00:01:30    1
    2000-01-01 00:02:00    2
    Freq: 30S, dtype: int64

使用 `bfill` 方法向前填充缺失值（NaN）：

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22

    >>> import pandas as pd
    >>> index = pd.date_range('1/1/2000', periods=9, freq='T')
    >>> series = pd.Series(range(9), index=index)
    >>> series
    2000-01-01 00:00:00    0
    2000-01-01 00:01:00    1
    2000-01-01 00:02:00    2
    2000-01-01 00:03:00    3
    2000-01-01 00:04:00    4
    2000-01-01 00:05:00    5
    2000-01-01 00:06:00    6
    2000-01-01 00:07:00    7
    2000-01-01 00:08:00    8
    Freq: T, dtype: int64
    >>>
    >>> series.resample('30S').bfill()[0:5]
    2000-01-01 00:00:00    0
    2000-01-01 00:00:30    1
    2000-01-01 00:01:00    1
    2000-01-01 00:01:30    2
    2000-01-01 00:02:00    2
    Freq: 30S, dtype: int64

通过 `apply` 方法传递自定义函数：

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23

    >>> import pandas as pd
    >>> index = pd.date_range('1/1/2000', periods=9, freq='T')
    >>> series = pd.Series(range(9), index=index)
    >>> series
    2000-01-01 00:00:00    0
    2000-01-01 00:01:00    1
    2000-01-01 00:02:00    2
    2000-01-01 00:03:00    3
    2000-01-01 00:04:00    4
    2000-01-01 00:05:00    5
    2000-01-01 00:06:00    6
    2000-01-01 00:07:00    7
    2000-01-01 00:08:00    8
    Freq: T, dtype: int64
    >>>
    >>> def custom_resampler(array_like):
    	return np.sum(array_like) + 5

    >>> series.resample('3T').apply(custom_resampler)
    2000-01-01 00:00:00     8
    2000-01-01 00:03:00    17
    2000-01-01 00:06:00    26
    Freq: 3T, dtype: int64

convention 参数的应用：

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25

    >>> import pandas as pd
    >>> s = pd.Series([1, 2], index=pd.period_range('2012-01-01', freq='A', periods=2))
    >>> s
    2012    1
    2013    2
    Freq: A-DEC, dtype: int64
    >>>
    >>> s.resample('Q', convention='start').asfreq()
    2012Q1    1.0
    2012Q2    NaN
    2012Q3    NaN
    2012Q4    NaN
    2013Q1    2.0
    2013Q2    NaN
    2013Q3    NaN
    2013Q4    NaN
    Freq: Q-DEC, dtype: float64
    >>>
    >>> s.resample('Q', convention='end').asfreq()
    2012Q4    1.0
    2013Q1    NaN
    2013Q2    NaN
    2013Q3    NaN
    2013Q4    2.0
    Freq: Q-DEC, dtype: float64

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36

    >>> import pandas as pd
    >>> q = pd.Series([1, 2, 3, 4], index=pd.period_range('2018-01-01', freq='Q', periods=4))
    >>> q
    2018Q1    1
    2018Q2    2
    2018Q3    3
    2018Q4    4
    Freq: Q-DEC, dtype: int64
    >>>
    >>> q.resample('M', convention='end').asfreq()
    2018-03    1.0
    2018-04    NaN
    2018-05    NaN
    2018-06    2.0
    2018-07    NaN
    2018-08    NaN
    2018-09    3.0
    2018-10    NaN
    2018-11    NaN
    2018-12    4.0
    Freq: M, dtype: float64
    >>>
    >>> q.resample('M', convention='start').asfreq()
    2018-01    1.0
    2018-02    NaN
    2018-03    NaN
    2018-04    2.0
    2018-05    NaN
    2018-06    NaN
    2018-07    3.0
    2018-08    NaN
    2018-09    NaN
    2018-10    4.0
    2018-11    NaN
    2018-12    NaN
    Freq: M, dtype: float64

对于 DataFrame 对象，可以使用关键字 on 来指定原数据中的某列为重采样后数据的行索引：

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21

    >>> import pandas as pd
    >>> d = dict({'price': [10, 11, 9, 13, 14, 18, 17, 19],
              	  'volume': [50, 60, 40, 100, 50, 100, 40, 50]})
    >>> df = pd.DataFrame(d)
    >>> df['week_starting'] = pd.date_range('01/01/2018', periods=8, freq='W')
    >>> df
       price  volume week_starting
    0     10      50    2018-01-07
    1     11      60    2018-01-14
    2      9      40    2018-01-21
    3     13     100    2018-01-28
    4     14      50    2018-02-04
    5     18     100    2018-02-11
    6     17      40    2018-02-18
    7     19      50    2018-02-25
    >>>
    >>> df.resample('M', on='week_starting').mean()
                   price  volume
    week_starting
    2018-01-31     10.75    62.5
    2018-02-28     17.00    60.0

对于具有层级索引（MultiIndex）的 DataFrame 对象，可以使用关键字 `level` 来指定需要在哪个级别上进行重新采样：

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22

    >>> import pandas as pd
    >>> days = pd.date_range('1/1/2000', periods=4, freq='D')
    >>> d2 = dict({'price': [10, 11, 9, 13, 14, 18, 17, 19],
               	   'volume': [50, 60, 40, 100, 50, 100, 40, 50]})
    >>> df2 = pd.DataFrame(d2, index=pd.MultiIndex.from_product([days, ['morning', 'afternoon']]))
    >>> df2
                          price  volume
    2000-01-01 morning       10      50
               afternoon     11      60
    2000-01-02 morning        9      40
               afternoon     13     100
    2000-01-03 morning       14      50
               afternoon     18     100
    2000-01-04 morning       17      40
               afternoon     19      50
    >>>
    >>> df2.resample('D', level=0).sum()
                price  volume
    2000-01-01     21     110
    2000-01-02     22     140
    2000-01-03     32     150
    2000-01-04     36      90

    1
    2
    3
    4
    5

    这里是一段防爬虫文本，请读者忽略。
    本文原创首发于 CSDN，作者 TRHX。
    博客首页：https://itrhx.blog.csdn.net/
    本文链接：https://itrhx.blog.csdn.net/article/details/106947061
    未经授权，禁止转载！恶意转载，后果自负！尊重原创，远离剽窃！

您的喜欢是作者写作最大的动力！❤️

- PayPal
- AliPay
- WeChatPay
- QQPay

Donate

最后更新于 2020年7月6日

Pandas

时间序列

###### 上一页

#### Python 数据分析三剑客之 Pandas（十）：数据读写

###### IO操作 Pandas 数据读写

###### 下一页

#### Python 数据分析三剑客之 Pandas（八）：数据重塑/重复数据处理/数据替换

###### Pandas 数据重塑 数据替换

#### 评论

## ๑۩ﺴ TRHX ﺴ۩๑

本文目录
欢迎光临

Hexo QQ 交流群 Telegram 交流群

CSDN 内容合伙人

文章分类

- BLOG
  (4)
- CDN
  (1)
- Hexo
  (9)
- Java
  (1)
- Linux
  (2)
- Markdown
  (2)
- Python 数据分析
  (27)
- Matplotlib
  (11)
- NumPy
  (6)
- Pandas
  (10)
- Python3 学习笔记
  (41)
- 基础学习
  (9)
- 学习经验
  (4)
- 爬虫学习
  (18)
- 爬虫实战
  (10)
- VPS
  (1)
- WEB前端
  (2)
- 图床
  (1)

热门标签
12306 3D图 58同城 Ajax BLOG Beautiful Soup CDN Coding Pages DataFrame Deepin Elicpse GitHub Pages Github Github Pages GroupBy HTTPS Hexo ICP备案 IO操作 Index JDBC JS 预加载 LaTeX Markdown Material X Matplotlib MongoDB MySQL NumPy PEP8 Pandas PicGo Pygame Python Redis SEO SQL Server 2012 SSR Selenium Series Ubuntu User-Agent VMware VPS XPath if语句 input()函数 instant.page jsDelivr lxml matplotibrc pyspider requests spfk urllib while循环 主题个性化 代理 位运算 公安备案 函数 函数应用 分割 切片 列表 判断函数 前程无忧 变量 合并数据集 哔哩哔哩 图例 图床 图形验证码 垃圾 备份 子图 字典 字符串函数 安居客 层级索引 年终总结 广播 异常 技巧 拼接 排序 排序函数 操作列表 散点图 数学函数 数据分裂 数据可视化 数据合并 数据替换 数据类型 数据读写 数据重塑 数组 文件 文件储存 无界面浏览器 时间序列 映射 条件函数 条形图 极区图 极坐标图 柱状图 模块 正则表达式 滑动验证码 点触验证码 爬虫 猫眼电影 瓜子二手车 画布 直方图 矩阵 等值线图 等高线图 算术函数 算术运算 类 索引 线性代数 线性图 统计函数 统计描述 统计计算 继承 编辑器 缺失值 网格 肺炎疫情 虎扑论坛 补丁 豆瓣电影 迭代 雷达图 饼状图
最近在听