顧名思義,時間序列(time series),就是由時間構成的序列,它指的是在一定時間内按照時間順序測量的某個變量的取值序列,比如一天内的溫度會随時間而發生變化,或者股票的價格會随着時間不斷的波動,這裡用到的一系列時間,就可以看做時間序列。時間序列包含三種應用場景,分别是:
- 特定的時刻(timestamp),也就是時間戳;
- 固定的日期(period),比如某年某月某日;
- 時間間隔(interval),每隔一段時間具有規律性;
在處理時間序列的過程中,我們一般會遇到兩個問題,第一,如何建立時間序列;第二,如何更改已生成時間序列的頻率。 Pandas 為解決上述問題提供了一套簡單、易用的方法。
下面用 Python 内置的 datetime 子產品來擷取目前時間,通過該子產品提供的
now()
方法即可實作。
- from datetime import datetime
- #資料類型為datetime
- print(datetime.now())
輸出結果:
2020-12-16 16:36:18.791297
建立時間戳
TimeStamp(時間戳) 是時間序列中的最基本的資料類型,它将數值與時間點完美結合在一起。Pandas 使用下列方法建立時間戳:
- import pandas as pd
- print (pd.Timestamp('2017-03-01'))
2017-03-01 00:00:00
同樣,可以将整型或浮點型表示的時間轉換為時間戳。預設的機關是納秒(時間戳機關),示例如下:
- print(pd.Timestamp(1587687255,unit='s'))
2022-03-19 14:26:39
建立時間範圍
通過 date_range() 方法可以建立某段連續的時間或者固定間隔的時間時間段。該函數提供了三個參數,分别是:
- start:開始時間
- end:結束時間
- freq:時間頻率,預設為 "D"(天)
示例如下:
- #freq表示時間頻率,每30min變化一次
- print(pd.date_range("9:00", "18:10", freq="30min").time)
[datetime.time(9, 0) datetime.time(9, 30) datetime.time(10, 0)
datetime.time(10, 30) datetime.time(11, 0) datetime.time(11, 30)
datetime.time(12, 0) datetime.time(12, 30) datetime.time(13, 0)
datetime.time(13, 30) datetime.time(14, 0) datetime.time(14, 30)
datetime.time(15, 0) datetime.time(15, 30) datetime.time(16, 0)
datetime.time(16, 30) datetime.time(17, 0) datetime.time(17, 30)
datetime.time(18, 0)]
更改時間頻率
- #修改為按小時
- print(pd.date_range("6:10", "11:45", freq="H").time)
[datetime.time(6, 10) datetime.time(7, 10) datetime.time(8, 10)
datetime.time(9, 10) datetime.time(10, 10) datetime.time(11, 10)]
轉化為時間戳
您可以使用 to_datetime() 函數将 series 或 list 轉換為日期對象,其中 list 會轉換為
DatetimeIndex
。示例如下:
- print(pd.to_datetime(pd.Series(['Jun 3, 2020','2020-12-10', None])))
- 0 2020-06-03
- 1 2020-12-10
- 2 NaT
- dtype: datetime64[ns]
注意:NaT 表示的不是時間 ,它等效于 NaN。
最後再來看一個示例:
- #傳入list,生成Datetimeindex
- print(pd.to_datetime(['Jun 31, 2020','2020-12-10', None]))
DatetimeIndex(['2020-06-03', '2020-12-10', 'NaT'], dtype='datetime64[ns]', freq=None)
頻率和周期轉換
Time Periods 表示時間跨度,一段時間周期,它被定義在 Pandas Periods 類中,通過該類提供的方法可以實作将頻率轉換為周期。比如 Periods() 方法,可以将頻率 "M"(月)轉換為 Period(時間段)。
下面示例,使用 asfreq() 和 start 參數,列印 "01" ,若使用 end 參數,則列印 "31"。示例如下:
- x = pd.Period('2014', freq='M')
- #start參數
- x.asfreq('D', 'start')
- #end參數
- x.asfreq('D', 'end')
輸出結果:
Period('2014-01-01', 'D')
Period('2014-01-31', 'D')
對于常用的時間序列頻率,Pandas 為其規定了一些字元串别名,我們将這些别名稱為“offset(偏移量)”。如下表所示:
别名 | 描述 | ||
---|---|---|---|
B | 工作日頻率 | BQS | 工作季度開始頻率 |
D | 月曆日頻率 | A | 年終頻率 |
W | 每周頻率 | BA | 工作年度結束頻率 |
M | 月末頻率 | BAS | 工作年度開始頻率 |
SM | 半月結束頻率 | BH | 營業時間頻率 |
BM | 工作月結束頻率 | H | 小時頻率 |
MS | 月開始頻率 | T,min | 每分鐘頻率 |
SMS | 半月開始頻率 | S | 每秒鐘頻率 |
BMS | 工作月開始頻率 | L,ms | 毫秒 |
Q | 季末頻率 | U,us | 微妙 |
BQ | 工作季度結束頻率 | N | 納秒 |
QS | 季度開始頻率 |
時間周期計算
周期計算,指的是對時間周期進行算術運算,所有的操作将在“頻率”的基礎上執行。
- #S表示秒
- x = pd.Period('2014', freq='S')
- x
Period('2014-01-01 00:00:00', 'S')
執行計算示例:
- #加1s的時間
- print(x+1)
Period('2014-01-01 00:00:01', 'S')
再看一組完整的示例:
- #定義時期period,預設freq="Y"年份
- p1=pd.Period('2020')
- p2=pd.Period('2019')
- #使用f''格式化輸出
- print(f'p1={p1}年')
- print(f'p2={p2}年')
- print(f'p1和p2間隔{p1-p2}年')
- #f''表示字元串格式化輸出
- print(f'五年前是{p1-5}年')
p1=2020年
p2=2019年
p1和p2間隔<YearEnd: month=12>年
五年前是2015年
建立時間周期
我們可以使用 period_range() 方法來建立時間周期範圍。示例如下:
- #Y表示年
- p = pd.period_range('2016','2018', freq='Y')
- p
PeriodIndex(['2016', '2017', '2018'], dtype='period[A-DEC]', freq='A-DEC')
時間序列轉換
如果想要把字元串日期轉換為 Period,首先需要将字元串轉換為日期格式,然後再将日期轉換為 Period。示例如下:
- # 建立時間序列
- index=pd.date_range("2020-03-17","2020-03-30",freq="1.5H")
- #随機選取4個互不相同的數
- loc=np.random.choice(np.arange(len(index)),size=4,replace=False)
- loc.sort()
- ts_index=index[loc]
- ts_index
- pd_index=ts_index.to_periods('D')
- pd_index()
DatetimeIndex(['2020-03-17 12:00:00', '2020-03-22 04:30:00',
'2020-03-27 03:00:00', '2020-03-30 00:00:00'],
dtype='datetime64[ns]', freq=None)
PeriodIndex(['2020-03-17', '2020-03-19', '2020-03-19', '2020-03-27'], dtype='period[D]', freq='D')
使用 to_timestamp() 能夠将 Period 時期轉換為時間戳(timestamp),示例如下:
- p1=pd.Periods("2020-2-3")
- p1.to_timestamp()
Timestamp('2020-02-03 00:00:00')
建立日期範圍
Pandas 提供了用來建立日期序列的函數 date_range(),該函數的預設頻率為 "D", 也就是“天”。日期序列隻包含年、月、日,不包含時、分、秒。
下面是一組簡單的示例,如下所示:
- print(pd.date_range('12/15/2020', periods=10))
DatetimeIndex(['2020-12-15', '2020-12-16', '2020-12-17', '2020-12-18',
'2020-12-19', '2020-12-20', '2020-12-21', '2020-12-22',
'2020-12-23', '2020-12-24'],
dtype='datetime64[ns]', freq='D')
當我們使用 date_range() 來建立日期範圍時,該函數包含結束的日期,用數學術語來說就是區間左閉右閉,即包含起始值,也包含結束值。示例如下:
- #建議使用Python的datetime子產品建立時間
- start = pd.datetime(2019, 1, 1)
- end = pd.datetime(2019, 1, 5)
- print pd.date_range(start,end)
DatetimeIndex(['2019-01-01', '2019-01-02', '2019-01-03', '2019-01-04','2019-01-05']
,dtype='datetime64[ns]', freq='D')
更改日頻率
使用下列方法可以修改頻率,比如按“天”為按“月”,示例如下:
- print(pd.date_range('12/15/2011', periods=5,freq='M'))
DatetimeIndex(['2020-12-31', '2021-01-31', '2021-02-28', '2021-03-31',
'2021-04-30'],dtype='datetime64[ns]', freq='M')
工作日時間
bdate_range() 表示建立工作日的日期範圍,它與 date_range() 不同,它不包括周六、周日。
- print(pd.date_range('11/25/2020', periods=8))
DatetimeIndex(['2020-11-25', '2020-11-26', '2020-11-27', '2020-11-28','2020-11-29', '2020-11-30', '2020-12-01', '2020-12-02'],dtype='datetime64[ns]', freq='D')
上述方法中,date_range() 預設頻率是月曆日,而 bdate_range() 的預設頻率是工作日。
----------------------------------------------------------------‘’
日期格式化符号
在對時間進行格式化處理時,它們都有固定的表示格式,比如小時的格式化符号為
%H
,分鐘簡寫為
%M
,秒簡寫為
%S
。下表對常用的日期格式化符号做了總結:
符号 | 說明 |
---|---|
%y | 兩位數的年份表示(00-99) |
%Y | 四位數的年份表示(000-9999) |
%m | 月份(01-12) |
%d | 月内中的一天(0-31) |
%H | 24小時制小時數(0-23) |
%I | 12小時制小時數(01-12) |
%M | 分鐘數(00=59) |
%S | 秒(00-59) |
%a | 本地英文縮寫星期名稱 |
%A | 本地英文完整星期名稱 |
%b | 本地縮寫英文的月份名稱 |
%B | 本地完整英文的月份名稱 |
%w | 星期(0-6),星期天為星期的開始 |
%W | 一年中的星期數(00-53)星期一為星期的開始 |
%x | 本地相應的日期表示 |
%X | 本地相應的時間表示 |
%Z | 目前時區的名稱 |
%U | 一年中的星期數(00-53)星期天為星期的開始 |
%j | 年内的一天(001-366) |
%c | 本地相應的日期表示和時間表示 |
Python處理
Python 内置的 strptime() 方法能夠将字元串日期轉換為 datetime 類型,下面看一組示例:
- #将日期定義為字元串
- date_str1 = 'Wednesday, July 18, 2020'
- date_str2 = '18/7/20'
- date_str3 = '18-07-2020'
- #将日期轉化為datetime對象
- dmy_dt1 = datetime.strptime(date_str1, '%A,%B%d,%Y')
- dmy_dt2 = datetime.strptime(date_str2, '%d/%m/%y')
- dmy_dt3 = datetime.strptime(date_str3, '%d-%m-%Y')
- #處理為相同格式,并列印輸出
- print(dmy_dt1)
- print(dmy_dt2)
- print(dmy_dt3)
2020-07-18 00:00:00
2020-07-18 00:00:00
2020-07-18 00:00:00
注意:strftime() 可以将 datetime 類型轉換為字元串類型,恰好與 strptime() 相反。
Pandas處理
除了使用 Python 内置的 strptime() 方法外,你還可以使用 Pandas 子產品的 pd.to_datetime() 和 pd.DatetimeIndex() 進行轉換。
1) to_datetime()
通過 to_datetime() 直接轉換為 datetime 類型
- import numpy as np
- date = ['2012-05-06 11:00:00','2012-05-16 11:00:00']
- pd_date=pd.to_datetime(date)
- df=pd.Series(np.random.randn(2),index=pd_date)
2012-05-06 11:00:00 0.189865
2012-05-16 11:00:00 1.052456
dtype: float64
2) DatetimeIndex()
使用 Datetimeindex() 函數設定時間序,示例如下:
- date = pd.DatetimeIndex(['1/1/2008', '1/2/2008', '1/3/2008', '1/4/2008', '1/5/2008'])
- dt = pd.Series(np.random.randn(5),index = date)
- print(dt)
2008-01-01 1.965619
2008-01-02 -2.897374
2008-01-03 0.625929
2008-01-04 1.204926
2008-01-05 1.755680
dtype: float6-----------------------------------------------------------
Timedelta 表示時間差(或者時間增量),我們可以使用不同的時間機關來表示它,比如,天、小時、分、秒。時間差的最終的結果可以是正時間差,也可以是負時間差。
本節主要介紹建立 Timedelta (時間差)的方法以及與時間差相關的運算法則。
字元串
通過傳遞字元串可以建立 Timedelta 對象,示例如下:
- print(pd.Timedelta('5 days 8 hours 6 minutes 59 seconds'))
輸出結果:
5 days 08:06:59
整數
通過傳遞整數值和 unit 參數也可以建立一個 Timedelta 對象。
- print(pd.Timedelta(19,unit='h'))
輸出結果:
0 days 19:00:00
資料偏移量
資料偏移量, 比如,周(weeks)、天(days)、小時(hours)、分鐘(minutes)、秒(milliseconds)、毫秒、微秒、納秒都可以使用。
- print (pd.Timedelta(days=2,hours=6))
輸出結果:
2 days 06:00:00
to_timedelta()
您可以使用 pd.to_timedelta() 方法,将具有 timedelta 格式的值 (标量、數組、清單或 Series)轉換為 Timedelta 類型。如果輸入是 Series,則傳回 Series;如果輸入是标量,則傳回值也為标量,其他情況輸出 TimedeltaIndex。示例如下:
- print(pd.to_timedelta(['1 days 06:05:01.00003', '15.5us', 'nan']))
- print(pd.to_timedelta(np.arange(5), unit='s'))
輸出結果:
TimedeltaIndex(['1 days 06:05:01.000030', '0 days 00:00:00.000015', NaT],dtype='timedelta64[ns]', freq=None)
TimedeltaIndex(['0 days 00:00:00', '0 days 00:00:01', '0 days 00:00:02','0 days 00:00:03',
'0 days 00:00:04'],dtype='timedelta64[ns]', freq=None)
算術操作
通過對 datetime64[ns] 類型的時間序列或時間戳做算術運算,其運算結果依然是 datetime64[ns] 資料類型。接下來,我們建立一個帶有 Timedelta 與 datetime 的 DataFrame 對象,并對其做一些算術運算。
- s = pd.Series(pd.date_range('2020-1-1', periods=5, freq='D'))
- #推導式用法
- td = pd.Series([ pd.Timedelta(days=i) for i in range(5)])
- df = pd.DataFrame(dict(A = s, B = td))
- print(df)
輸出結果:
A B
0 2020-01-01 0 days
1 2020-01-02 1 days
2 2020-01-03 2 days
3 2020-01-04 3 days
4 2020-01-05 4 days
加法運算
- s = pd.Series(pd.date_range('20120-1-1', periods=3, freq='D'))
- td = pd.Series([ pd.Timedelta(days=i) for i in range(3) ])
- #加法運算
- df['C']=df['A']+df['B']
輸出結果:
A B C
0 2020-01-01 0 days 2020-01-01
1 2020-01-02 1 days 2020-01-03
2 2020-01-03 2 days 2020-01-05
減法運算
- s = pd.Series(pd.date_range('2012-1-1', periods=3, freq='D'))
- df['D']=df['C']-df['B']
輸出結果:
A B C D
0 2019-01-01 0 days 2019-01-01 2019-01-01
1 2019-01-02 1 days 2019-01-03 2019-01-02
2 2019-01-03 2 days 2019-01-05 2019-01-03
------------------------------------------------------