欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【python数据分析(18)】Pandas中时间序列处理(4)pd.to_period()与pd.to_timestamp()数据之间转换以及时间序列索引及切片

程序员文章站 2022-05-07 15:13:20
...

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