天天看點

pandas之時間操作

顧名思義,時間序列(time series),就是由時間構成的序列,它指的是在一定時間内按照時間順序測量的某個變量的取值序列,比如一天内的溫度會随時間而發生變化,或者股票的價格會随着時間不斷的波動,這裡用到的一系列時間,就可以看做時間序列。時間序列包含三種應用場景,分别是:

  • 特定的時刻(timestamp),也就是時間戳;
  • 固定的日期(period),比如某年某月某日;
  • 時間間隔(interval),每隔一段時間具有規律性;

在處理時間序列的過程中,我們一般會遇到兩個問題,第一,如何建立時間序列;第二,如何更改已生成時間序列的頻率。 Pandas 為解決上述問題提供了一套簡單、易用的方法。

下面用 Python 内置的 datetime 子產品來擷取目前時間,通過該子產品提供的

now()

方法即可實作。

  1. from datetime import datetime
  2. #資料類型為datetime
  3. print(datetime.now())

輸出結果:

2020-12-16 16:36:18.791297

建立時間戳

TimeStamp(時間戳) 是時間序列中的最基本的資料類型,它将數值與時間點完美結合在一起。Pandas 使用下列方法建立時間戳:

  1. import pandas as pd
  2. print (pd.Timestamp('2017-03-01'))

2017-03-01 00:00:00

同樣,可以将整型或浮點型表示的時間轉換為時間戳。預設的機關是納秒(時間戳機關),示例如下:

  1. print(pd.Timestamp(1587687255,unit='s'))

2022-03-19 14:26:39

建立時間範圍

通過 date_range() 方法可以建立某段連續的時間或者固定間隔的時間時間段。該函數提供了三個參數,分别是:

  • start:開始時間
  • end:結束時間
  • freq:時間頻率,預設為 "D"(天)

示例如下:

  1. #freq表示時間頻率,每30min變化一次
  2. 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)]      

更改時間頻率

  1. #修改為按小時
  2. 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

。示例如下:

  1. print(pd.to_datetime(pd.Series(['Jun 3, 2020','2020-12-10', None])))
  1. 0 2020-06-03
  2. 1 2020-12-10
  3. 2 NaT
  4. dtype: datetime64[ns]

注意:NaT 表示的不是時間 ,它等效于 NaN。

最後再來看一個示例:

  1. #傳入list,生成Datetimeindex
  2. 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"。示例如下:

  1. x = pd.Period('2014', freq='M')
  2. #start參數
  3. x.asfreq('D', 'start')
  4. #end參數
  5. 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 季度開始頻率

時間周期計算

周期計算,指的是對時間周期進行算術運算,所有的操作将在“頻率”的基礎上執行。

  1. #S表示秒
  2. x = pd.Period('2014', freq='S')
  3. x

Period('2014-01-01 00:00:00', 'S')

執行計算示例:

  1. #加1s的時間
  2. print(x+1)

Period('2014-01-01 00:00:01', 'S')

再看一組完整的示例:

  1. #定義時期period,預設freq="Y"年份
  2. p1=pd.Period('2020')
  3. p2=pd.Period('2019')
  4. #使用f''格式化輸出
  5. print(f'p1={p1}年')
  6. print(f'p2={p2}年')
  7. print(f'p1和p2間隔{p1-p2}年')
  8. #f''表示字元串格式化輸出
  9. print(f'五年前是{p1-5}年')
p1=2020年
p2=2019年
p1和p2間隔<YearEnd: month=12>年
五年前是2015年      

建立時間周期

我們可以使用 period_range() 方法來建立時間周期範圍。示例如下:

  1. #Y表示年
  2. p = pd.period_range('2016','2018', freq='Y')
  3. p

PeriodIndex(['2016', '2017', '2018'], dtype='period[A-DEC]', freq='A-DEC')

時間序列轉換

如果想要把字元串日期轉換為 Period,首先需要将字元串轉換為日期格式,然後再将日期轉換為 Period。示例如下:

  1. # 建立時間序列
  2. index=pd.date_range("2020-03-17","2020-03-30",freq="1.5H")
  3. #随機選取4個互不相同的數
  4. loc=np.random.choice(np.arange(len(index)),size=4,replace=False)
  5. loc.sort()
  6. ts_index=index[loc]
  7. ts_index
  8. pd_index=ts_index.to_periods('D')
  9. 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),示例如下:

  1. p1=pd.Periods("2020-2-3")
  2. p1.to_timestamp()
Timestamp('2020-02-03 00:00:00')      

建立日期範圍

Pandas 提供了用來建立日期序列的函數 date_range(),該函數的預設頻率為 "D", 也就是“天”。日期序列隻包含年、月、日,不包含時、分、秒。

下面是一組簡單的示例,如下所示:

  1. 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() 來建立日期範圍時,該函數包含結束的日期,用數學術語來說就是區間左閉右閉,即包含起始值,也包含結束值。示例如下:

  1. #建議使用Python的datetime子產品建立時間
  2. start = pd.datetime(2019, 1, 1)
  3. end = pd.datetime(2019, 1, 5)
  4. 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')      

更改日頻率

使用下列方法可以修改頻率,比如按“天”為按“月”,示例如下:

  1. 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() 不同,它不包括周六、周日。

  1. 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 類型,下面看一組示例:

  1. #将日期定義為字元串
  2. date_str1 = 'Wednesday, July 18, 2020'
  3. date_str2 = '18/7/20'
  4. date_str3 = '18-07-2020'
  5. #将日期轉化為datetime對象
  6. dmy_dt1 = datetime.strptime(date_str1, '%A,%B%d,%Y')
  7. dmy_dt2 = datetime.strptime(date_str2, '%d/%m/%y')
  8. dmy_dt3 = datetime.strptime(date_str3, '%d-%m-%Y')
  9. #處理為相同格式,并列印輸出
  10. print(dmy_dt1)
  11. print(dmy_dt2)
  12. 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 類型

  1. import numpy as np
  2. date = ['2012-05-06 11:00:00','2012-05-16 11:00:00']
  3. pd_date=pd.to_datetime(date)
  4. 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() 函數設定時間序,示例如下:

  1. date = pd.DatetimeIndex(['1/1/2008', '1/2/2008', '1/3/2008', '1/4/2008', '1/5/2008'])
  2. dt = pd.Series(np.random.randn(5),index = date)
  3. 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 對象,示例如下:      
  1. print(pd.Timedelta('5 days 8 hours 6 minutes 59 seconds'))
輸出結果:      

5 days 08:06:59

整數

通過傳遞整數值和         unit                參數也可以建立一個 Timedelta 對象。      
  1. print(pd.Timedelta(19,unit='h'))
輸出結果:      

0 days 19:00:00

資料偏移量

資料偏移量, 比如,周(weeks)、天(days)、小時(hours)、分鐘(minutes)、秒(milliseconds)、毫秒、微秒、納秒都可以使用。      
  1. print (pd.Timedelta(days=2,hours=6))
輸出結果:      

2 days 06:00:00

to_timedelta()

您可以使用         pd.to_timedelta()                方法,将具有 timedelta 格式的值 (标量、數組、清單或 Series)轉換為 Timedelta 類型。如果輸入是 Series,則傳回 Series;如果輸入是标量,則傳回值也為标量,其他情況輸出 TimedeltaIndex。示例如下:      
  1. print(pd.to_timedelta(['1 days 06:05:01.00003', '15.5us', 'nan']))
  2. 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 對象,并對其做一些算術運算。      
  1. s = pd.Series(pd.date_range('2020-1-1', periods=5, freq='D'))
  2. #推導式用法
  3. td = pd.Series([ pd.Timedelta(days=i) for i in range(5)])
  4. df = pd.DataFrame(dict(A = s, B = td))
  5. 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      

加法運算

  1. s = pd.Series(pd.date_range('20120-1-1', periods=3, freq='D'))
  2. td = pd.Series([ pd.Timedelta(days=i) for i in range(3) ])
  3. #加法運算
  4. 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      

減法運算

  1. s = pd.Series(pd.date_range('2012-1-1', periods=3, freq='D'))
  2. 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
------------------------------------------------------