时间序列
首先导入需要用到的包

  1. import pandas as pd
  2. import numpy as np
时间类型 Python中的类型
时间戳 timestamp
时间间隔 timedelta
时期 period

pd.Period()构造时期

时期(period)表示的是时间区间,比如数日、数月、数季、数年等。

  1. >>> import pandas as pd
  2. # Period类所表示的就是这种数据类型,其构造函数需要用到一个字符串或整数
  3. >>> p = pd.Period('2010',freq = 'A-DEC')
  4. >>> p
  5. # 这个Period对象表示的是从2010年1月1日到2010年12月31日之间的整段时间
  6. Period('2010', 'A-DEC')
  7. # 只需对Period对象加上或减去一个整数即可达到根据其频率进行位移的
  8. >>> p + 5
  9. Period('2015', 'A-DEC')
  10. >>> p - 4
  11. Period('2006', 'A-DEC')
  12. # 如果两个Period对象拥有相同频率,则它们的差就是它们之间的单位数量
  13. >>> pd.Period('2015',freq='A-DEC') - p
  14. 5

pd.period_range()构造时期范围

period_range函数可用于创建规则的时期范围:

  1. >>> rng = pd.period_range('2012-1-1','2012-6-30',freq = 'M')
  2. >>> rng
  3. PeriodIndex(['2012-01', '2012-02', '2012-03', '2012-04', '2012-05', '2012-06'], dtype='period[M]', freq='M')
  4. # PeriodIndex类保存了一组Period,它可以在任何pandas数据结构中被用作轴索引
  5. >>> ped = pd.Series(np.random.randn(len(rng)), index = rng)
  6. >>> ped
  7. 2012-01 -2.411963
  8. 2012-02 0.893100
  9. 2012-03 1.438209
  10. 2012-04 0.193747
  11. 2012-05 -1.469531
  12. 2012-06 0.943145
  13. Freq: M, dtype: float64
  14. >>> ped.index
  15. PeriodIndex(['2012-01', '2012-02', '2012-03', '2012-04', '2012-05', '2012-06'], dtype='period[M]', freq='M')

使用PeriodIndex类将一个字符串数组转换为一段时期

  1. # PeriodIndex类的构造函数允许直接使用一组字符串表示一段时期
  2. >>> values =['2010Q1','2010Q2','2010Q3']
  3. >>> index = pd.PeriodIndex(values,freq = 'Q-DEC')
  4. >>> index
  5. PeriodIndex(['2010Q1', '2010Q2', '2010Q3'], dtype='period[Q-DEC]', freq='Q-DEC')

时间的频率转换

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

一个年度时期,希望将其转换为当年年初或年末的一个月度时期

  1. >>> p = pd.Period('2012',freq = 'A-DEC')
  2. >>> p
  3. Period('2012', 'A-DEC')
  4. >>> p.asfreq('M',how = 'start')
  5. Period('2012-01', 'M')
  6. >>> p.asfreq('Q','End')
  7. Period('2012Q4', 'Q-DEC')

可以将Period('2012','A-DEC')看做一个被划分为多个月度时期的时间段中的游标。下图对此进行了说明在将高频率转换为低频率时,超时期(superperiod)是由子时期(subperiod)所属的位置决定的。
时间序列 | 时期(Period)及其算术运算 - 图1
在A-JUN频率中,月份”2007年8月”实际上是属于周期”2008年”的:

  1. >>> p = pd.Period('Aug-2007', freq = 'M')
  2. >>> p
  3. Period('2007-08', 'M')
  4. >>> p.asfreq('A-JUN')
  5. Period('2008', 'A-JUN')

完整的PeriodIndex或TimeSeries的频率转换方式相同

  1. >>> rng = pd.period_range('2001','2008', freq = 'A-DEC')
  2. >>> ts = pd.Series(np.random.randn(len(rng)), index = rng)
  3. >>> ts
  4. 2001 0.859500
  5. 2002 -1.213256
  6. 2003 -0.591023
  7. 2004 -0.393317
  8. 2005 1.015904
  9. 2006 0.278310
  10. 2007 1.860136
  11. 2008 0.119815
  12. Freq: A-DEC, dtype: float64

根据年度时期的第一个月,每年的时期被取代为每月的时期。

  1. ts.asfreq('M',how = 'start')
  2. 2001-01 0.859500
  3. 2002-01 -1.213256
  4. 2003-01 -0.591023
  5. 2004-01 -0.393317
  6. 2005-01 1.015904
  7. 2006-01 0.278310
  8. 2007-01 1.860136
  9. 2008-01 0.119815
  10. Freq: M, dtype: float64

每年的最后一个工作日,可以使用”B”频率,并指明想要该时期的末尾

  1. ts.asfreq('B',how = 'end')
  2. 2001-12-31 0.859500
  3. 2002-12-31 -1.213256
  4. 2003-12-31 -0.591023
  5. 2004-12-31 -0.393317
  6. 2005-12-30 1.015904
  7. 2006-12-29 0.278310
  8. 2007-12-31 1.860136
  9. 2008-12-31 0.119815
  10. Freq: B, dtype: float64

按季度计算的时期频率

时间序列 | 时期(Period)及其算术运算 - 图2

季度型数据

许多季度型数据都会涉及”财年末”,通常是一年12个月的最后一个日历日或工作日。时期”2012Q4”根据财年末的不同会有不同含义。

  1. >>> p = pd.Period('2012Q4',freq = 'Q-FEB') # Q-FEB是指2月末的工作日是财政年末
  2. >>> p
  3. Period('2012Q4', 'Q-FEB')
  4. >>> p.asfreq('D','start')
  5. Period('2011-12-01', 'D')
  6. >>> p.asfreq('D','end')
  7. Period('2012-02-29', 'D')
  8. >>> from pandas.tseries.offsets import Hour
  9. >>> pm4 = (p.asfreq('B','end') - 1).asfreq('T','start') + 16 * Hour()
  10. >>> pm4
  11. Period('2012-02-28 16:00', 'T')

季度型范围

  1. >>> rng = pd.period_range('2012Q1','2012Q4',freq = 'Q-DEC')
  2. >>> rs = pd.Series(np.random.randn(len(rng)), index = rng)
  3. >>> rs
  4. 2012Q1 3.271631
  5. 2012Q2 0.030144
  6. 2012Q3 0.778939
  7. 2012Q4 -0.785795
  8. Freq: Q-DEC, dtype: float64
  9. >>> rng_new = (rs.index.asfreq('B','end') - 1
  10. ).asfreq('T','start') + 16 * Hour()
  11. >>> rng_new
  12. PeriodIndex(['2012-03-29 16:00', '2012-06-28 16:00',
  13. '2012-09-27 16:00', '2012-12-28 16:00'],
  14. dtype='period[T]', freq='T')
  15. >>> rs1 = rs.copy()
  16. >>> rs.index
  17. PeriodIndex(['2012Q1', '2012Q2', '2012Q3', '2012Q4']
  18. , dtype='period[Q-DEC]', freq='Q-DEC')

将period 转换为 timestamp

  1. >>> rs1.index = rng_new
  2. >>> rs1
  3. 2012-03-29 16:00 3.271631
  4. 2012-06-28 16:00 0.030144
  5. 2012-09-27 16:00 0.778939
  6. 2012-12-28 16:00 -0.785795
  7. Freq: T, dtype: float64
  8. >>> rs.index = rng_new.to_timestamp()
  9. >>> rs
  10. 2012-03-29 16:00:00 3.271631
  11. 2012-06-28 16:00:00 0.030144
  12. 2012-09-27 16:00:00 0.778939
  13. 2012-12-28 16:00:00 -0.785795
  14. dtype: float64
  15. >>> rs.index
  16. DatetimeIndex(['2012-03-29 16:00:00', '2012-06-28 16:00:00',
  17. '2012-09-27 16:00:00', '2012-12-28 16:00:00'],
  18. dtype='datetime64[ns]', freq=None)
  19. >>> rs1.index
  20. PeriodIndex(['2012-03-29 16:00', '2012-06-28 16:00',
  21. '2012-09-27 16:00', '2012-12-28 16:00'],
  22. dtype='period[T]', freq='T')

Timestamp与Period互转

将Timestamp转换为Period(及其反向过程)
通过使用to_period方法,可以将由时间戳索引的Series和DataFrame对象转换为以时期索引。

  1. >>> rng = pd.date_range('2000-1-1',periods = 3, freq = 'M')
  2. >>> ts = pd.Series(np.random.randn(len(rng)), index = rng)
  3. >>> ts
  4. 2000-01-31 0.185383
  5. 2000-02-29 -0.304269
  6. 2000-03-31 1.447754
  7. Freq: M, dtype: float64
  8. >>> pts = ts.to_period()
  9. >>> pts
  10. 2000-01 0.185383
  11. 2000-02 -0.304269
  12. 2000-03 1.447754
  13. Freq: M, dtype: float64
  14. >>> rng = pd.date_range('2000-1-29',periods = 6, freq = 'D')
  15. >>> ts2 = pd.Series(np.random.randn(len(rng)), index = rng)
  16. >>> ts2
  17. 2000-01-29 -1.246242
  18. 2000-01-30 2.271754
  19. 2000-01-31 0.935833
  20. 2000-02-01 -0.527219
  21. 2000-02-02 -0.385504
  22. 2000-02-03 0.504284
  23. Freq: D, dtype: float64

新PeriodIndex的频率默认是从时间戳推断而来的,也可以指定任何别的频率

  1. >>> ts2.to_period('M') # 结果中允许存在重复时期
  2. 2000-01 -1.246242
  3. 2000-01 2.271754
  4. 2000-01 0.935833
  5. 2000-02 -0.527219
  6. 2000-02 -0.385504
  7. 2000-02 0.504284
  8. Freq: M, dtype: float64

要转换回时间戳,使用to_timestamp即可。

  1. >>> pts = ts2.to_period()
  2. >>> ts3 = pts.to_timestamp(how = 'end')
  3. >>> ts3
  4. 2000-01-29 23:59:59.999999999 -1.246242
  5. 2000-01-30 23:59:59.999999999 2.271754
  6. 2000-01-31 23:59:59.999999999 0.935833
  7. 2000-02-01 23:59:59.999999999 -0.527219
  8. 2000-02-02 23:59:59.999999999 -0.385504
  9. 2000-02-03 23:59:59.999999999 0.504284
  10. Freq: D, dtype: float64

通过数组创建PeriodIndex

某些数据集中时间信息是分开在多个列存放的,可以通过PeriodIndex的参数将这些列组合在一起。

  1. >>> year = [2017, 2017, 2017, 2017,
  2. 2018, 2018, 2018, 2018]
  3. >>> quarter = [1,2,3,4,1,2,3,4]
  4. >>> index = pd.PeriodIndex(year=year,quarter=quarter,freq='Q-DEC')
  5. >>> index
  6. PeriodIndex(['2017Q1', '2017Q2', '2017Q3',
  7. '2017Q4', '2018Q1', '2018Q2',
  8. '2018Q3', '2018Q4'],
  9. dtype='period[Q-DEC]', freq='Q-DEC')