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. 时间序列 - 索引及切片

​TimeSeries​​​是​​Series​​​的一个子类,所以​​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:

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: