时间序列--时间序列基础
本节pandas库会用到,约定:import pandas as pd
numpy库也会用到,约定:import numpy as np
2 时间序列基础
pandas最基本的时间序列类型就是以时间戳(通常以python字符串或datetime对象表示)为索引的Series。
1 >>> from datetime import datetime
2 >>> dates = [datetime(2020, 1, 23), datetime(2020, 1, 24), datetime(2020, 1, 25)]
3 >>> ts = pd.Series(np.random.randn(3), index=dates)
4 >>> ts
5 2020-01-23 -0.225688
6 2020-01-24 -0.520823
7 2020-01-25 -0.819271
8 dtype: float64
这些datetime对象实际被放在一个DatetimeIndex中,变量ts就变成了一个TimeSeries。跟其它Series一样,不同索引的时间序列之间的算术运算会自动按日期对齐。
1 >>> type(ts)
2 <class 'pandas.core.series.Series'>
3 >>> ts.index
4 DatetimeIndex(['2020-01-23', '2020-01-24', '2020-01-25'], dtype='datetime64[ns]', freq=None)
5 >>> ts + ts[::2]
6 2020-01-23 -2.573547
7 2020-01-24 NaN
8 2020-01-25 -0.967854
9 dtype: float64
10 >>> ts.index.dtype
11 dtype('<M8[ns]')
DatetimeIndex中的各个标量值是pandas的Timestamp对象。
1 >>> ts.index.dtype
2 dtype('<M8[ns]')
3 >>> stamp = ts.index[0]
4 >>> stamp
5 Timestamp('2020-01-23 00:00:00')
6 >>> ts
7 2020-01-23 -1.286773
8 2020-01-24 0.347610
9 2020-01-25 -0.483927
10 dtype: float64
2.1 索引、选取、子集构造
由于TimeSeries是Series的一个之类,所以在索引以及数据选取方面它们的行为是一样的。
也可以通过传入一个可以被解释为日期的字符串进行索引。
1 >>> ts
2 2020-01-23 -1.286773
3 2020-01-24 0.347610
4 2020-01-25 -0.483927
5 dtype: float64
6 >>> stamp= ts.index[2]
7 >>> ts[stamp]
8 -0.48392707723832107
9 >>> ts['1/23/2020']
10 -1.2867733405401018
11 >>> ts['20200123']
12 -1.2867733405401018
对于较长的时间序列,只需传入“年”或“年月”即可轻松获取数据的切片。
1 >>> long_ts = pd.Series(np.random.randn(1000), index=pd.date_range('1/1/2020', periods=1000))
2 >>> long_ts
3 2020-01-01 0.483528
4 2020-01-02 0.083113
5 2020-01-03 -0.355438
6 2020-01-04 -0.163374
7 2020-01-05 -0.629642
8 ...
9 2022-09-22 1.761658
10 2022-09-23 0.594090
11 2022-09-24 0.876740
12 2022-09-25 -0.607211
13 2022-09-26 1.333760
14 Freq: D, Length: 1000, dtype: float64
15 >>> long_ts['2020']
16 2020-01-01 0.483528
17 2020-01-02 0.083113
18 2020-01-03 -0.355438
19 2020-01-04 -0.163374
20 2020-01-05 -0.629642
21 ...
22 2020-12-27 -1.722599
23 2020-12-28 -0.605329
24 2020-12-29 2.414726
25 2020-12-30 -2.142943
26 2020-12-31 -0.263092
27 Freq: D, Length: 366, dtype: float64
28 >>> ts[datetime(2020, 1, 7):]
29 2020-01-23 -1.286773
30 2020-01-24 0.347610
31 2020-01-25 -0.483927
32 dtype: float64
33 >>> ts #影响了源时间序列
34 2020-01-23 -1.286773
35 2020-01-24 0.347610
36 2020-01-25 -0.483927
37 dtype: float64
切片操作可以传入字符串日期、datetime或timestamp。这样切片所产生的是源时间序列的视图。
另外,还有一个等价的实例方法truncate也可以截取两个日期之间的TimeSeries。
1 >>> ts.truncate(after='1/24/2020')
2 2020-01-23 -1.286773
3 2020-01-24 0.347610
4 dtype: float64
5 >>> ts
6 2020-01-23 -1.286773
7 2020-01-24 0.347610
8 2020-01-25 -0.483927
9 dtype: float64
上述操作对DataFrame也有效。
1 >>> dates = pd.date_range('1/1/2000', periods=100, freq='W-WED')
2 >>> long_df = pd.DataFrame(np.random.randn(100, 4), index=dates, columns=['Co', 'Te', 'New', 'Oh'])
3 >>> long_df.loc['5-2001']
4 Co Te New Oh
5 2001-05-02 -1.096373 -0.628539 0.055700 -1.806065
6 2001-05-09 -2.037862 0.116222 0.572079 -0.122774
7 2001-05-16 -0.934510 1.650582 0.084567 1.361691
8 2001-05-23 -1.289954 0.647815 -0.855843 -1.201742
9 2001-05-30 0.958377 -0.122075 0.637788 -1.001172
10 >>>
2.2 带有重复索引的时间序列**
在某些场景中,可能存在多个观测数据落在同一个时间点上的情况。通过is_unique属性,就知道它是否是唯一的。
1 >>> dates = pd.DatetimeIndex(['1/1/2020', '1/2/2020', '1/2/2020', '1/3/2020', '1/4/2020'])
2 >>> dup_ts = pd.Series(np.arange(5), index=dates)
3 >>> dup_ts.index.is_unique
4 False
5 >>> dup_ts
6 2020-01-01 0
7 2020-01-02 1
8 2020-01-02 2
9 2020-01-03 3
10 2020-01-04 4
11 dtype: int32
对这个时间序列进行索引,要么产生标量值,要么产生切片。具体要看所选的时间点是否重复。
1 >>> dup_ts['1/1/2020']
2 0
3 >>> dup_ts['1/2/2020']
4 2020-01-02 1
5 2020-01-02 2
6 dtype: int32
7 >>>
如果想要对具有非唯一时间戳的数据进行聚合,一个方法是使用groupby,并传入level=0(索引的唯一一层)。
1 >>> grouped = dup_ts.groupby(level=0)
2 >>> grouped.mean()
3 2020-01-01 0.0
4 2020-01-02 1.5
5 2020-01-03 3.0
6 2020-01-04 4.0
7 dtype: float64
8 >>> grouped.count()
9 2020-01-01 1
10 2020-01-02 2
11 2020-01-03 1
12 2020-01-04 1
13 dtype: int64
14 >>>