pandas教程:Periods and Period Arithmetic 周期和周期运算-灵析社区

清晨我上码

11.5 Periods and Period Arithmetic(周期和周期运算)

Periods(周期)表示时间跨度(timespans),比如天,月,季,年。Period类表示的就是这种数据类型,构建的时候需要用字符串或整数,以及一个频度(关于频度的代码可以看11.4中的表格):

import numpy as np
import pandas as pd
p = pd.Period(2007, freq='A-DEC')
p
Period('2007', 'A-DEC')

在这个例子里,Period对象代表了整个2007年一年的时间跨度,从1月1日到12月31日。在Period对象上进行加减,会有和对频度进行位移(shifting)一样的效果:

p + 5
Period('2012', 'A-DEC')
p - 2
Period('2005', 'A-DEC')

如果两个周期有相同的频度,二者的区别就是它们之间有多少个单元(units):

pd.Period('2014', freq='A-DEC') - p
7

固定范围的周期(Regular ranges of periods)可以通过period_range函数创建:

rng = pd.period_range('2000-01-01', '2000-06-03', freq='M')
rng
PeriodIndex(['2000-01', '2000-02', '2000-03', '2000-04', '2000-05', '2000-06'], dtype='int64', freq='M')

PeriodIndex类能存储周期组成的序列,而且可以作为任何pandas数据结构中的轴索引(axis index):

pd.Series(np.random.randn(6), index=rng)
2000-01    0.439035
2000-02   -0.231125
2000-03   -1.085106
2000-04   -1.909902
2000-05    1.478810
2000-06    0.656713
Freq: M, dtype: float64

如果我们有字符串组成的数组,可以使用PeriodIndex类:

values = ['2001Q3', '2002Q2', '2003Q1']
index = pd.PeriodIndex(values, freq='Q-DEC')
index
PeriodIndex(['2001Q3', '2002Q2', '2003Q1'], dtype='int64', freq='Q-DEC')

1 Period Frequency Conversion(周期频度转换)

通过使用asfreq方法,Periods和PeriodIndex对象能被转换为其他频度。例如,假设我们有一个年度期间(annual period),并且想要转换为月度期间(monthly period),做法非常直观:

p = pd.Period('2007', freq='A-DEC')
p
Period('2007', 'A-DEC')
p.asfreq('M', how='start')
Period('2007-01', 'M')
p.asfreq('M', how='end')
Period('2007-12', 'M')

我们可以认为Period('2007', freq='A-DEC')是某种指向时间跨度的光标,而这个时间跨度被细分为月度期间。可以看下面的图示:

如果一个财政年度(fiscal year)是在1月结束,而不是12月,那么对应的月度期间会不一样:

p = pd.Period('2007', freq='A-JUN')
p
Period('2007', 'A-JUN')
p.asfreq('M', 'start')
Period('2006-07', 'M')
p.asfreq('M', 'end')
Period('2007-06', 'M')

当我们转换高频度为低频度时,pandas会根据 subperiod(次周期;子周期)的归属来决定superperiod(超周期;母周期)。例如,在A-JUN频度中,月份Aug-2007其实是个2008周期的一部分:

p = pd.Period('Aug-2007', 'M')
p.asfreq('A-JUN')
Period('2008', 'A-JUN')

整个PeriodIndex对象或时间序列可以被转换为一样的语义(semantics):

rng = pd.period_range('2006', '2009', freq='A-DEC')
ts = pd.Series(np.random.randn(len(rng)), index=rng)
ts
2006    0.391629
2007    0.497413
2008   -1.685639
2009    0.939885
Freq: A-DEC, dtype: float64
ts.asfreq('M', how='start')
2006-01    0.391629
2007-01    0.497413
2008-01   -1.685639
2009-01    0.939885
Freq: M, dtype: float64

这里,年度周期可以用月度周期替换,对应的第一个月也会包含在每个年度周期里。如果我们想要每年的最后一个工作日的话,可以使用'B'频度,并指明我们想要周期的结尾:

ts.asfreq('B', how='end')
2006-12-29    0.391629
2007-12-31    0.497413
2008-12-31   -1.685639
2009-12-31    0.939885
Freq: B, dtype: float64

2 Quarterly Period Frequencies(季度周期频度)

季度数据经常出现在会计,经济等领域。大部分季度数据都与财政年度结束日(fiscal year end)相关,比如12月最后一个工作日。因此,根据财政年度结束的不同,周期2012Q4也有不同的意义。pandas支持所有12个周期频度,从Q-JAN到Q-DEC:

p = pd.Period('2012Q4', freq='Q-JAN')
p
Period('2012Q4', 'Q-JAN')

如果是财政年度结束日在一月份,那么2012Q4代表从11月到1月,可以用日频度查看。

p.asfreq('D', 'start')
Period('2011-11-01', 'D')
p.asfreq('D', 'end')
Period('2012-01-31', 'D')

因此,做些简单的周期运算也是可能的,例如,获得每个季度的,第二个到最后一个工作日的,下午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('2011Q3', '2012Q4', freq='Q-JAN')
ts = pd.Series(np.arange(len(rng)), index=rng)
ts
2011Q3    0
2011Q4    1
2012Q1    2
2012Q2    3
2012Q3    4
2012Q4    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
2010-10-28 16:00:00    0
2011-01-28 16:00:00    1
2011-04-28 16:00:00    2
2011-07-28 16:00:00    3
2011-10-28 16:00:00    4
2012-01-30 16:00:00    5
dtype: int64

3 Converting Timestamps to Periods (and Back)(时间戳与周期相互转换)

用时间戳作为索引的Series和DataFrame对象,可以用to_period方法转变为周期:

rng = pd.date_range('2000-01-01', periods=3, freq='M')
ts = pd.Series(np.random.randn(3), index=rng)
ts
2000-01-31    1.556049
2000-02-29   -0.708661
2000-03-31   -0.154767
Freq: M, dtype: float64
pts = ts.to_period()
pts
2000-01    1.556049
2000-02   -0.708661
2000-03   -0.154767
Freq: M, dtype: float64

因为周期是不重复的时间跨度(non-overlapping timespans),一个时间戳只能属于一个有指定频度的单独周期。尽管默认情况下新的PeriodIndex的频度会从时间戳中来推测,但我们也可以自己设定想要的频度。结果中有重复的周期也没有关系:

rng = pd.date_range('1/29/2000', periods=6, freq='D')
rng
DatetimeIndex(['2000-01-29', '2000-01-30', '2000-01-31', '2000-02-01',
               '2000-02-02', '2000-02-03'],
              dtype='datetime64[ns]', freq='D')
ts2 = pd.Series(np.random.randn(6), index=rng)
ts2
2000-01-29    1.115254
2000-01-30   -1.813124
2000-01-31    0.970670
2000-02-01    1.306337
2000-02-02    0.673274
2000-02-03   -0.105436
Freq: D, dtype: float64
ts2.to_period('M')
2000-01    1.115254
2000-01   -1.813124
2000-01    0.970670
2000-02    1.306337
2000-02    0.673274
2000-02   -0.105436
Freq: M, dtype: float64

想转换回时间戳的话,使用to_timestamp:

pts = ts2.to_period()
pts
2000-01-29    1.115254
2000-01-30   -1.813124
2000-01-31    0.970670
2000-02-01    1.306337
2000-02-02    0.673274
2000-02-03   -0.105436
Freq: D, dtype: float64
pts.to_timestamp(how='end')
2000-01-29    1.115254
2000-01-30   -1.813124
2000-01-31    0.970670
2000-02-01    1.306337
2000-02-02    0.673274
2000-02-03   -0.105436
Freq: D, dtype: float64

4 Creating a PeriodIndex from Arrays(从数组中创建一个周期索引)

有固定频度的数据集,有时会在很多列上存储时间跨度信息。例如,在下面的宏观经济数据及上,年度和季度在不同的列:

data = pd.read_csv('../examples/macrodata.csv')
data.head()

data.year[:5]

1959Q1    1959.0

1959Q2    1959.0
1959Q3    1959.0
1959Q4    1959.0
1960Q1    1960.0
Freq: Q-DEC, Name: year, dtype: float64
data.quarter[:5]
1959Q1    1.0
1959Q2    2.0
1959Q3    3.0
1959Q4    4.0
1960Q1    1.0
Freq: Q-DEC, Name: quarter, dtype: float64

通过把这些数组传递给PeriodIndex,并指定频度,我们可以把这些合并得到一个新的DataFrame:

index = pd.PeriodIndex(year=data.year, quarter=data.quarter, 
                       freq='Q-DEC')
index
PeriodIndex(['1959Q1', '1959Q2', '1959Q3', '1959Q4', '1960Q1', '1960Q2',
             '1960Q3', '1960Q4', '1961Q1', '1961Q2',
             ...
             '2007Q2', '2007Q3', '2007Q4', '2008Q1', '2008Q2', '2008Q3',
             '2008Q4', '2009Q1', '2009Q2', '2009Q3'],
            dtype='int64', length=203, freq='Q-DEC')
data.index = index
data.head()

data.infl[:5]
1959Q1    0.00
1959Q2    2.34
1959Q3    2.74
1959Q4    0.27
1960Q1    2.31
Freq: Q-DEC, Name: infl, dtype: float64


阅读量:113

点赞量:0

收藏量:0