時間序列--日期的范圍、頻率及移動


pandas中的時間序列一般被認為是不規則的,也就是說,沒有固定的頻率。但pandas有一整套標准時間序列頻率以及用於重采樣、頻率推斷、生成固定頻率日期范圍的工具。例如將一個時間序列轉換為固定頻率的時間序列,只需要調用resample即可。

頻率的轉換(或重采樣)是一個大的主題,這里先介紹如何使用基本的頻率。

1.1 生成日期范圍

pandas.date_range()可用於生成指定長度的DatetimeIndex。

1 >>> index = pd.date_range('1/1/2020', '1/10/2020')  
2 >>> index
3 DatetimeIndex(['2020-01-01', '2020-01-02', '2020-01-03', '2020-01-04',
4                '2020-01-05', '2020-01-06', '2020-01-07', '2020-01-08',
5                '2020-01-09', '2020-01-10'],
6               dtype='datetime64[ns]', freq='D')
7 >>>

默認情況下,date_range會產生按天計算的時間點,如果只傳入起始或結束日期。那就還得傳入一個表示一段時間的數字。

 1 >>> pd.date_range(start='1/1/2020', periods=20)
 2 DatetimeIndex(['2020-01-01', '2020-01-02', '2020-01-03', '2020-01-04',
 3                '2020-01-05', '2020-01-06', '2020-01-07', '2020-01-08',
 4                '2020-01-09', '2020-01-10', '2020-01-11', '2020-01-12',
 5                '2020-01-13', '2020-01-14', '2020-01-15', '2020-01-16',
 6                '2020-01-17', '2020-01-18', '2020-01-19', '2020-01-20'],
 7               dtype='datetime64[ns]', freq='D')
 8 >>> pd.date_range(end='1/20/2020', periods=20) 
 9 DatetimeIndex(['2020-01-01', '2020-01-02', '2020-01-03', '2020-01-04',
10                '2020-01-05', '2020-01-06', '2020-01-07', '2020-01-08',
11                '2020-01-09', '2020-01-10', '2020-01-11', '2020-01-12',
12                '2020-01-13', '2020-01-14', '2020-01-15', '2020-01-16',
13                '2020-01-17', '2020-01-18', '2020-01-19', '2020-01-20'],
14               dtype='datetime64[ns]', freq='D')
15 >>>

起始和結束日期定義了日期索引的嚴格邊界。例如,如果你想要生成由每月最后一個工作日組成的日期索引,可以傳入“BM”頻率(表示business end of month),這樣只會包含時間間隔內(或剛好在邊界上)符合頻率要求的日期。

1 >>> pd.date_range('1/1/2000', '12/1/2000', freq='BM') 
2 DatetimeIndex(['2000-01-31', '2000-02-29', '2000-03-31', '2000-04-28',
3                '2000-05-31', '2000-06-30', '2000-07-31', '2000-08-31',
4                '2000-09-29', '2000-10-31', '2000-11-30'],
5               dtype='datetime64[ns]', freq='BM')
6 >>>

date_range默認會保留起始和結束時間戳的時間信息。

1 >>> pd.date_range('5/2/2012 12:56:31', periods=5) 
2 DatetimeIndex(['2012-05-02 12:56:31', '2012-05-03 12:56:31',
3                '2012-05-04 12:56:31', '2012-05-05 12:56:31',
4                '2012-05-06 12:56:31'],
5               dtype='datetime64[ns]', freq='D')

有時,雖然起始和結束日期都帶有時間信息,但希望產生一組被規范化(normalize)到午夜的時間戳,normalize選項即可實現該功能。

1 >>> pd.date_range('5/2/2012 12:56:31', periods=5, normalize=True) 
2 DatetimeIndex(['2012-05-02', '2012-05-03', '2012-05-04', '2012-05-05',
3                '2012-05-06'],
4               dtype='datetime64[ns]', freq='D'

1.2  頻率與日期偏移量

pandas的頻率由一個基礎頻率(base frequency)和一個乘數組成的。基礎頻率通常以一個字符串別名表示,比如“M”表示每月,“H”表示每小時。對於每個基礎頻率,都有一個被稱為日期偏移量(date offset)的對象與之對應。如,按小時計算的頻率可以用Hour類表示。

1 >>> from pandas.tseries.offsets import Hour, Minute
2 >>> hour = Hour()
3 >>> hour  
4 <Hour>
5 >>> four_hours = Hour(4)  #定義偏移量的倍數
6 >>> four_hours
7 <4 * Hours>

一般來說,無需顯示創建這樣的對象,只需要使用諸如“H”或“4H”這樣的字符串別名即可。在基礎頻率前放一個整數即可創建倍數。

 1 >>> pd.date_range('1/1/2020', '1/3/2020 23:59', freq='4H') 
 2 DatetimeIndex(['2020-01-01 00:00:00', '2020-01-01 04:00:00',
 3                '2020-01-01 08:00:00', '2020-01-01 12:00:00',
 4                '2020-01-01 16:00:00', '2020-01-01 20:00:00',
 5                '2020-01-02 00:00:00', '2020-01-02 04:00:00',
 6                '2020-01-02 08:00:00', '2020-01-02 12:00:00',
 7                '2020-01-02 16:00:00', '2020-01-02 20:00:00',
 8                '2020-01-03 00:00:00', '2020-01-03 04:00:00',
 9                '2020-01-03 08:00:00', '2020-01-03 12:00:00',
10                '2020-01-03 16:00:00', '2020-01-03 20:00:00'],
11               dtype='datetime64[ns]', freq='4H')

大部分偏移量對象可通過加法進行連接。

1 >>> Hour(2) + Minute(30) 
2 <150 * Minutes>

同理,也可以傳入頻率字符串,這種字符串可以被高效的解析為等效的表達式。

1 >>> pd.date_range('1/1/2020', periods=10, freq='1h30min') 
2 DatetimeIndex(['2020-01-01 00:00:00', '2020-01-01 01:30:00',
3                '2020-01-01 03:00:00', '2020-01-01 04:30:00',
4                '2020-01-01 06:00:00', '2020-01-01 07:30:00',
5                '2020-01-01 09:00:00', '2020-01-01 10:30:00',
6                '2020-01-01 12:00:00', '2020-01-01 13:30:00'],
7               dtype='datetime64[ns]', freq='90T')

有些頻率說描述的時間點並不是均勻分隔的,例如:“M”(日歷月末)和“BM”(每月最后一個工作日)就取決於每月的天數。對於后者,還要考慮月末是不是周末。我們將這些稱為瞄點偏移量(anchored offset)。下表是pandas中頻率代碼和日期偏移量類。

別名

偏移量類型

說明

D

Day

每日歷日

B

BusinessDay

每工作日

H

Hour

每小時

T或min

Minute

每分

S

Second

每秒

L或ms

Milli

每毫秒(即每千分之一秒)

Y

Micro

每微妙(即每百萬分之一秒)

M

MonthEnd

每月最后一個日歷日

BM

BusinessMonthEnd

每月最后一個工作日

MS

MonthBegin

每月第一個日歷日

BMS

BusinessMonthBegin

每月第一個工作日

W-MON、W-TUE…

Week

從指定的星期幾(MON、TUE、WED、THU、FRI、SAT、SUM)開始算起,每周

WOM-1MON、WOM-2MON…

WeekOfMonth

產生每月第一、第二、第三或第四周的星期幾。例如,WOM-3FRI表示每月第三個星期五

Q-JAN、Q-FEB…

QuarterEnd

對於以指定月份(JAN、FEB、MAR、APR、MAY、JUN、JUL、AUG、SEP、OCT、NOV、DEC)結束的年度,每季度最后一月的最后一個日歷日

BQ-JAN、BQ-FEB…

BusinessQuarterEnd

對於以指定月份結束的年度,每季度最后一月的最后一個工作日

QS-JAN、QS-FEB…

QuarterBegin

對於以指定月份結束的年度,么季度最后一月的第一個日歷日

BQS-JAN、BQS-FEB…

BusinessQuarterBegin

對於以指定月份結束的年度。每季度最后一月的第一個工作日

A-JAN、A-FEB…

YearEnd

每年指定月份的最后一個日歷日

BA-JAN、BA-FEB…

BusinessYearEnd

每年指定月份的最后一個工作日

AS-JAN、AS-FEB…

YearBegin

每年指定月份的第一個日歷日

BAS-JAN、BAS-FEB…

BusinessYearBegin

每年指定月份的第一個工作日

WOM日期:WOM(Week Of Month)是一種很實用的頻率類。它使你能夠獲得諸如“每月第三個星期五”之類的日期:

1 >>> rng = pd.date_range('1/1/2020', '9/1/2020', freq='WOM-3FRI') 
2 >>> list(rng) 
3 [Timestamp('2020-01-17 00:00:00', freq='WOM-3FRI'), Timestamp('2020-02-21 00:00:00', freq='WOM-3FRI'), Timestamp('2020-03-20 00:00:00', freq='WOM-3FRI'), Timestamp('2020-04-17 
4 00:00:00', freq='WOM-3FRI'), Timestamp('2020-05-15 00:00:00', freq='WOM-3FRI'), Timestamp('2020-06-19 00:00:00', freq='WOM-3FRI'), Timestamp('2020-07-17 00:00:00', freq='WOM-3FRI'), Timestamp('2020-08-21 00:00:00', freq='WOM-3FRI')]
5 >>>

1.3  移動(超前或滯后)數據

移動(shifting)指的是沿着時間軸將數據前移或者后移。Series和DataFrame都有一個shift方法用於執行單純的前移或后移操作,保持索引不變。

 1 >>> ts = pd.Series(np.random.randn(4), index=pd.date_range('1/1/2000', periods=4, freq='M'))
 2 >>> ts
 3 2000-01-31   -1.341160
 4 2000-02-29    1.146953
 5 2000-03-31   -1.434801
 6 2000-04-30   -1.175278
 7 Freq: M, dtype: float64
 8 >>> ts.shift(2)
 9 2000-01-31         NaN
10 2000-02-29         NaN
11 2000-03-31   -1.341160
12 2000-04-30    1.146953
13 Freq: M, dtype: float64
14 >>> ts.shift(-2) 
15 2000-01-31   -1.434801
16 2000-02-29   -1.175278
17 2000-03-31         NaN
18 2000-04-30         NaN
19 Freq: M, dtype: float64
20 >>>

shift通常用於計算一個時間序列或多個時間序列(如DataFrame的列)中的百分比變化。可以這樣表達:ts/ts.shift(1) – 1。

由於單純的移位操作不會修改索引,所以部分數據會被丟棄。因此,如果頻率已知,則可以將其傳給shift以便實現對時間戳進行移位而不是對數據進行簡單移位。

 1 >>> ts                      
 2 2000-01-31   -1.341160
 3 2000-02-29    1.146953
 4 2000-03-31   -1.434801
 5 2000-04-30   -1.175278
 6 Freq: M, dtype: float64
 7 >>> ts.shift(2, freq='M') 
 8 2000-03-31   -1.341160
 9 2000-04-30    1.146953
10 2000-05-31   -1.434801
11 2000-06-30   -1.175278
12 Freq: M, dtype: float64
13 >>> ts.shift(3, freq='D') 
14 2000-02-03   -1.341160
15 2000-03-03    1.146953
16 2000-04-03   -1.434801
17 2000-05-03   -1.175278
18 dtype: float64
19 >>> ts.shift(1, freq='3D') 
20 2000-02-03   -1.341160
21 2000-03-03    1.146953
22 2000-04-03   -1.434801
23 2000-05-03   -1.175278
24 dtype: float64
25 >>> ts.shift(1, freq='90T') 
26 2000-01-31 01:30:00   -1.341160
27 2000-02-29 01:30:00    1.146953
28 2000-03-31 01:30:00   -1.434801
29 2000-04-30 01:30:00   -1.175278
30 Freq: M, dtype: float64
31 >>> 

1.4  通過偏移量對日期進行位移

pandas的日期偏移量還可以對用在datetime或timestamp對象上。

如果加的是錨點偏移量(比如MonthEnd),第一次增量會將原日期向前滾動到符合頻率規則的下一個日期。

通過錨點偏移量的rollforward和rollback方法,可以顯示的將日期向前或先后“滾動”。

 1 >>> from pandas.tseries.offsets import Day, MonthEnd
 2 >>> now = datetime(2011, 11, 17) 
 3 >>> now + 3*Day()  #增加錨點偏移量
 4 Timestamp('2011-11-20 00:00:00')
 5 >>> now + MonthEnd()
 6 Timestamp('2011-11-30 00:00:00')
 7 >>> now + MonthEnd(2) 
 8 Timestamp('2011-12-31 00:00:00')
 9 >>> offset = MonthEnd()
10 >>> offset.rollforward(now)  #前滾
11 Timestamp('2011-11-30 00:00:00')
12 >>> offset.rollback(now)    #后滾
13 Timestamp('2011-10-31 00:00:00')

日期偏移量還有一個巧妙地用法,即結合groupby使用這兩個“滾動”方法:

 1 >>> ts = pd.Series(np.random.randn(20), index=pd.date_range('1/15/2000', periods=20, freq='4d'))
 2 >>> ts.groupby(offset.rollforward).mean()
 3 2000-01-31   -0.472525
 4 2000-02-29   -0.328598
 5 2000-03-31   -0.620547
 6 dtype: float64
 7 >>> ts
 8 2000-01-15    1.318127
 9 2000-01-19   -1.589067
10 2000-01-23   -1.157066
11 2000-01-27   -0.621659
12 2000-01-31   -0.312961
13 2000-02-04   -0.839835
14 2000-02-08    0.886033
15 2000-02-12   -0.478009
16 2000-02-16   -0.383263
17 2000-02-20    1.837059
18 2000-02-24   -1.343584
19 2000-02-28   -1.978589
20 2000-03-03   -1.372423
21 2000-03-07   -0.837760
22 2000-03-11   -0.329621
23 2000-03-15   -0.237106
24 2000-03-19   -0.596162
25 2000-03-23   -1.020840
26 2000-03-27   -0.037938
27 2000-03-31   -0.532527
28 Freq: 4D, dtype: float64


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM