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('')
DatetimeIndex中的各个标量值是pandas的Timestamp对象。
1 >>> ts.index.dtype 2 dtype('') 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
1.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 >>>
1.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 >>>