时期(Period)表示的是一个固定时间区间,比如数日、数月数季、数年等,例如一个账单是一段时间内的所有交易数据,这就是按月,季度等划分的固定时间区间。Period 类所表示的就是这种数据类型,其构造函数需要用到一个字符串或整数,以及频率:
import pandas as pd
from pandas import Series
import numpy as np
p = pd.Period(2012, freq="A-DEC") #Period 对象表示的是从2012年1月1日到2012年12月31日之间的整段时间。
p
Period('2012', 'A-DEC')
p + 5
Period('2017', 'A-DEC')
p - 2
Period('2010', 'A-DEC')
pd.Period('2014', freq='A-DEC') - p
<2 * YearEnds: month=12>
#period_range 函数可用于创建规则的时期范围
rng = pd.period_range('1/1/2015','6/30/2015',freq='M')
rng
PeriodIndex(['2015-01', '2015-02', '2015-03', '2015-04', '2015-05', '2015-06'], dtype='period[M]', freq='M')
PeriodIndex 类保存了一组 Period,它可以在任何 pandas 数据结构中被用作轴索引:
Series(np.random.randn(6), index = rng)
2015-01 -0.314419
2015-02 -0.655416
2015-03 1.868826
2015-04 -0.528982
2015-05 0.092287
2015-06 0.321132
Freq: M, dtype: float64
#PeriodIndex 类的构造函数还允许直接使用一组字符串
values = ['2001Q3', '2002Q2', '2003Q1']
index = pd.PeriodIndex(values, freq='Q-DEC')
index
PeriodIndex(['2001Q3', '2002Q2', '2003Q1'], dtype='period[Q-DEC]', freq='Q-DEC')
时期的频率转换
Period 和 PeriodIndex 对象都可以通过其 asfreq 方法被转换成别的频率。假设我们有一个年度时期,希望将其转换为当年年初或年末的一个月度时期:
p = pd.Period('2015', freq = 'A-DEC')
p.asfreq('M', how = 'start')
Period('2015-01', 'M')
p.asfreq('M',how='end')
Period('2015-12', 'M')
将 Period('2015','A-DEC')看做一个被划分为多个月度时期的时间段中的游标。对于一个不以12结束的财政年度,月度子时期的归属情况就不一样了:
p = pd.Period('2015', freq = 'A-JUN')
p
Period('2015', 'A-JUN')
在将高频率转换为低频率时,超时期(superperiod)是由子时期(subperiod)所属的位置决定的。例如,在 A-JUN 频率中,月份“2014年8月”实际上是属于周期“2015年”的:
p = pd.Period('2014-08','M')
p.asfreq('A-JUN')
#PeriodIndex 或 TimeSeries 的频率转换方式也是如此
rng = pd.period_range('2010','2015',freq='A-DEC')
ts = Series(np.random.randn(len(rng)),index=rng)
ts
2010 0.104686
2011 -0.458433
2012 -0.760378
2013 1.815320
2014 0.005840
2015 -0.794424
Freq: A-DEC, dtype: float64
ts.asfreq('M',how='start')
2010-01 0.104686
2011-01 -0.458433
2012-01 -0.760378
2013-01 1.815320
2014-01 0.005840
2015-01 -0.794424
Freq: M, dtype: float64
ts.asfreq('B',how='end')
2010-12-31 0.104686
2011-12-30 -0.458433
2012-12-31 -0.760378
2013-12-31 1.815320
2014-12-31 0.005840
2015-12-31 -0.794424
Freq: B, dtype: float64
3
季度型数据在会计、金融等领域中很常见。许多季度型数据都会涉及“财年末”的概念,通常是一年12个月中某月的最后一个日历日或工作日。就这一点来说,时期“2012Q4”根据财年末的不同会有不同的含义。pandas 支持12种可能的季度型频率,即 Q-JAN 到 Q-DEC:
p = pd.Period('2012Q4', freq='Q-JAN')
p
Period('2012Q4', 'Q-JAN')
p.asfreq('D','start')
Period('2011-11-01', 'D')
p.asfreq('D','end')
Period('2012-01-31', 'D')
因此,Period 之间的算术运算会非常简单。例如,要获取该季度倒数第二个工作日下午4点的时间戳,我们可以这样:
p4pm = (p.asfreq('B','e')-1).asfreq('T','s')+16*60
p4pm
Period('2012-01-30 16:00', 'T')
p4pm.to_timestamp()
Timestamp('2012-01-30 16:00:00')
period_range 还可以用于生成季度型范围。季度型范围的算术运算也跟上面是一样的:
rng = pd.period_range('2014Q3','2015Q4',freq='Q-JAN')
ts = Series(np.arange(len(rng)), index = rng)
ts
2014Q3 0
2014Q4 1
2015Q1 2
2015Q2 3
2015Q3 4
2015Q4 5
Freq: Q-JAN, dtype: int64
new_rng = (rng.asfreq('B','e')-1).asfreq('T','s')+16*60
ts.index = new_rng.to_timestamp()
ts
2013-10-30 16:00:00 0
2014-01-30 16:00:00 1
2014-04-29 16:00:00 2
2014-07-30 16:00:00 3
2014-10-30 16:00:00 4
2015-01-29 16:00:00 5
dtype: int64
4 将 Timestamp 转换为 Period(及其反向过程)
rng = pd.date_range('1/1/2000',periods=3,freq='M')
ts = Series(np.random.randn(3),index=rng)
pts=ts.to_period()
ts
2000-01-31 -2.054633
2000-02-29 -0.650259
2000-03-31 -1.125433
Freq: M, dtype: float64
pts
2000-01 -2.054633
2000-02 -0.650259
2000-03 -1.125433
Freq: M, dtype: float64
由于时期指的是非重叠时间区间,因此对于给定的频率,一个时间戳只能属于一个时期。新 PeriodIndex 的频率默认是从时间戳推断而来的,你也可以指定任何别的频率。结果中允许存在重复时期:
rng = pd.date_range('1/29/2000',periods=6,freq='D')
ts2 = Series(np.random.randn(6), index=rng)
ts2.to_period('M')
2000-01 0.888082
2000-01 -1.252855
2000-01 -2.822398
2000-02 -1.185904
2000-02 -0.121582
2000-02 0.198893
Freq: M, dtype: float64
要转换为时间戳,使用 to_timestamp 即可
pts = ts.to_period()
pts
2000-01 -2.054633
2000-02 -0.650259
2000-03 -1.125433
Freq: M, dtype: float64
pts.to_timestamp(how='end')
2000-01-31 23:59:59.999999999 -2.054633
2000-02-29 23:59:59.999999999 -0.650259
2000-03-31 23:59:59.999999999 -1.125433
Freq: M, dtype: float64
通过数组创建PeriodIndex
某些数据集中时间信息是分开在多个列存放的,可以通过PeriodIndex的参数将这些列组合在一起
year = [2017,2017,2017,2017,2018,2018,2018,2018]
quarter = [1,2,3,4,1,2,3,4]
index = pd.PeriodIndex(year=year,quarter=quarter,freq='Q-DEC')
index
PeriodIndex(['2017Q1', '2017Q2', '2017Q3', '2017Q4', '2018Q1', '2018Q2',
'2018Q3', '2018Q4'],
dtype='period[Q-DEC]', freq='Q-DEC')