Py学习  »  Python

Python 数据分析三剑客之 Pandas(九):时间序列

TRHX • 鲍勃 • 3 年前 • 273 次点击  

CSDN 课程推荐:《迈向数据科学家:带你玩转Python数据分析》,讲师齐伟,苏州研途教育科技有限公司CTO,苏州大学应用统计专业硕士生指导委员会委员;已出版《跟老齐学Python:轻松入门》《跟老齐学Python:Django实战》、《跟老齐学Python:数据分析》和《Python大学实用教程》畅销图书。


Pandas 系列文章(正在更新中…):


另有 NumPy、Matplotlib 系列文章已更新完毕,欢迎关注:


推荐学习资料与网站(博主参与部分文档翻译):



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

【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

基本语法:

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

常用参数:

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

简单示例:

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

设置 unit='s' ,即待转换对象单位为秒:

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

使用 tz 参数设置时区:

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

【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

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

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

>>> 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
  • 5
  • 6
  • 7

基本语法:

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

官方文档: 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)

简单应用:

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

设置 format errors 参数:

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

设置 unit 参数:

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

【02x04】date_range

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

基本语法:

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

官方文档: 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' :保留结束日期,不保留开始日期

简单示例:

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

指定 periods 参数:

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

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

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

使用 tz 参数设置时区:

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

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

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

设置 closed 参数:

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

【02x05】索引与切片

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

>>> 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

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

>>> 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
  • 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

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

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

>>> 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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

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

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

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

>>> from pandas.tseries.offsets import Hour, Minute
>>> hour = Hour()
>>


    
> hour
<Hour>
>>> 
>>> four_hours = Hour(4)
>>> four_hours
<4 * Hours>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

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

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

大部分偏移量对象都可通过加法进行连接:

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

对于 freq 参数也可以传入频率字符串(如 "2h30min" ),这种字符串可以被高效地解析为等效的表达式:

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

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

>>> from pandas.tseries.offsets import Day, MonthEnd
>>> now = datetime(2011, 11,


    
 17)
>>> now + 3 * Day()
Timestamp('2011-11-20 00:00:00')
  • 1
  • 2
  • 3
  • 4

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

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

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

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

groupby 方法结合使用:

>>> 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
  • 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

【02x07】时区处理

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

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

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

>>> 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')
  • 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

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

>>> 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
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

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

【03x00】period 固定时期

【03x01】pandas.Period

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

基本语法:

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

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

常用参数:

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

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

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

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

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

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

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

【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 对象名称

简单应用:

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

【03x03】asfreq 时期频率转换

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

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

常用参数:

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

应用示例:

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

【03x04】to_period 与 to_timestamp()

to_period 方法可以将 Timestamp(时间戳) 转换为 Period(固定时期);

to_timestamp 方法可以将 Period(固定时期)转换为 Timestamp(时间戳) 。

>>> 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')
  • 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

【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 对象之间的时间差:

>>


    
> 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

获取属性:

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

【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 对象:

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

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

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

指定 unit 参数:

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

【04x03】timedelta_range

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

基本语法:

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

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

常用参数:

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

应用示例:

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

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

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

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

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

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

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

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

基本语法:

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

常用参数:

参数 描述
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 对象,可以使用该参数来指定需要在哪个级别上进行重新采样

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

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

设置 label='right' ,即每个索引 index 会使用靠右侧(较大值)的标签:

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

设置 closed='right' ,即结果中会包含原数据中最右侧(较大)的值:

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

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

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

使用 pad 方法向后填充缺失值(NaN):

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

使用 bfill 方法向前填充缺失值(NaN):

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

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

>>> 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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

convention 参数的应用:

>>> 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
>>> 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
  • 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

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

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

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

>>> 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
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

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

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/70698
 
273 次点击