時間序列是很重要的。時間序列(time series)數據是一種重要的結構化數據格式。時間序列的意義取決於具體的應用場景,主要有以下幾種:
-
時間戳(timestamp),特定的時刻
-
固定時期(period),如2015年全年
-
時間間隔(interval),由起始和結束時間戳表示。就是說,時期可以是時間間隔的特例。
-
實驗或過程時間,每個時間點都是相對於特定起始時間的一個度量。例如,自從放入烤箱時起,每秒鍾餅干的直徑。
pandas提供了一組標准的時間序列處理工具和數據算法。因此可以高效處理非常大的時間序列,輕松進行切片/切塊、聚合、對定期/不定期的時間序列進行重采樣等。也就是說,大部分都對金融和經濟數據尤為有用,當然也可以用它們來分析服務器日志數據。
1、日期和時間數據類型及工具
Python標准庫中包含用於日期(date)、時間(time)數據的數據類型。而且還有日歷方面的功能。主要會用到datetime、time、calendar模塊。
#-*- coding:utf-8 -*- import numpy as np import pandas as pd import matplotlib.pyplot as plt import datetime as dt from datetime import datetime now = datetime.now() #datetime以毫秒形式儲存時間 print now,now.year,now.month,now.day,now.microsecond,'\n' #print datetime(2015,12,17,20,00,01,555555) #設置一個時間 #datetime.timedelta表示兩個datetime對象之間的時間差 #換句話說,datetime格式可以相相減 delta = datetime(2011,1,7) - datetime(2008,6,24,8,15) print delta #把注意下面是days And seconds print dt.timedelta(926,56700) print delta.days print delta.seconds #下面是錯誤的 #print delta.minutes start = datetime(2011,1,7) #參數分別為days,seconds,microseconds(微秒),milliseconds(毫秒),minutes,hours,weeks,除了微秒小數自動四舍五入之外,其他的都能自動轉換為其他度量 print start + dt.timedelta(1,20,0.5,5,10,10,0)
>>>
2015-12-17 20:24:21.829000 2015 12 17 829000
926 days, 15:45:00
926 days, 15:45:00
926
56700
2011-01-08 10:10:20.005001
[Finished in 0.6s]
datetime中的數據類型有:
-
字符串和datetime的相互轉換
利用str或者strftime方法(傳入一個格式化字符串),datetime對象和pandas中timestamp對象就可以轉換為字符串:
#-*- coding:utf-8 -*- import numpy as np import pandas as pd import matplotlib.pyplot as plt import datetime as dt from datetime import datetime from dateutil.parser import parse stamp = datetime(2011,1,3) print str(stamp),'\n' #看一下下面的字符,很有意思,自己不小心打錯了,運行仍然是正確的 print stamp.strftime('&Y-%m-%d') print stamp.strftime('%Y-%m-%d'),'\n' value = '2011-01-03' print datetime.strptime(value,'%Y-%m-%d') #注意這是datetime函數的函數,不是模塊的函數 datestrs = ['7/6/2011','8/6/2011'] print [datetime.strptime(x,'%m/%d/%Y') for x in datestrs] #上面將字符串轉化為最常用的格式,但是米次都自己寫出來有點麻煩,可以用dateutil這個第三方包中的parser.parse方法 print parse('2011-01-03') #dateutil可以幾乎解析所有能夠理解的日期表示形式(很可惜中文不行) #這個應該是很實用的 print parse('2011/01/03') print parse('Jan 31,1997 10:45 PM') #國際通用格式中,日出現在月的前面,傳入dayfirst = True即可 print parse('6/12/2011',dayfirst = True),'\n' #pandas通常是用於處理成組日期的,不管這些日期是DataFrame的行還是列。 print pd.to_datetime(datestrs),'\n' idx = pd.to_datetime(datestrs + [None]) print idx print idx[2] #這里應該是NaT(Not a Time) print pd.isnull(idx) #parse是一個不完美的工具,比如下面 print parse('42')
>>>
2011-01-03 00:00:00
&Y-01-03
2011-01-03
2011-01-03 00:00:00
[datetime.datetime(2011, 7, 6, 0, 0), datetime.datetime(2011, 8, 6, 0, 0)]
2011-01-03 00:00:00
2011-01-03 00:00:00
1997-01-31 22:45:00
2011-12-06 00:00:00
<class 'pandas.tseries.index.DatetimeIndex'>
[2011-07-06 00:00:00, 2011-08-06 00:00:00]
Length: 2, Freq: None, Timezone: None
<class 'pandas.tseries.index.DatetimeIndex'>
[2011-07-06 00:00:00, ..., NaT]
Length: 3, Freq: None, Timezone: None
0001-255-255 00:00:00
[False False True]
2042-12-17 00:00:00
[Finished in 0.6s]
下面是日期的一些格式:
datetime對象還有一些特定於當前環境(位於不同國家或使用不同語言系統)的格式化選項。估計用的少?
2、時間序列基礎
pandas最基本的時間序列類型就是以時間戳(通常用Python字符串或datatime對象表示)為索引的Series。
#-*- coding:utf-8 -*- import numpy as np import pandas as pd import matplotlib.pyplot as plt import datetime as dt from pandas import Series,DataFrame from datetime import datetime from dateutil.parser import parse dates = [datetime(2011,1,2),datetime(2011,1,5),datetime(2011,1,7), datetime(2011,1,8),datetime(2011,1,10),datetime(2011,1,12)] #print dates ts = Series(np.random.randn(6),index = dates) print ts,'\n' #這些datetime對象實際上是被放在一個DatetimeIndex中的。現在,變量ts就成為了TimeSeries了。 print type(ts) print ts.index,'\n' #沒必要顯示使用TimeSeries的構造函數。當創建一個帶有DatetimeIndex的Series時,pandas就會知道該對象是一個時間序列 print ts + ts[::2] #pandas用NumPy的datetime64數據類型以納秒形式存儲時間戳: print ts.index.dtype #DatetimeIndex中的各個標量值是pandas的Timestamp stamp = ts.index[0] print stamp
#只要有需要,TimeStamp可以隨時自動轉換為datetime對象。此外,還可以存儲頻率信息,且知道如何執行時區轉換以及其他操作
>>>
2011-01-02 -1.267108
2011-01-05 -0.450098
2011-01-07 0.784850
2011-01-08 0.024722
2011-01-10 0.638663
2011-01-12 0.246022
<class 'pandas.core.series.TimeSeries'>
<class 'pandas.tseries.index.DatetimeIndex'>
[2011-01-02 00:00:00, ..., 2011-01-12 00:00:00]
Length: 6, Freq: None, Timezone: None
2011-01-02 -2.534216
2011-01-05 NaN
2011-01-07 1.569701
2011-01-08 NaN
2011-01-10 1.277326
2011-01-12 NaN
datetime64[ns]
2011-01-02 00:00:00
[Finished in 0.7s]
索引、選取、子集構造
TimeSeries是Series的一個子類,所以在索引以及數據選取方面跟Series一樣。
stamp = ts.index[2] print ts[stamp],'\n' #還有更方便的用法,傳入可以被解釋為日期的字符串 print ts['1/10/2011'] print ts['20110110'],'\n' #對於較長的時間序列,只需傳入“年”或“年月”即可輕松選取數據切片 long_ts = Series(np.random.randn(1000), index = pd.date_range('1/1/2000',periods = 1000)) #-*- coding:utf-8 -*- import numpy as np import pandas as pd import matplotlib.pyplot as plt import datetime as dt from pandas import Series,DataFrame from datetime import datetime from dateutil.parser import parse import time print long_ts,'\n' print long_ts['2001'],'\n' print long_ts['2001-05'],'\n' #通過日期進行切片的方式只對規則Series有效: print ts[datetime(2011,1,7):],'\n' #由於大部分時間序列數據都是按照時間先后排序的,因此你可以用不存在於該時間序列中的時間戳對其進行切片(即范圍查詢) #就是說,本來1/6/2011不在index中,卻可以用來當作范圍 print ts['1/6/2011':'1/11/2011'],'\n' #這里可以傳入字符串日期、datetime或者Timestamp print 'This is time and localtime' print "time.time(): %f " % time.time() print time.localtime( time.time() ) print time.asctime( time.localtime(time.time()) ) ltime=time.localtime(int(time.time())) #time.time()不能直接運用strftime進行轉換 print time.strftime("%Y-%m-%d %H:%M:%S", ltime) #time asctime() 函數接受時間元組並返回一個可讀的形式為"Tue Dec 11 18:07:14 2008" print 'over','\n' #還有一個等價方法截取兩個日期之間的TimeSeries. print ts.truncate(after = '1/9/2011'),'\n' #上面這些對DataFrame也有效 dates = pd.date_range('1/1/2000',periods = 100,freq = 'W-WED') #這里的freq是按照星期進行增加 long_df = DataFrame(np.random.randn(100,4),index = dates,columns = ['Colorado','Texas','New York','Ohio']) print long_df.ix['2001-05']
>>>
0.0751316698811
-0.622706612554
-0.622706612554
2000-01-01 -1.646726
2000-01-02 1.531423
2000-01-03 0.251503
2000-01-04 0.938951
2000-01-05 0.647967
2000-01-06 0.696173
2000-01-07 -1.372519
2000-01-08 -1.398277
2000-01-09 -0.679975
2000-01-10 -0.801375
2000-01-11 -0.241165
2000-01-12 -0.332811
2000-01-13 -0.337774
2000-01-14 0.826756
2000-01-15 -0.279239
...
2002-09-12 -0.097634
2002-09-13 2.222456
2002-09-14 0.042517
2002-09-15 0.266974
2002-09-16 0.038329
2002-09-17 -1.524744
2002-09-18 1.476706
2002-09-19 0.108336
2002-09-20 0.016759
2002-09-21 -0.072676
2002-09-22 -0.960545
2002-09-23 0.520699
2002-09-24 -1.188202
2002-09-25 1.669166
2002-09-26 -0.043997
Freq: D, Length: 1000
2001-01-01 -0.168866
2001-01-02 -0.273377
2001-01-03 0.094258
2001-01-04 -0.979666
2001-01-05 0.947706
2001-01-06 0.666709
2001-01-07 0.451145
2001-01-08 -0.301992
2001-01-09 0.272385
2001-01-10 -0.255775
2001-01-11 -0.321916
2001-01-12 1.894119
2001-01-13 0.582272
2001-01-14 -1.102707
2001-01-15 0.019423
...
2001-12-17 -0.243563
2001-12-18 1.757564
2001-12-19 -0.145106
2001-12-20 -0.579629
2001-12-21 -0.431069
2001-12-22 0.480805
2001-12-23 -0.651905
2001-12-24 0.702051
2001-12-25 -0.384549
2001-12-26 -1.077664
2001-12-27 -0.972768
2001-12-28 1.001220
2001-12-29 0.418016
2001-12-30 0.567361
2001-12-31 -0.811610
Freq: D, Length: 365
2001-05-01 -0.071521
2001-05-02 0.402344
2001-05-03 -0.568929
2001-05-04 0.227754
2001-05-05 0.194631
2001-05-06 -0.407669
2001-05-07 -1.407606
2001-05-08 -0.804147
2001-05-09 0.050445
2001-05-10 -0.604275
2001-05-11 0.270760
2001-05-12 0.000804
2001-05-13 -0.348938
2001-05-14 -1.626158
2001-05-15 0.084629
2001-05-16 -0.376655
2001-05-17 1.913789
2001-05-18 2.497594
2001-05-19 0.818446
2001-05-20 0.067115
2001-05-21 -0.993827
2001-05-22 0.940616
2001-05-23 -0.951763
2001-05-24 -0.806228
2001-05-25 0.441872
2001-05-26 0.067010
2001-05-27 -1.903360
2001-05-28 -0.400990
2001-05-29 0.257146
2001-05-30 0.785503
2001-05-31 -1.129024
Freq: D
2011-01-07 0.075132
2011-01-08 -0.985630
2011-01-10 -0.622707
2011-01-12 -1.356095
2011-01-07 0.075132
2011-01-08 -0.985630
2011-01-10 -0.622707
This is time and localtime
time.time(): 1450362054.149000
time.struct_time(tm_year=2015, tm_mon=12, tm_mday=17, tm_hour=22, tm_min=20, tm_sec=54, tm_wday=3, tm_yday=351, tm_isdst=0)
Thu Dec 17 22:20:54 2015
2015-12-17 22:20:54
over
2011-01-02 -0.772858
2011-01-05 -0.908074
2011-01-07 0.075132
2011-01-08 -0.985630
Colorado Texas New York Ohio
2001-05-02 0.303341 0.026978 -0.036389 0.463034
2001-05-09 -1.573227 -0.283074 -0.882382 -1.207936
2001-05-16 1.520804 -0.838297 0.725690 1.240092
2001-05-23 1.297194 -0.516198 -0.022075 -0.876630
2001-05-30 -1.629426 1.022547 -0.131823 -0.621269
[Finished in 0.7s]
-
帶有重復索引的時間序列
#-*- coding:utf-8 -*- import numpy as np import pandas as pd import matplotlib.pyplot as plt import datetime as dt from pandas import Series,DataFrame from datetime import datetime from dateutil.parser import parse import time #注意下面的DatetimeIndex生成方式 dates = pd.DatetimeIndex(['1/1/2000','1/2/2000','1/2/2000','1/2/2000','1/3/2000']) dup_ts = Series(np.arange(5),index = dates) print dup_ts,'\n' #通過檢唯一的測is_unique屬性,我們就可以知道它不是 print dup_ts.index.is_unique,'\n' #此時若索引,得到的可能是標量值,也可能是切片 print dup_ts['1/2/2000'],'\n' print dup_ts['1/3/2000'] #假如你想要對具有非 #唯一時間戳的數據進行聚合一個辦法是使用groupby,並傳入level = 0 grouped = dup_ts.groupby(level = 0) print grouped.mean(),'\n' print grouped.count()
>>>
2000-01-01 0
2000-01-02 1
2000-01-02 2
2000-01-02 3
2000-01-03 4
False
2000-01-02 1
2000-01-02 2
2000-01-02 3
4
2000-01-01 0
2000-01-02 2
2000-01-03 4
2000-01-01 1
2000-01-02 3
2000-01-03 1
[Finished in 1.3s]
3、日期的范圍、頻率以及移動
有時候需要用相對固定的頻率對數據進行分析,比如每月、每天等。幸運的是,pandas有一整套標准時間序列頻率以及用於重采樣、頻率推斷、生成固定頻率日期范圍的工具。
#定義列表 dates = [datetime(2011,1,2),datetime(2011,1,5),datetime(2011,1,7), datetime(2011,1,8),datetime(2011,1,10),datetime(2011,1,12)] #print dates ts = Series(np.random.randn(6),index = dates) #print ts #下面進行重采樣,得到具有固定時間頻率(每天)的時間序列,當讓這樣的話就會產生缺失值 print ts.resample('D')#-*- coding:utf-8 -*- import numpy as np import pandas as pd import matplotlib.pyplot as plt import datetime as dt from pandas import Series,DataFrame from datetime import datetime from dateutil.parser import parse import time #定義列表 dates = [datetime(2011,1,2),datetime(2011,1,5),datetime(2011,1,7), datetime(2011,1,8),datetime(2011,1,10),datetime(2011,1,12)] #print dates ts = Series(np.random.randn(6),index = dates) #print ts #下面進行重采樣,得到具有固定時間頻率(每天)的時間序列,當讓這樣的話就會產生缺失值 print ts.resample('D') #頻率的轉換(或重采樣)主題較大,后面再說
>>>
2011-01-02 -0.956627
2011-01-03 NaN
2011-01-04 NaN
2011-01-05 0.130565
2011-01-06 NaN
2011-01-07 0.090270
2011-01-08 0.753881
2011-01-09 NaN
2011-01-10 -0.733514
2011-01-11 NaN
2011-01-12 -0.200039
Freq: D
[Finished in 1.2s]
- 生成日期范圍
#-*- coding:utf-8 -*- import numpy as np import pandas as pd import matplotlib.pyplot as plt import datetime as dt from pandas import Series,DataFrame from datetime import datetime from dateutil.parser import parse import time #pandas.date_range會生成指定長度的DatetimeIndex index = pd.date_range('4/1/2015','6/1/2015') print index,'\n' #默認情況下,date_range產生按天計算的時間點,當然可以傳入開始或結束日期,還得傳入一個表示一段時間的數字 print pd.date_range('1/1/2016',periods = 31),'\n' #開始和結束定義了日期索引的嚴格邊界,如果你想要生成一個由每月最后一個工作日組成的日期索引,可以傳入‘BM’(business end of month) #這樣就只會包含時間間隔內(或者放好在時間邊界上)符合頻率要求的日期: print pd.date_range('12/18/2015','1/1/2016',freq = 'BM'),'\n' #date_range默認保留起始和結束時間戳信息 print pd.date_range('5/2/2015 12:12:12',periods = 5) #有時,雖然起始和結束帶有時間信息,但是可以用normalize = True把它們吧變為00:00:00 print pd.date_range('5/2/2015 12:12:12',periods = 5,normalize = True)
>>>
<class 'pandas.tseries.index.DatetimeIndex'>
[2015-04-01 00:00:00, ..., 2015-06-01 00:00:00]
Length: 62, Freq: D, Timezone: None
<class 'pandas.tseries.index.DatetimeIndex'>
[2016-01-01 00:00:00, ..., 2016-01-31 00:00:00]
Length: 31, Freq: D, Timezone: None
<class 'pandas.tseries.index.DatetimeIndex'>
[2015-12-31 00:00:00]
Length: 1, Freq: BM, Timezone: None
<class 'pandas.tseries.index.DatetimeIndex'>
[2015-05-02 12:12:12, ..., 2015-05-06 12:12:12]
Length: 5, Freq: D, Timezone: None
<class 'pandas.tseries.index.DatetimeIndex'>
[2015-05-02 00:00:00, ..., 2015-05-06 00:00:00]
Length: 5, Freq: D, Timezone: None
[Finished in 1.1s]
- 頻率和日期偏移量
有些頻率所描述的時間點並不是均勻分隔的。例如'M'和'BM'就取決於每月的天數,對於后者,還要考慮月末是不是周末,將這些成為錨點偏移量(anchored offset)。pandas還允許自定義一些日期邏輯,但是暫且不表。
#-*- coding:utf-8 -*- import numpy as np import pandas as pd import matplotlib.pyplot as plt import datetime as dt from pandas import Series,DataFrame from datetime import datetime from dateutil.parser import parse import time from pandas.tseries.offsets import Hour,Minute #pandas中的頻率是由一個基礎頻率和一個乘數組成的。基礎的頻率由字符串表示,比如‘M’表示月,‘H’表示小時 #對於每個基礎頻率,都有一個被稱為日期偏移量(date offset)的對象與之對應。 hour = Hour() print hour #感覺這個形式比較霸氣 #傳入整數可以自定義偏移量倍數 four_hours = Hour(4) print four_hours #一般而言,並不需要顯示創建偏移量,只需創建時間序列時傳入'H'或者'4h'即可 print pd.date_range('1/1/2016','1/2/2016',freq = '4h'),'\n' #偏移量可以拼接 print Hour(1) + Minute(30) #傳入頻率字符串('2h30min'),這種字符串可以被高效地解析為等效的表達式 print pd.date_range('1/1/2016',periods = 10,freq = '1h30min'),'\n' #有些頻率所描述的時間點並不是均勻分隔的。例如'M'和'BM'就取決於每月的天數,對於后者,還要考慮月末是不是周末,將這些成為錨點偏移量(anchored offset) #WOM(Week Of Month)日期是一個非常常用的頻率,以WOM開頭,能產生諸如“每月第三個星期五”之類的信息 rng = pd.date_range('1/1/2016','9/1/2016',freq = 'WOM-3FRI') print rng
>>>
<1 Hour>
<4 Hours>
<class 'pandas.tseries.index.DatetimeIndex'>
[2016-01-01 00:00:00, ..., 2016-01-02 00:00:00]
Length: 7, Freq: 4H, Timezone: None
<90 Minutes>
<class 'pandas.tseries.index.DatetimeIndex'>
[2016-01-01 00:00:00, ..., 2016-01-01 13:30:00]
Length: 10, Freq: 90T, Timezone: None
<class 'pandas.tseries.index.DatetimeIndex'>
[2016-01-15 00:00:00, ..., 2016-08-19 00:00:00]
Length: 8, Freq: WOM-3FRI, Timezone: None
[Finished in 1.1s]
下面是一些常用的基礎頻率,很多很詳細。
-
移動(超前和滯后)數據
移動(shifting)指的是沿着時間軸將數據前移或后移。Series和DataFrame都有一個shift方法用於執行單純的前移或后移操作,保持索引不變。
#-*- coding:utf-8 -*- import numpy as np import pandas as pd import matplotlib.pyplot as plt import datetime as dt from pandas import Series,DataFrame from datetime import datetime from dateutil.parser import parse import time from pandas.tseries.offsets import Hour,Minute ts = Series(np.random.randn(4),index = pd.date_range('1/1/2016',periods = 4,freq = 'M')) print ts print ts.shift(2) print ts.shift(-2),'\n' #可以看到,shift通常用於計算一個時間序列或多個時間序列(如DataFrame列)中的百分比變化。 print ts / ts.shift(1) - 1 #單純的移位操作不會修改索引,所以部分數據會被丟棄,如果頻率已知,則可以將其傳給shift以實現對時間戳進行位移而不是只對數據移位 print ts.shift(2,freq = 'M') #時間戳移動,而數據不動 #當然也可以自己定義移動的頻率 print ts.shift(3,freq = 'D'),'\n' #時間的移動不是上下移動,而是將時間列的每個值進行移動 print ts.shift(1,freq = '3D') print ts.shift(1,freq = '90T')
>>>
2016-01-31 0.721445
2016-02-29 -0.568200
2016-03-31 -0.945288
2016-04-30 0.198176
Freq: M
2016-01-31 NaN
2016-02-29 NaN
2016-03-31 0.721445
2016-04-30 -0.568200
Freq: M
2016-01-31 -0.945288
2016-02-29 0.198176
2016-03-31 NaN
2016-04-30 NaN
Freq: M
2016-01-31 NaN
2016-02-29 -1.787585
2016-03-31 0.663653
2016-04-30 -1.209646
Freq: M
2016-03-31 0.721445
2016-04-30 -0.568200
2016-05-31 -0.945288
2016-06-30 0.198176
Freq: M
2016-02-03 0.721445
2016-03-03 -0.568200
2016-04-03 -0.945288
2016-05-03 0.198176
2016-02-03 0.721445
2016-03-03 -0.568200
2016-04-03 -0.945288
2016-05-03 0.198176
2016-01-31 01:30:00 0.721445
2016-02-29 01:30:00 -0.568200
2016-03-31 01:30:00 -0.945288
2016-04-30 01:30:00 0.198176
[Finished in 0.7s]
-
通過偏移量對日期進行位移
pandas的日期偏移量還可以用在datetime或Timestemp對象上。
#-*- coding:utf-8 -*- import numpy as np import pandas as pd import matplotlib.pyplot as plt import datetime as dt from pandas import Series,DataFrame from datetime import datetime from dateutil.parser import parse import time from pandas.tseries.offsets import Hour,Minute,Day,MonthEnd now = datetime(2011,11,29) print type(now) print now + Day(3),'\n' #如果加的是錨點偏移量,第一次增量會將原日期向前滾動到符合頻率規則的下一個日期 #如果本來就是錨點,那么下一個就是下一個錨點 print now + MonthEnd(),'\n' print now + MonthEnd(2),'\n' #通過錨點偏移量的rollforward和rollback方法,可顯示地將日期向前或向后“滾動” offset = MonthEnd() print offset.rollforward(now),'\n' print offset.rollback(now),'\n' #日期偏移量還有一個巧妙的用法,即結合groupby使用這兩個“滾動”方法 ts = Series(np.random.randn(20),index = pd.date_range('1/15/2000',periods = 20,freq = '4d')) print ts,'\n' #注意下面的方式,很隱晦 print ts.groupby(offset.rollforward).mean(),'\n' #當然,更簡單快速的方式是使用resample print ts.resample('M',how = 'mean')
>>>
<type 'datetime.datetime'>
2011-12-02 00:00:00
2011-11-30 00:00:00
2011-12-31 00:00:00
2011-11-30 00:00:00
2011-10-31 00:00:00
2000-01-15 -1.234284
2000-01-19 -1.078641
2000-01-23 -0.727257
2000-01-27 -0.943798
2000-01-31 0.050586
2000-02-04 0.019833
2000-02-08 -1.407244
2000-02-12 -0.446414
2000-02-16 -0.521847
2000-02-20 0.066200
2000-02-24 1.604580
2000-02-28 -0.714762
2000-03-03 1.743459
2000-03-07 1.675388
2000-03-11 0.104701
2000-03-15 0.124533
2000-03-19 -1.113306
2000-03-23 -1.442906
2000-03-27 -0.489818
2000-03-31 0.344161
Freq: 4D
2000-01-31 -0.786679
2000-02-29 -0.199950
2000-03-31 0.118276
2000-01-31 -0.786679
2000-02-29 -0.199950
2000-03-31 0.118276
Freq: M
[Finished in 0.7s]
4、時區處理
時間序列最讓人不爽的就是對時區的處理。很多人已經用協調世界時(UTC,格林尼治時間接替者,目前是國際標准)來處理時間序列。時區就是以UTC偏移量的形式表示的。
Python中,時區信息來自第三方庫pytz,它可以使Python可以使用Olson數據庫。pandas包裝了pytz功能。因此不用記憶API,只要記得時區名稱即可。時區名可以在文檔中找到。
#-*- coding:utf-8 -*- import numpy as np import pandas as pd import matplotlib.pyplot as plt import datetime as dt from pandas import Series,DataFrame from datetime import datetime from dateutil.parser import parse import time from pandas.tseries.offsets import Hour,Minute,Day,MonthEnd import pytz print pytz.common_timezones[-5:] #要從pytz中獲取時區對象,使用pytz.timezone即可 tz = pytz.timezone('US/Eastern') print tz #這里的輸出已經和課本上不一樣,估計是進行了簡化,使得更方便了
>>>
['US/Eastern', 'US/Hawaii', 'US/Mountain', 'US/Pacific', 'UTC']
US/Eastern
[Finished in 0.7s]
-
本地化和轉換
默認情況下,pandas中的序列是單純的(naive[too young too simple!navie!])時區。
#-*- coding:utf-8 -*- import numpy as np import pandas as pd import matplotlib.pyplot as plt import datetime as dt from pandas import Series,DataFrame from datetime import datetime from dateutil.parser import parse import time from pandas.tseries.offsets import Hour,Minute,Day,MonthEnd import pytz rng = pd.date_range('3/9/2012 9:30',periods = 6,freq = 'D') ts = Series(np.random.randn(len(rng)),index = rng) print ts,'\n' print ts.index.tz,'\n' #默認的時區字段為None #在生成日期范圍的時候還可以加上一個時區集 print pd.date_range('3/9/2012',periods = 10,freq = 'D',tz = 'UTC'),'\n' #從單純到本地化的轉換是通過tz_localize方法處理的: ts_utc = ts.tz_localize('US/Pacific') #轉換為美國太平洋時間 print ts_utc,'\n' print ts_utc.index,'\n' #一旦被轉換為某個特定時期,就可以用tz_convert將其轉換到其他時區了 print ts_utc.tz_convert('US/Eastern'),'\n' #tz_localize和tz_convert是DatetimeIndex的實例方法,可以把一個DatetimeIndex轉化為特定時區 print ts.index.tz_localize('Asia/Shanghai')
>>>
2012-03-09 09:30:00 0.079530
2012-03-10 09:30:00 -0.434450
2012-03-11 09:30:00 0.360739
2012-03-12 09:30:00 0.678065
2012-03-13 09:30:00 -0.705374
2012-03-14 09:30:00 0.684572
Freq: D
None
<class 'pandas.tseries.index.DatetimeIndex'>
[2012-03-09 00:00:00, ..., 2012-03-18 00:00:00]
Length: 10, Freq: D, Timezone: UTC
2012-03-09 09:30:00-08:00 0.079530
2012-03-10 09:30:00-08:00 -0.434450
2012-03-11 09:30:00-07:00 0.360739
2012-03-12 09:30:00-07:00 0.678065
2012-03-13 09:30:00-07:00 -0.705374
2012-03-14 09:30:00-07:00 0.684572
Freq: D
<class 'pandas.tseries.index.DatetimeIndex'>
[2012-03-09 09:30:00, ..., 2012-03-14 09:30:00]
Length: 6, Freq: D, Timezone: US/Pacific
2012-03-09 12:30:00-05:00 0.079530
2012-03-10 12:30:00-05:00 -0.434450
2012-03-11 12:30:00-04:00 0.360739
2012-03-12 12:30:00-04:00 0.678065
2012-03-13 12:30:00-04:00 -0.705374
2012-03-14 12:30:00-04:00 0.684572
Freq: D
<class 'pandas.tseries.index.DatetimeIndex'>
[2012-03-09 09:30:00, ..., 2012-03-14 09:30:00]
Length: 6, Freq: D, Timezone: Asia/Shanghai
[Finished in 0.6s]
-
操作時區意識型(time zone-aware)Timestamp對象
跟時間序列和日期序列差不多,Timestamp對象也能被從單純型(navie)本地化為time zone-aware,並從一個時區轉換為另一個時區。
#-*- coding:utf-8 -*- import numpy as np import pandas as pd import matplotlib.pyplot as plt import datetime as dt from pandas import Series,DataFrame from datetime import datetime from dateutil.parser import parse import time from pandas.tseries.offsets import Hour,Minute,Day,MonthEnd import pytz stamp = pd.Timestamp('2011-03-12 04:00') print type(stamp),'\n' stamp_utc = stamp.tz_localize('UTC') print stamp_utc,'\n' print stamp_utc.tz_convert('US/Eastern'),'\n' stamp_moscow = pd.Timestamp('2011-03-12 04:00',tz = 'Europe/Moscow') print stamp_moscow #時區意識型Timestamp對象在內部保存了一個UTC時間戳值(自1970年1月1日起的納秒數),這個UTC值在時區轉換過程中是不會變化的 print stamp_utc.value print stamp_utc.tz_convert('US/Eastern').value,'\n' #當使用pandas的DataOffset對象執行運算時,會自動關注“夏時令”…………
>>>
<class 'pandas.lib.Timestamp'>
2011-03-12 04:00:00+00:00
2011-03-11 23:00:00-05:00
2011-03-12 04:00:00+03:00
1299902400000000000
1299902400000000000
[Finished in 0.7s]
-
不同時區之間的運算
如果時間時間時區不同,那么結果就會是UTC時間,由於時間戳其實是以UTC儲存的,索引計算很方便。
#-*- coding:utf-8 -*- import numpy as np import pandas as pd import matplotlib.pyplot as plt import datetime as dt from pandas import Series,DataFrame from datetime import datetime from dateutil.parser import parse import time from pandas.tseries.offsets import Hour,Minute,Day,MonthEnd import pytz rng = pd.date_range('3/7/2012',periods = 10,freq = 'B') ts = Series(np.random.randn(len(rng)),index = rng) print ts ts1 = ts[:7].tz_localize('Europe/London') #注意naive是不能直接轉換為時區的,必須先轉換為localize再進行轉換 ts2 = ts1[2:].tz_convert('Europe/Moscow') result = ts1 + ts2 #轉換為UTC print result.index
>>>
2012-03-07 -0.591417
2012-03-08 1.009651
2012-03-09 -1.922004
2012-03-12 0.246206
2012-03-13 0.033430
2012-03-14 0.614911
2012-03-15 1.944014
2012-03-16 -2.349846
2012-03-19 0.425925
2012-03-20 1.941166
Freq: B
<class 'pandas.tseries.index.DatetimeIndex'>
[2012-03-07 00:00:00, ..., 2012-03-15 00:00:00]
Length: 7, Freq: B, Timezone: UTC
[Finished in 0.7s]