顧名思義,時間序列(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
同樣,可以將整型或浮點型表示的時間轉換為時間戳。默認的單位是納秒(時間戳單位),示例如下:
- import pandas as pd
- print(pd.Timestamp(1587687255,unit='s'))
輸出結果:
2022-03-19 14:26:39
創建時間范圍
通過 date_range() 方法可以創建某段連續的時間或者固定間隔的時間時間段。該函數提供了三個參數,分別是:
- start:開始時間
- end:結束時間
- freq:時間頻率,默認為 "D"(天)
示例如下:
- import pandas as pd
- #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)]
更改時間頻率
- import pandas as pd
- #修改為按小時
- 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
。示例如下:
- import pandas as pd
- 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。
最后再來看一個示例:
- import pandas as pd
- #傳入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"。示例如下:
- import pandas as pd
- 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 | 季度開始頻率 |
時間周期計算
周期計算,指的是對時間周期進行算術運算,所有的操作將在“頻率”的基礎上執行。
- import pandas as pd
- #S表示秒
- x = pd.Period('2014', freq='S')
- x
輸出結果:
Period('2014-01-01 00:00:00', 'S')
執行計算示例:
- import pandas as pd
- x = pd.Period('2014', freq='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() 方法來創建時間周期范圍。示例如下:
- import pandas as pd
- #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),示例如下:
- import pandas as pd
- p1=pd.Periods("2020-2-3")
- p1.to_timestamp()
輸出結果:
Timestamp('2020-02-03 00:00:00')
創建日期范圍
Pandas 提供了用來創建日期序列的函數 date_range(),該函數的默認頻率為 "D", 也就是“天”。日期序列只包含年、月、日,不包含時、分、秒。
下面是一組簡單的示例,如下所示:
- import pandas as pd
- 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() 來創建日期范圍時,該函數包含結束的日期,用數學術語來說就是區間左閉右閉,即包含起始值,也包含結束值。示例如下:
- import pandas as pd
- #建議使用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')
更改日頻率
使用下列方法可以修改頻率,比如按“天”為按“月”,示例如下:
- import pandas as pd
- 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() 不同,它不包括周六、周日。
- import pandas as pd
- 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 類型,下面看一組示例:
- from datetime import 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 pandas as pd
- 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 對象,示例如下:
- import pandas as pd
- print(pd.Timedelta('5 days 8 hours 6 minutes 59 seconds'))
輸出結果:
5 days 08:06:59
整數
通過傳遞整數值和unit
參數也可以創建一個 Timedelta 對象。
- import pandas as pd
- print(pd.Timedelta(19,unit='h'))
輸出結果:
0 days 19:00:00
數據偏移量
數據偏移量, 比如,周(weeks)、天(days)、小時(hours)、分鍾(minutes)、秒(milliseconds)、毫秒、微秒、納秒都可以使用。
- import pandas as pd
- print (pd.Timedelta(days=2,hours=6))
輸出結果:
2 days 06:00:00
to_timedelta()
您可以使用pd.to_timedelta()
方法,將具有 timedelta 格式的值 (標量、數組、列表或 Series)轉換為 Timedelta 類型。如果輸入是 Series,則返回 Series;如果輸入是標量,則返回值也為標量,其他情況輸出 TimedeltaIndex。示例如下:
- import pandas as pd
- 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 對象,並對其做一些算術運算。
- import pandas as pd
- 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
加法運算
- import pandas as pd
- 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 = pd.DataFrame(dict(A = s, B = td))
- #加法運算
- df['C']=df['A']+df['B']
- print(df)
輸出結果:
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
減法運算
- import pandas as pd
- s = pd.Series(pd.date_range('2012-1-1', periods=3, freq='D'))
- td = pd.Series([ pd.Timedelta(days=i) for i in range(3) ])
- df = pd.DataFrame(dict(A = s, B = td))
- df['C']=df['A']+df['B']
- df['D']=df['C']-df['B']
- print(df)
輸出結果:
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
------------------------------------------------------