Pandas 基础 (18) - Period and PeriodIndex

这节依然是时间相关的知识, 前面是侧重于时间点的一些方法, 这节要介绍的是关于时间段的相关知识.

创建一个 period 对象:

import pandas as pd
y = pd.Period('2016')
y

输出:

Period('2016', 'A-DEC')

A 代表 Annual | 年度的
DEC 代表 December | 12月
整体表示已经创建了一个 2016年的时间段对象, 并赋值给变量 y, 现在就可以调用这个对象的方法:

求2016年的起始时间:

y.start_time

输出:

Timestamp('2016-01-01 00:00:00')

2016年的结束时间:

y.end_time

输出:

Timestamp('2016-12-31 23:59:59.999999999')

创建 2019年1月的时间段对象, 注意, 这里具体到月份了:

m = pd.Period('2019-01')
m

输出:

Period('2019-01', 'M')

求 2019年1月的起始时间:

m.start_time

输出:

Timestamp('2019-01-01 00:00:00')

2019年1月的结束时间:

m.end_time

输出:

Timestamp('2019-01-31 23:59:59.999999999')

还可以对月份做加减操作:

m + 1

输出:

Period('2019-02', 'M')

从2019年1月往后推12个月:

m + 12  

输出:

Period('2020-01', 'M')

从输出可以看出 Pandas 对日历的精准掌握.

创建以天为单位的时间段对象:

d = pd.Period('2019-2-12')
d

输出:

Period('2019-02-12', 'D')

查看起始时间:

d.start_time

输出:

Timestamp('2019-02-12 00:00:00')

查看结束时间:

d.end_time

输出:

Timestamp('2019-02-12 23:59:59.999999999')

对天进行加运算:

d + 3

输出:

Period('2019-02-15', 'D')

创建以小时为单位的时间段对象:

h = pd.Period('2019-2-12 23')
h

输出:

Period('2019-02-12 23:00', 'H')

这里插播一条意外, 如果我按照如下格式写时间:

h = pd.Period('2019-2-12 23:09:7')
h

得到的就是以秒为单位的时间段对象:

Period('2019-02-12 23:09:07', 'S')

那么如果我固执地还想要以小时为单位的时间段对象呢? 那么就可以用参数 freq 的值加以限制:

h = pd.Period('2019-2-12 23:09:7', freq='H')
h

这样就得到了以小时为单位的时间段对象:

Period('2019-02-12 23:00', 'H')

同样可以进行加减运算:

h+3

输出:

Period('2019-02-13 02:00', 'H')

也可以用这种方式推移时间, 得到效果跟加运算是一样的:

h+pd.offsets.Hour(3)

输出:

Period('2019-02-13 02:00', 'H')

我们在做数据分析的时候还经常遇到以季度为时间节点的分析需求, 我们可以这样创建以季度为单位的时间段对象:

q = pd.Period('2019Q1')
q

输出:

Period('2019Q1', 'Q-DEC')

同样可以进行加减运算:

q+1

输出:

Period('2019Q2', 'Q-DEC')

查看起始时间:

q.start_time

输出:

Timestamp('2019-01-01 00:00:00')

查看结束时间:

q.end_time

输出:

Timestamp('2019-03-31 23:59:59.999999999')

通过上面的方式查看的起始时间和结束时间都是精确到秒的, 但是从实际的角度出发, 通常我们如果需要按季度做一些分析, 应该只要精确到月就可以了, 可以通过如下方式做转换:

q.asfreq('M', how='start')

输出:

Period('2019-01', 'M')

以及精确到月的结束时间:

q.asfreq('M', how='end')

输出:

Period('2019-03', 'M')

以季度为单位创建时间段对象:

idx = pd.period_range('2011', '2018', freq='Q')
idx

输出:

PeriodIndex(['2011Q1', '2011Q2', '2011Q3', '2011Q4', '2012Q1', '2012Q2',
             '2012Q3', '2012Q4', '2013Q1', '2013Q2', '2013Q3', '2013Q4',
             '2014Q1', '2014Q2', '2014Q3', '2014Q4', '2015Q1', '2015Q2',
             '2015Q3', '2015Q4', '2016Q1', '2016Q2', '2016Q3', '2016Q4',
             '2017Q1', '2017Q2', '2017Q3', '2017Q4', '2018Q1'],
            dtype='period[Q-DEC]', freq='Q-DEC')

这样活得的就是一个 list, 其中的每个元素都是一个 period 对象, 因此都可以调用我们之前所讲到的方法, 比如起始时间:

idx[0].start_time

输出:

Timestamp('2011-01-01 00:00:00')

以及结束时间:

idx[0].end_time

输出:

Timestamp('2011-03-31 23:59:59.999999999')

period_range() 函数还可以通过如下方式传参, 以设定取值范围:

idx = pd.period_range('2011', periods=10, freq='Q')
idx

输出:

PeriodIndex(['2011Q1', '2011Q2', '2011Q3', '2011Q4', '2012Q1', '2012Q2',
             '2012Q3', '2012Q4', '2013Q1', '2013Q2'],
            dtype='period[Q-DEC]', freq='Q-DEC')

继续, 看下面这个例子:

import numpy as np
ps = pd.Series(np.random.randn(len(idx)), idx)
ps

结构稍显复杂, 解释一下, 首先利用 numpy 的 random.randn()函数生成一些随机浮点数, 在这里是传入了 idx 的长度作为参数, 所以就会生成 10个随机的浮点数, 并且是以数组的形式返回. 然后是用 Pandas 的 Series()函数给这个数组加上索引, (按照我前面讲过的方法, 按下 shift+tab 就可以查看任意函数的用法, 这里 Series() 函数的第一个参数刚好是数组, 第二个参数就是索引), 索引的值, 就是我们上面生成的 period 对象:

2011Q1   -0.108024
2011Q2   -0.535832
2011Q3    1.258304
2011Q4   -0.490206
2012Q1   -1.517975
2012Q2    0.329804
2012Q3   -0.017833
2012Q4   -1.739612
2013Q1   -0.349370
2013Q2    0.341614
Freq: Q-DEC, dtype: float64

查看数组的索引:

ps.index

输出:

PeriodIndex(['2011Q1', '2011Q2', '2011Q3', '2011Q4', '2012Q1', '2012Q2',
             '2012Q3', '2012Q4', '2013Q1', '2013Q2'],
            dtype='period[Q-DEC]', freq='Q-DEC')

按年份查看数据:

ps['2011']

输出:

2011Q1   -0.108024
2011Q2   -0.535832
2011Q3    1.258304
2011Q4   -0.490206
Freq: Q-DEC, dtype: float64

跨年查看数据:

ps['2011':'2013']

输出:

2011Q1   -0.108024
2011Q2   -0.535832
2011Q3    1.258304
2011Q4   -0.490206
2012Q1   -1.517975
2012Q2    0.329804
2012Q3   -0.017833
2012Q4   -1.739612
2013Q1   -0.349370
2013Q2    0.341614
Freq: Q-DEC, dtype: float64

如果觉得 Q1, Q2 这种形式不符合人的阅读习惯, 还可以将其转为正常的日期格式:

pst = ps.to_timestamp()
pst

输出:

2011-01-01   -0.108024
2011-04-01   -0.535832
2011-07-01    1.258304
2011-10-01   -0.490206
2012-01-01   -1.517975
2012-04-01    0.329804
2012-07-01   -0.017833
2012-10-01   -1.739612
2013-01-01   -0.349370
2013-04-01    0.341614
Freq: QS-OCT, dtype: float64

再开查看一下改变后的索引:

pst.index

输出:

DatetimeIndex(['2011-01-01', '2011-04-01', '2011-07-01', '2011-10-01',
               '2012-01-01', '2012-04-01', '2012-07-01', '2012-10-01',
               '2013-01-01', '2013-04-01'],
              dtype='datetime64[ns]', freq='QS-OCT')

当然, 还可以再转回去:

pst.to_period()

输出:

2011Q1   -0.108024
2011Q2   -0.535832
2011Q3    1.258304
2011Q4   -0.490206
2012Q1   -1.517975
2012Q2    0.329804
2012Q3   -0.017833
2012Q4   -1.739612
2013Q1   -0.349370
2013Q2    0.341614
Freq: Q-DEC, dtype: float64

再来举一个现实的例子, 请看下图, 上面是我们从 csv 文件直接导过来的数据格式, 但是我们希望转换成下面的格式, 首先是让季度时间段作为索引列, 并且加上每个季度的起始时间和结束时间:

Pandas 基础(18) - Period and PeriodIndex

首先我把 csv 文件的截图放在这里, 大家需要手动敲一下:

Pandas 基础(18) - Period and PeriodIndex

引入文件:

import pandas as pd
df = pd.read_csv('/Users/rachel/Sites/pandas/py/pandas/18_ts_period/wmt.csv')
df

输出:

Pandas 基础(18) - Period and PeriodIndex

设置索引列:

df.set_index('Line Item', inplace=True)
df

输出:

Pandas 基础(18) - Period and PeriodIndex

转换索引列:

df = df.T
df

输出:

Pandas 基础(18) - Period and PeriodIndex

获取这个数据表的索引 list:

df.index

输出:

Index(['2017Q1', '2017Q2', '2017Q3', '2017Q4', '2018Q1'], dtype='object')

利用 Pandas 的 PeriodIndex()函数, 索引 list 的数据格式改为 period 对象的 list:

df.index = pd.PeriodIndex(df.index, freq = 'Q')
df.index

输出:

PeriodIndex(['2017Q1', '2017Q2', '2017Q3', '2017Q4', '2018Q1'], dtype='period[Q-DEC]', freq='Q-DEC')

转换为 period 对象就是为了可以调用 start_time()和 end_time()函数.
接下来就是为 df 增加两个字段:

df['start time'] = df.index.map(lambda x: x.start_time)
df

输出:

Pandas 基础(18) - Period and PeriodIndex

df['end time'] = df.index.map(lambda x: x.end_time)
df

输出:

Pandas 基础(18) - Period and PeriodIndex

以上, 就是这一节的全部内容, 方法零零碎碎的看着有点多, 我觉得也不用一下都记到吧, 主要就是先照着敲一遍, 大概有个印象.

讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

请勿发布不友善或者负能量的内容。与人为善,比聪明更重要!