1. period时期数据

1.1 pd.Period()创建时期数据

1) pd.Period()参数:一个时间戳 + freq 参数 → freq 用于指明该 period 的长度,时间戳则说明该 period 在时间轴上的位置

import pandas as pd

p = pd.Period('2020', freq = 'M')
print(p)
print(type(p))

–> 输出的结果为:(输出的结果为2020年的第一个月份的日期数据)

2020-01
<class 'pandas._libs.tslibs.period.Period'>

2) 可以通过加减运算进行(年、月)日期数据的变换

print(p + 1)
print(p - 2)
print(pd.Period('2020', freq = 'A-DEC') - 1)

–> 输出的结果为:

2020-02
2019-11
2019
1.2 pd.period_range()创建时期范围

1) 简单demo

prng = pd.period_range('1/1/2020', '1/1/2021', freq='M')
print(prng)
print(type(prng))
print(prng[0])
print(type(prng[0]))

–> 输出的结果为:

PeriodIndex(['2020-01', '2020-02', '2020-03', '2020-04', '2020-05', '2020-06',
             '2020-07', '2020-08', '2020-09', '2020-10', '2020-11', '2020-12',
             '2021-01'],
            dtype='period[M]', freq='M')
<class 'pandas.core.indexes.period.PeriodIndex'>
2020-01
<class 'pandas._libs.tslibs.period.Period'>

★★★★★2) 如果将生成的时间索引转化为我们日常中见到的字符串数据的话,如下

print([str(prng[i]) for i in range(len(prng))])
month_day = list(zip(prng.month,prng.day))
print(month_day)

–> 输出的结果为:(可以对比上一篇的将时间戳索引转化为字符串数据的方式,如果也是用这种方式会怎么样)

['2020-01', '2020-02', '2020-03', '2020-04', '2020-05', '2020-06', '2020-07', '2020-08', '2020-09', '2020-10', '2020-11', '2020-12', '2021-01']

[(1, 31), (2, 29), (3, 31), (4, 30), (5, 31), (6, 30), (7, 31), (8, 31), (9, 30), (10, 31), (11, 30), (12, 31), (1, 31)]

★★★★★ 3) 对比一下上一个博客中关于时间戳索引转化为字符串数据

data = pd.date_range('2020','2021', freq = 'M')
print([str(data[i]) for i in range(len(data))])

–> 输出的结果为:(通过两者的对比,就可以更清楚的了解什么是时间戳索引和日期索引,上面输出月和天就是为了和下面的输出做对比)

['2020-01-31 00:00:00', '2020-02-29 00:00:00', '2020-03-31 00:00:00', '2020-04-30 00:00:00', '2020-05-31 00:00:00', '2020-06-30 00:00:00', '2020-07-31 00:00:00', '2020-08-31 00:00:00', '2020-09-30 00:00:00', '2020-10-31 00:00:00', '2020-11-30 00:00:00', '2020-12-31 00:00:00']

4) 创建时期数据的TimeSeries时间序列

ts = pd.Series(np.random.rand(len(prng)), index = prng)
print(ts,type(ts))
print(ts.index)

–> 输出的结果为:(标签为时期数据,后面是数值的Series,和之前的时刻数据类似,一个是时刻数据,一个是时间段)

2020-01    0.733202
2020-02    0.330304
2020-03    0.079378
2020-04    0.836970
2020-05    0.540214
2020-06    0.423610
2020-07    0.944636
2020-08    0.617366
2020-09    0.223554
2020-10    0.057547
2020-11    0.567743
2020-12    0.121468
2021-01    0.196632
Freq: M, dtype: float64 <class 'pandas.core.series.Series'>

PeriodIndex(['2020-01', '2020-02', '2020-03', '2020-04', '2020-05', '2020-06',
             '2020-07', '2020-08', '2020-09', '2020-10', '2020-11', '2020-12',
             '2021-01'],
            dtype='period[M]', freq='M')
1.3 频率转换

在numpy中进行数据类型的转换,使用到了astype()的方法,而在pandas里面要进行时间频率的转换有点类似,是通过.asfreq(freq, method=None, how=None)方法转换成别的频率

p = pd.Period('2020','A-DEC')
print(p)
print(p.asfreq('M', how = 'start'))  # 也可写 how = 's'
print(p.asfreq('D', how = 'end'))  # 也可写 how = 'e'

–> 输出的结果为:

2020
2020-01
2020-12-31

★★★★★ 将时期索引(时期对应的时间序列)转化为时刻索引(时刻对应的时间序列)

prng = pd.period_range('2020','2021',freq = 'M')
ts1 = pd.Series(np.random.rand(len(prng)), index = prng)
ts2 = pd.Series(np.random.rand(len(prng)), index = prng.asfreq('D', how = 'start'))
print(ts1.head())
print(type(ts1.index))
print(ts2.head())
print(type(ts2.index))

–> 输出的结果为:(注意这里转换频率后,数据类型是不变的,并不是真正变成了时刻数据,仍然还是时期数据,只是形式上和之前的时刻索引一致)

2020-01    0.017181
2020-02    0.193328
2020-03    0.047001
2020-04    0.043000
2020-05    0.295609
Freq: M, dtype: float64 
<class 'pandas.core.indexes.period.PeriodIndex'>

2020-01-01    0.801138
2020-02-01    0.654645
2020-03-01    0.185378
2020-04-01    0.357173
2020-05-01    0.122337
Freq: D, dtype: float64 
<class 'pandas.core.indexes.period.PeriodIndex'>
1.4 时刻与时期数据之间的转换

上面的示例可以发现并没有实现真正上的时刻(时间戳)数据与时期数据之间的转换,那么接下来就是实现真正意义上的数据类型的转换,使用的方法是:pd.to_period()pd.to_timestamp()

1) 时刻转时期

rng = pd.date_range('2020/1/1', periods = 10, freq = 'M')
ts1 = pd.Series(np.random.rand(len(rng)), index = rng)
ts2 = ts1.to_period()

print(ts1.head())
print(type(ts1.index))
print(ts2.head())
print(type(ts2.index))

–> 输出的结果为:(实现时刻数据向时期数据的转化)

2020-01-31    0.181266
2020-02-29    0.934712
2020-03-31    0.179842
2020-04-30    0.372101
2020-05-31    0.799920
Freq: M, dtype: float64
<class 'pandas.core.indexes.datetimes.DatetimeIndex'>

2020-01    0.181266
2020-02    0.934712
2020-03    0.179842
2020-04    0.372101
2020-05    0.799920
Freq: M, dtype: float64
<class 'pandas.core.indexes.period.PeriodIndex'>

2) 时期转时刻

prng = pd.period_range('2020','2021', freq = 'M')
ts3 = pd.Series(np.random.rand(len(prng)), index = prng)
ts4 = ts3.to_timestamp()
print(ts3.head())
print(type(ts3.index))
print(ts4.head())
print(type(ts4.index))

–> 输出的结果为:(实现时期数据向时刻数据的转化)

2020-01    0.287591
2020-02    0.056996
2020-03    0.566121
2020-04    0.725879
2020-05    0.067077
Freq: M, dtype: float64
<class 'pandas.core.indexes.period.PeriodIndex'>

2020-01-01    0.287591
2020-02-01    0.056996
2020-03-01    0.566121
2020-04-01    0.725879
2020-05-01    0.067077
Freq: MS, dtype: float64
<class 'pandas.core.indexes.datetimes.DatetimeIndex'>

2. 时间序列 - 索引及切片

TimeSeriesSeries的一个子类,所以Series索引及数据选取方面的方法基本一样;同时TimeSeries通过时间序列有更便捷的方法做索引和切片;时间序列由于按照时间先后排序,故不用考虑顺序问题

1)简单索引

from datetime import datetime

rng = pd.date_range('2020/1','2020/3')
ts = pd.Series(np.random.rand(len(rng)), index = rng)
print(ts.head())

print(ts[0])

–> 输出的结果为:

2020-01-01    0.402184
2020-01-02    0.435946
2020-01-03    0.524105
2020-01-04    0.605212
2020-01-05    0.852766
Freq: D, dtype: float64

0.40218382128573316

2) 时间序列标签索引,支持各种时间字符串,以及datetime.datetime

print(ts['2020/1/2'])
print(ts['20200103'])
print(ts['1/10/2020'])
print(ts[datetime(2020,1,20)])

–> 输出的结果为:(可以实现多种日期字符串形式的索引)

0.6968196406360381
0.3747735841244546
0.3420296886910025
0.11972763328609326

3) 切片

★★★★★ 关于第三种方式的切片特别实用,比如调用某一个月的数据,进行查看或者处理

rng = pd.date_range('2020/1','2020/3',freq = '12H')
ts = pd.Series(np.random.rand(len(rng)), index = rng)

print(ts[:2])
print(ts['2020/1/5':'2020/1/10'])
print(ts['2020/2'].head())

–> 输出的结果为:(三个不同方式的切片,第一个直接按照行数切片,第二个按照索引切片,第三个直接传入月份进行切片)

2020-01-01 00:00:00    0.182351
2020-01-01 12:00:00    0.203575
Freq: 12H, dtype: float64

2020-01-05 00:00:00    0.805461
2020-01-05 12:00:00    0.728251
2020-01-06 00:00:00    0.065754
2020-01-06 12:00:00    0.606569
2020-01-07 00:00:00    0.801891
2020-01-07 12:00:00    0.995801
2020-01-08 00:00:00    0.056166
2020-01-08 12:00:00    0.110309
2020-01-09 00:00:00    0.195206
2020-01-09 12:00:00    0.984065
2020-01-10 00:00:00    0.464639
2020-01-10 12:00:00    0.574147
Freq: 12H, dtype: float64

2020-02-01 00:00:00    0.804735
2020-02-01 12:00:00    0.134206
2020-02-02 00:00:00    0.088963
2020-02-02 12:00:00    0.368319
2020-02-03 00:00:00    0.602443
Freq: 12H, dtype: float64

4) 重复索引的时间序列

有时候,日期数据里面并不止一个时间标签,结果就是一个标签对应多个数据,检查标签和数值是否重复的方式为:is_unique

dates = pd.DatetimeIndex(['1/1/2020','1/2/2020','1/3/2020','1/4/2020','1/1/2020','1/2/2020'])
ts = pd.Series(np.random.rand(6), index = dates)
print(ts)
print(ts.is_unique,ts.index.is_unique)

–> 输出的结果为:

2020-01-01    0.650634
2020-01-02    0.272747
2020-01-03    0.627082
2020-01-04    0.182520
2020-01-01    0.455632
2020-01-02    0.869520
dtype: float64

True False

index有重复的索引时候将返回多个值

print(ts['20200101'],type(ts['20200101']))
print(ts['20200104'],type(ts['20200104']))

–> 输出的结果为:

2020-01-01    0.650634
2020-01-01    0.455632
dtype: float64 <class 'pandas.core.series.Series'>

2020-01-04    0.18252
dtype: float64 <class 'pandas.core.series.Series'>

如果要处理同一标签对应的数据,可以在分组的时候添加level = 0 这个参数,也就是在标签数据进行唯一值处理(按照标签值进行分组)

print(ts.groupby(level = 0).mean())

–> 输出的结果为:(这里选择的处理方式为,按照平均值处理)

2020-01-01    0.553133
2020-01-02    0.571133
2020-01-03    0.627082
2020-01-04    0.182520
dtype: float64
Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐