《利用Python 进行数据分析》第十章:时间序列
??? ???對《利用Python 進行數(shù)據(jù)分析》(Wes Mckinney著)一書中的第十章中時間序列進行代碼實驗。原書中采用的是Python2.7,而我采用的Python3.7在Pycharm調(diào)試的,因此對書中源代碼進行了一定的修改,每步結(jié)果與原文校驗對照一致(除了隨機函數(shù)外;輸出結(jié)果在注釋中,簡單的輸出就沒寫結(jié)果),全手工敲寫,供參考。
??? ???Pdf文檔和數(shù)據(jù)集參見:《利用Python 進行數(shù)據(jù)分析》第二章:引言中的分析代碼(含pdf和數(shù)據(jù)集下載鏈接)
 
???時間序列:
- 1、日期和時間數(shù)據(jù)類型及工具
- 1.1 日期類型初識
- 1.2 字符串和datetime相互轉(zhuǎn)換
 
- 2、時間序列基礎(chǔ)
- 2.1 索引、選取、子集構(gòu)造
- 2.2 帶重復(fù)索引的時間序列
 
- 3、日期的范圍、頻率以及移動
- 3.1 生成日期范圍
- 3.2 頻率和日期偏移量
- 3.3 移動(超前和滯后)數(shù)據(jù)
 
- 4、時區(qū)處理
- 4.1 本地化和轉(zhuǎn)換
- 4.2 操作時區(qū)意識型Timestamp對象
- 4.3 不同時區(qū)之間的運算
 
- 5、時期及算術(shù)運算
- 5.1 時期的構(gòu)建
- 5.2 時期的頻率轉(zhuǎn)換
- 5.3 按季度計算的時期頻率
- 5.4 將Timestamp轉(zhuǎn)化為Period(及其反向過程)
- 5.5 通過數(shù)組創(chuàng)建PeriodIndex
 
- 6、重采樣及頻率轉(zhuǎn)換
- 6.1 重采樣
- 6.2 降采樣
- 6.3 升采樣和差值
- 6.4 通過時期進行重采樣
 
- 7、時間序列繪圖
- 8、移動窗口函數(shù)
- 8.1 移動窗口
- 8.2 指數(shù)加權(quán)函數(shù)
- 8.3 二次移動窗口函數(shù)
- 8.4 用戶定義的移動窗口函數(shù)
 
??? ???因為代碼過長,放在一個代碼段中顯得冗長,因此進行了拆分,如下的庫引入每個代碼段中均可能有必要。 # -*- coding:utf-8 -*- from datetime import datetime, timedelta import pandas as pd import numpy as np from pandas import DataFrame, Series
1、日期和時間數(shù)據(jù)類型及工具
時間序列數(shù)據(jù)的意義取決于具體的應(yīng)用場景
 時間戳(timestamp):特定的時刻
 固定時期(period):如2007年1月或2010年全年
 時間間隔(interval):由起始和結(jié)束時間戳表示,時期(period)可以被看作間隔的特例
1.1 日期類型初識
# 主要用到datetime、time以及calendar模塊 now = datetime.now() print(now) # 2020-09-28 14:05:42.871960 print(now.year, now.month, now.day) # 2020 9 28# datetime以毫秒形式儲存日期和時間 delta = datetime(2011,1,7) - datetime(2008, 6, 24, 8, 15) print(delta) # 926 days, 15:45:00# datetime.timedelta表示兩個datetime對象之間的時間差 timedelta(926, 56700) print(delta.days) # 926 print(delta.seconds) # 56700# 可以給datetime對象加上(減去)一個或多個timedelta,會產(chǎn)生一個新對象 start = datetime(2011,1,7) ret = start + timedelta(12) print(ret) # 2011-01-19 00:00:00ret = start - 2 * timedelta(12) print(ret) # 2010-12-14 00:00:001.2 字符串和datetime相互轉(zhuǎn)換
# 利用str或strftime方法(傳入格式化字符串),datetime對象和pandas的Timestamp對象可以被格式化為字符串 stamp = datetime(2011, 1, 3) print(str(stamp)) # 2011-01-03 00:00:00 print(stamp.strftime('%Y-%m-%d')) # 2011-01-03# date.time.strptime也可以用這些格式化編碼將字符串轉(zhuǎn)化為日期 value = '2011-01-09' print(datetime.strptime(value,'%Y-%m-%d')) # 2011-01-09 00:00:00datestrs=['7/6/2011', '8/6/2011'] print([datetime.strptime(x, '%m/%d/%Y') for x in datestrs]) '''[datetime.datetime(2011, 7, 6, 0, 0), datetime.datetime(2011, 8, 6, 0, 0)]'''# datetime.strptime是通過已知格式進行日期解析,但每次編寫都需要定義格式比較麻煩 # 所以我們可以使用dateutil 這個第三方庫的parser.parse方法 from dateutil.parser import parse print(parse('2011-01-03')) # 2011-01-03 00:00:00# dateutil 可以解析幾乎所有人類能理解的日期表現(xiàn)形式 print(parse('Jan 31, 1997 10:45 PM')) # 1997-01-31 22:45:00# 國際通用格式中,日常常出現(xiàn)在月的前面,傳入dayfirst=True即可解決這個問題 print(parse('6/12/2011', dayfirst=True)) # 2011-12-06 00:00:00# to_datetime方法可以解析多種不同日期的表示形式 print(datestrs) # ['7/6/2011', '8/6/2011'] print(pd.to_datetime(datestrs)) ''' DatetimeIndex(['2011-07-06', '2011-08-06'], dtype='datetime64[ns]', freq=None) '''# to_datetime也可以處理缺失值(None、空字符串等) idx = pd.to_datetime(datestrs + [None]) print(idx) ''' atetimeIndex(['2011-07-06', '2011-08-06', 'NaT'], dtype='datetime64[ns]', freq=None) ''' print(idx[2]) # NaT , NaT(Not a Time)是pandas中時間戳數(shù)據(jù)的NA值 print(pd.isnull(idx)) # [False False True]2、時間序列基礎(chǔ)
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)] ts = Series(np.random.randn(6), index = dates) print(ts) ''' 2011-01-02 -0.804594 2011-01-05 0.444492 2011-01-07 -1.336713 2011-01-08 1.380549 2011-01-10 -1.090957 2011-01-12 0.162639 dtype: float64 ''' # datetime對象是被放在一個DatetimeIndex中,現(xiàn)在ts就成為一個TimeSeries了 print(type(ts)) ''' <class 'pandas.core.series.Series'> DatetimeIndex(['2011-01-02', '2011-01-05', '2011-01-07', '2011-01-08','2011-01-10', '2011-01-12'],dtype='datetime64[ns]', freq=None) ''' print(ts.index) ''' 2011-01-02 -1.609187 2011-01-05 NaN 2011-01-07 -2.673426 2011-01-08 NaN 2011-01-10 -2.181915 2011-01-12 NaN dtype: float64 ''' # 跟其他Series一樣,不同索引的時間序列之間的算術(shù)運算會按自動日期對齊 print(ts + ts[::2]) print(ts.index.dtype) # datetime64[ns] # DatetimeIndex中的各個標(biāo)量值是pandas的Timestamp對象 stamp = ts.index[0] print(stamp) # 2011-01-02 00:00:002.1 索引、選取、子集構(gòu)造
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)] ts = Series(np.random.randn(6), index = dates) print(ts) ''' 2011-01-02 0.348253 2011-01-05 -0.068450 2011-01-07 -1.073036 2011-01-08 1.059299 2011-01-10 0.497196 2011-01-12 0.713568 dtype: float64 ''' # TimeSeries是Series的一個類,所以在索引以及數(shù)據(jù)選取方面他們的行為是一樣的 stamp=ts.index[2] print(ts[stamp]) # -1.073035582647907# 可以傳入一個可以解釋為日期的字符串 print(ts['1/10/2011']) # 0.4971955016152246 print(ts['20110110']) # 0.4971955016152246# 對于較長的時間序列,只需要傳入“年”或“年月”即可輕松選取數(shù)據(jù)的切片 longer_ts = Series(np.random.randn(1000),index=pd.date_range('1/1/2000', periods=1000)) print(longer_ts) ''' 2000-01-01 0.650802 2000-01-02 2.018351 2000-01-03 0.676741 2000-01-04 0.779642 2000-01-05 0.851207... 2002-09-22 -1.794156 2002-09-23 0.515699 2002-09-24 0.257113 2002-09-25 -1.512441 2002-09-26 -0.680429 Freq: D, Length: 1000, dtype: float64 ''' print(longer_ts['2001']) ''' 2001-01-01 1.357131 2001-01-02 -0.840957 2001-01-03 -1.000980 2001-01-04 -1.183331 2001-01-05 0.453523... 2001-12-27 0.919488 2001-12-28 -1.240291 2001-12-29 0.061306 2001-12-30 -1.226537 2001-12-31 -0.744249 Freq: D, Length: 365, dtype: float64 ''' print(longer_ts['2001-05']) ''' 2001-05-01 0.377640 2001-05-02 0.389160 2001-05-03 -0.657888 2001-05-04 1.353799 2001-05-05 0.834874... 2001-05-26 -1.333958 2001-05-27 1.405335 2001-05-28 -0.217538 2001-05-29 -0.029023 2001-05-30 -0.889619 2001-05-31 -0.986640 Freq: D, dtype: float64 ''' # 通過日期進行切片的方式只對規(guī)則Series有效 print(ts[datetime(2011,1,7):]) ''' 2011-01-07 -1.073036 2011-01-08 1.059299 2011-01-10 0.497196 2011-01-12 0.713568 dtype: float64 '''# 由于大部分時間都是按照時間先后排序,因此可以用不存在于該時間序列中的時間戳對其進行切片 print(ts) ''' 2011-01-02 0.348253 2011-01-05 -0.068450 2011-01-07 -1.073036 2011-01-08 1.059299 2011-01-10 0.497196 2011-01-12 0.713568 dtype: float64 ''' print(ts['1/6/2011':'1/11/2011']) # 取范圍內(nèi)的日期 ''' 2011-01-07 -1.073036 2011-01-08 1.059299 2011-01-10 0.497196 dtype: float64 '''# 截取兩個日期之間的TimeSeries print(ts.truncate(after='1/9/2011')) ''' 2011-01-02 0.348253 2011-01-05 -0.068450 2011-01-07 -1.073036 2011-01-08 1.059299 dtype: float64 ''' # 也可以對DataFrame操作,對DataFrame的行進行索引 dates = pd.date_range('1/1/2000',periods = 100, freq='W-WED') long_df = DataFrame(np.random.randn(100,4),index=dates,columns=['Colorado','Texas', 'NewYork', 'Ohio']) print(long_df.loc['5-2001']) '''Colorado Texas NewYork Ohio 2001-05-02 1.467936 1.063116 1.344797 -0.580989 2001-05-09 0.637778 -0.905873 0.855643 -1.161038 2001-05-16 0.305796 -1.233853 -0.628636 -0.052159 2001-05-23 -1.098029 0.052049 0.531545 1.161001 2001-05-30 -0.981410 -2.068461 2.049203 -0.786793 '''2.2 帶重復(fù)索引的時間序列
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) ''' 2000-01-01 0 2000-01-02 1 2000-01-02 2 2000-01-02 3 2000-01-03 4 dtype: int32 '''# 通過檢查索引的is_unique屬性,可以知道它是不是唯一的 print(dup_ts.index.is_unique) # False# 通過對這個時間序列進行索引,要么產(chǎn)生標(biāo)量值,要么產(chǎn)生切片,取決于所選的時間點是否重復(fù) print(dup_ts['1/3/2000']) # 4 print(dup_ts['1/2/2000']) ''' 2000-01-02 1 2000-01-02 2 2000-01-02 3 dtype: int32 '''# 如果想要對具有非唯一的數(shù)據(jù)進行聚合,可以使用groupby,并傳入level=0(索引的唯一一層!) grouped = dup_ts.groupby(level=0) print(grouped.mean()) ''' 2000-01-01 0 2000-01-02 2 2000-01-03 4 dtype: int32 ''' print(grouped.count()) ''' 2000-01-01 1 2000-01-02 3 2000-01-03 1 dtype: int64 '''3、日期的范圍、頻率以及移動
# pandas有一套標(biāo)準(zhǔn)時間序列頻率以及重采樣、頻率推斷、生成固定頻率日期的范圍 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)] ts = Series(np.random.randn(6), index = dates) print(ts)ts_resmp = ts.resample('D') print(ts_resmp) '''DatetimeIndexResampler [freq=<Day>, axis=0, closed=left, label=left, convention=start, base=0]'''ts_resmp_sum = ts.resample('3D').sum() print(ts_resmp_sum) # 按3天重新采樣并求和 ''' 2011-01-02 1.041772 2011-01-05 -0.854215 2011-01-08 -2.727751 2011-01-11 0.809483 Freq: 3D, dtype: float64 ''' # 關(guān)于重采樣是比較大的主題,在第6小節(jié)專門討論3.1 生成日期范圍
# 用pandas_range可用于生成指定長度的DatetimeIndex index = pd.date_range('4/1/2012', '6/1/2012') print(index[:5]) ''' DatetimeIndex(['2012-04-01', '2012-04-02', '2012-04-03', '2012-04-04','2012-04-05'],dtype='datetime64[ns]', freq='D') '''# 默認情況下,date_range會按天計算的時間點 # 如果傳入起始或起始結(jié)束日期,還需要傳入一個表示一段時間的數(shù)字 print(pd.date_range(start='4/1/2012', periods=20)) ''' DatetimeIndex(['2012-04-01', '2012-04-02', '2012-04-03', '2012-04-04','2012-04-05', '2012-04-06', '2012-04-07', '2012-04-08','2012-04-09', '2012-04-10', '2012-04-11', '2012-04-12','2012-04-13', '2012-04-14', '2012-04-15', '2012-04-16','2012-04-17', '2012-04-18', '2012-04-19', '2012-04-20'],dtype='datetime64[ns]', freq='D') ''' print(pd.date_range(end='6/1/2012',periods =20)) ''' DatetimeIndex(['2012-05-13', '2012-05-14', '2012-05-15', '2012-05-16','2012-05-17', '2012-05-18', '2012-05-19', '2012-05-20','2012-05-21', '2012-05-22', '2012-05-23', '2012-05-24','2012-05-25', '2012-05-26', '2012-05-27', '2012-05-28','2012-05-29', '2012-05-30', '2012-05-31', '2012-06-01'],dtype='datetime64[ns]', freq='D') '''# 生成一個由每月最后一個工作日組成的日期索引,傳入“BM"頻率(business end of month) print(pd.date_range('1/1/2000','12/1/2000',freq='BM')) ''' DatetimeIndex(['2000-01-31', '2000-02-29', '2000-03-31', '2000-04-28','2000-05-31', '2000-06-30', '2000-07-31', '2000-08-31','2000-09-29', '2000-10-31', '2000-11-30'],dtype='datetime64[ns]', freq='BM') '''# date_range默認保留起始和結(jié)束時間戳的時間信息(如果有的話) print(pd.date_range('5/2/2012 12:56:31', periods=5)) ''' DatetimeIndex(['2012-05-02 12:56:31', '2012-05-03 12:56:31','2012-05-04 12:56:31', '2012-05-05 12:56:31','2012-05-06 12:56:31'],dtype='datetime64[ns]', freq='D') '''# normalize選項可以實現(xiàn)產(chǎn)生一組被規(guī)范化到午夜的時間戳 print(pd.date_range('5/2/2012 12:56:31', periods=5, normalize=True)) ''' DatetimeIndex(['2012-05-02', '2012-05-03', '2012-05-04', '2012-05-05','2012-05-06'],dtype='datetime64[ns]', freq='D') '''3.2 頻率和日期偏移量
# pandas中的頻率是由一個基礎(chǔ)頻率和一個乘數(shù)組成的 # 基礎(chǔ)頻率通常以一個字符串別名表示,比如“M"表示每月,”H“表示每小時 from pandas.tseries.offsets import Hour, Minute hour = Hour() print(hour) # <Hour># 傳入一個整數(shù)即可定義便宜量的倍數(shù) four_hours = Hour(4) print(four_hours) # <4 * Hours># 在基礎(chǔ)頻率前面放上一個整數(shù)即可創(chuàng)建倍數(shù) print(pd.date_range('1/1/2000', '1/1/2000 23:59', freq='4h')) ''' DatetimeIndex(['2000-01-01 00:00:00', '2000-01-01 04:00:00','2000-01-01 08:00:00', '2000-01-01 12:00:00','2000-01-01 16:00:00', '2000-01-01 20:00:00'],dtype='datetime64[ns]', freq='4H') '''# 大部分偏移量對象都可以通過加法進行連接 print(Hour(2) + Minute(30)) # <150 * Minutes># 同時也可以傳入頻率字符串(如“2h30min”),這種字符串可以被高效地解析為等效的表達式 print(pd.date_range('1/1/2000',periods = 10, freq='1h30min')) ''' DatetimeIndex(['2000-01-01 00:00:00', '2000-01-01 01:30:00','2000-01-01 03:00:00', '2000-01-01 04:30:00','2000-01-01 06:00:00', '2000-01-01 07:30:00','2000-01-01 09:00:00', '2000-01-01 10:30:00','2000-01-01 12:00:00', '2000-01-01 13:30:00'],dtype='datetime64[ns]', freq='90T') '''# WOM日期,week of month是一種非常實用的頻率類,如獲得諸如“每月第3個星期五”之類的日期 rng = pd.date_range('1/1/2012','9/1/2012', freq="WOM-3FRI") print(rng) ''' DatetimeIndex(['2012-01-20', '2012-02-17', '2012-03-16', '2012-04-20','2012-05-18', '2012-06-15', '2012-07-20', '2012-08-17'],dtype='datetime64[ns]', freq='WOM-3FRI') '''3.3 移動(超前和滯后)數(shù)據(jù)
# 移動是指沿著時間軸將數(shù)據(jù)前移或后移,Series和DataFrame都有一個shift方法用于執(zhí)行單純的前移或后移操作 ts = Series(np.random.randn(4),index = pd.date_range('1/1/2000', periods=4, freq='M')) print(ts) ''' 2000-01-31 -0.309081 2000-02-29 0.754501 2000-03-31 -0.727029 2000-04-30 -0.628417 Freq: M, dtype: float64 '''# Shift通常用于計算一個時間序列或多個時間序列中百分比變化:ts/st.shift(1) - 1 # 如果頻率已知,則可以將其傳給shift以便實現(xiàn)對時間戳進行位移而不是對數(shù)據(jù)進行簡單位移 print(ts.shift(2, freq='M')) ''' 2000-03-31 -0.309081 2000-04-30 0.754501 2000-05-31 -0.727029 2000-06-30 -0.628417 Freq: M, dtype: float64 '''# 還可以使用其他頻率,可以靈活對數(shù)據(jù)進行超前或滯后處理 print(ts.shift(3,freq='D')) ''' 2000-02-03 -0.309081 2000-03-03 0.754501 2000-04-03 -0.727029 2000-05-03 -0.628417 dtype: float64 '''print(ts.shift(1,freq='3D')) ''' 2000-02-03 -0.309081 2000-03-03 0.754501 2000-04-03 -0.727029 2000-05-03 -0.628417 dtype: float64 '''print(ts.shift(1,freq='90T')) # 1h30mins ''' 2000-01-31 01:30:00 -0.309081 2000-02-29 01:30:00 0.754501 2000-03-31 01:30:00 -0.727029 2000-04-30 01:30:00 -0.628417 Freq: M, dtype: float64 ''' print('----') # 通過偏移量對日期進行位移 from pandas.tseries.offsets import Day, MonthEnd now = datetime(2011, 11, 17) print(now + 3*Day()) # 2011-11-20 00:00:00# 如果加的是錨點偏移量(MonthEnd例如),第一次增量會將原日期向前滾動到符合頻率規(guī)則的下一日期 print(now+MonthEnd()) # 2011-11-30 00:00:00 print(now+MonthEnd(2)) # 2011-12-31 00:00:00# 通過錨點偏移量的rollforward和rollback方法,可顯式地將日期向前或向后”滾動“ offset = MonthEnd() print(offset.rollforward(now)) # 2011-11-30 00:00:00 print(offset.rollback(now)) # 2011-10-31 00:00:00# 日期偏移量還有一個巧妙的用法,即結(jié)合groupby使用這兩個“滾動”方法 ts = Series(np.random.randn(20),index = pd.date_range('1/15/2000',periods=20,freq='4d')) print(ts.groupby(offset.rollforward).mean()) ''' 2000-01-31 0.168758 2000-02-29 -0.167549 2000-03-31 0.379540 dtype: float64 '''# 當(dāng)然實現(xiàn)上述功能最快的方法是使用resample函數(shù) print(ts.resample("M").mean()) ''' 2000-01-31 0.168758 2000-02-29 -0.167549 2000-03-31 0.379540 Freq: M, dtype: float64 '''4、時區(qū)處理
# 時區(qū)信息來自第三方庫Pytz import pytz print(pytz.common_timezones[-5:]) # ['US/Eastern', 'US/Hawaii', 'US/Mountain', 'US/Pacific', 'UTC']# 從pytz中獲取時區(qū)對象,使用pytz.timezone即可 tz=pytz.timezone('US/Eastern') print(tz) # US/Eastern4.1 本地化和轉(zhuǎn)換
# 默認情況,pandas的時間序列是單純的(naive)時區(qū) rng = pd.date_range('3/9/2012 9:30', periods=6, freq='D') ts=Series(np.random.randn(len(rng)), index = rng) print(ts.index.tz) # None# 在生成日期范圍的時候還可以加上一個時區(qū)集 print(pd.date_range('2/9/2012 9:30', periods=10, freq='D', tz='UTC')) ''' DatetimeIndex(['2012-02-09 09:30:00+00:00', '2012-02-10 09:30:00+00:00','2012-02-11 09:30:00+00:00', '2012-02-12 09:30:00+00:00','2012-02-13 09:30:00+00:00', '2012-02-14 09:30:00+00:00','2012-02-15 09:30:00+00:00', '2012-02-16 09:30:00+00:00','2012-02-17 09:30:00+00:00', '2012-02-18 09:30:00+00:00'],dtype='datetime64[ns, UTC]', freq='D') '''# 從單純到本地化的轉(zhuǎn)換時通過tz_local方法處理的 ts_utc=ts.tz_localize('UTC') print(ts_utc) ''' 2012-03-09 09:30:00+00:00 -0.366451 2012-03-10 09:30:00+00:00 -1.254051 2012-03-11 09:30:00+00:00 0.733324 2012-03-12 09:30:00+00:00 -0.267528 2012-03-13 09:30:00+00:00 -0.938285 2012-03-14 09:30:00+00:00 -1.037081 Freq: D, dtype: float64 '''print(ts_utc.index) ''' DatetimeIndex(['2012-03-09 09:30:00+00:00', '2012-03-10 09:30:00+00:00','2012-03-11 09:30:00+00:00', '2012-03-12 09:30:00+00:00','2012-03-13 09:30:00+00:00', '2012-03-14 09:30:00+00:00'],dtype='datetime64[ns, UTC]', freq='D') '''# 一旦時間序列被本地化到某個特定時區(qū),就可以用tz_convert將其轉(zhuǎn)換到別的時區(qū) print(ts_utc.tz_convert('US/Eastern')) ''' 2012-03-09 04:30:00-05:00 -0.366451 2012-03-10 04:30:00-05:00 -1.254051 2012-03-11 05:30:00-04:00 0.733324 2012-03-12 05:30:00-04:00 -0.267528 2012-03-13 05:30:00-04:00 -0.938285 2012-03-14 05:30:00-04:00 -1.037081 Freq: D, dtype: float64 '''# 對于上面的時間序列(跨越了美國東部時區(qū)的夏令時期轉(zhuǎn)變期)可以先將其本地化到EST,再轉(zhuǎn)為UTC或柏林時間 ts_eastern = ts.tz_localize('US/Eastern') print(ts_eastern.tz_convert('UTC')) ''' 2012-03-09 14:30:00+00:00 -0.366451 2012-03-10 14:30:00+00:00 -1.254051 2012-03-11 13:30:00+00:00 0.733324 2012-03-12 13:30:00+00:00 -0.267528 2012-03-13 13:30:00+00:00 -0.938285 2012-03-14 13:30:00+00:00 -1.037081 dtype: float64 ''' print(ts_eastern.tz_convert('Europe/Berlin')) ''' 2012-03-09 15:30:00+01:00 -0.366451 2012-03-10 15:30:00+01:00 -1.254051 2012-03-11 14:30:00+01:00 0.733324 2012-03-12 14:30:00+01:00 -0.267528 2012-03-13 14:30:00+01:00 -0.938285 2012-03-14 14:30:00+01:00 -1.037081 dtype: float64 '''# tz_localize和tz_convert也是DatetimeIndex的實例方法 print(ts.index.tz_localize('Asia/Shanghai')) ''' DatetimeIndex(['2012-03-09 09:30:00+08:00', '2012-03-10 09:30:00+08:00','2012-03-11 09:30:00+08:00', '2012-03-12 09:30:00+08:00','2012-03-13 09:30:00+08:00', '2012-03-14 09:30:00+08:00'],dtype='datetime64[ns, Asia/Shanghai]', freq=None) '''4.2 操作時區(qū)意識型Timestamp對象
# 與時間序列和日期范圍差不多,Timestamp對象也能從單純型(naive)本地化為時區(qū)意識型,并從一個時區(qū)轉(zhuǎn)換到另一時區(qū) stamp = pd.Timestamp('2011-03-12 04:00') stamp_utc = stamp.tz_localize('utc') print(stamp_utc.tz_convert('US/Eastern')) # 2011-03-11 23:00:00-05:00# 在創(chuàng)建Timestamp時,還可以傳入一個時區(qū)信息 stamp_moscow=pd.Timestamp('2011-03-12 04:00', tz='Europe/Moscow') print(stamp_moscow) # 2011-03-12 04:00:00+03:00# 時區(qū)意識型Timestamp對象在內(nèi)部保存了一個UTC時間戳值,這個值在時區(qū)轉(zhuǎn)換過程中是不會發(fā)生變化的 print(stamp_utc.value) # 1299902400000000000 print(stamp_utc.tz_convert('US/Eastern').value) # 1299902400000000000# 使用pandas的DateOffset對象執(zhí)行時間算術(shù)運算時,運算過程會自動關(guān)注是否存在夏令時轉(zhuǎn)變期 # 夏令時轉(zhuǎn)變前30分鐘 from pandas.tseries.offsets import Hour stamp = pd.Timestamp('2012-03-12 01:30', tz='US/Eastern') print(stamp) # 2012-03-12 01:30:00-04:00 print(stamp+Hour()) # 2012-03-12 02:30:00-04:00# 夏令時轉(zhuǎn)變前90分鐘 stamp=pd.Timestamp('2012-11-04 00:30', tz='US/Eastern') print(stamp) # 2012-11-04 00:30:00-04:00 print(stamp + 2*Hour()) # 2012-11-04 01:30:00-05:004.3 不同時區(qū)之間的運算
# 如果兩個時間序列的時區(qū)不同,將它們合并到一起時,最終結(jié)果就會是UTC # 由于時間戳其實是以UTC儲存的,所以這是一個簡單的運算,并不需要發(fā)生任何轉(zhuǎn)換 rng = pd.date_range('3/7/2012 09:30', periods = 10, freq='B') ts = Series(np.random.randn(len(rng)), index=rng) print(ts) ''' 2012-03-07 09:30:00 0.041705 2012-03-08 09:30:00 0.461161 2012-03-09 09:30:00 0.197227 2012-03-12 09:30:00 -1.409566 2012-03-13 09:30:00 0.227489 2012-03-14 09:30:00 -1.624908 2012-03-15 09:30:00 0.717115 2012-03-16 09:30:00 -1.355306 2012-03-19 09:30:00 -1.684638 2012-03-20 09:30:00 -0.566004 Freq: B, dtype: float64 ''' ts1= ts[:7].tz_localize('Europe/London') ts2= ts1[2:].tz_convert('Europe/Moscow') result = ts1 + ts2 print(result.index) ''' DatetimeIndex(['2012-03-07 09:30:00+00:00', '2012-03-08 09:30:00+00:00','2012-03-09 09:30:00+00:00', '2012-03-12 09:30:00+00:00','2012-03-13 09:30:00+00:00', '2012-03-14 09:30:00+00:00','2012-03-15 09:30:00+00:00'],dtype='datetime64[ns, UTC]', freq=None) '''5、時期及算術(shù)運算
5.1 時期的構(gòu)建
# 時期表示的是時間區(qū)間,如日、數(shù)月、數(shù)季、數(shù)年等 # Period類所表示的就是此種類型,其構(gòu)造函數(shù)需要用到一個字符串或整數(shù),以及頻率 p = pd.Period(2007,freq='A-DEC') print(p) # 2007# 上述p值表示的是2007年1月1日到2007年12月31日之間的整段時間 # 對Period對象加上或減去一個整數(shù)即可達到根據(jù)其頻率進行位移的效果 print(p+5) # 2012 print(p-2) # 2005# 如果兩個Period對象擁有相同的頻率,則他們的差就是他們之間的單位數(shù)量 print(pd.Period('2014', freq='A-DEC') - p) # <7 * YearEnds: month=12># period_range函數(shù)可以用于創(chuàng)建規(guī)則的的時期范圍 rng = pd.period_range('1/1/2000','6/30/2000', freq='M') print(rng) ''' PeriodIndex(['2000-01', '2000-02', '2000-03', '2000-04', '2000-05', '2000-06'], dtype='period[M]', freq='M') '''# PeriodIndex類保存了一組Period,可以在任何pandas數(shù)據(jù)結(jié)構(gòu)中被用作軸索引 print(Series(np.random.randn(6), index = rng)) ''' 2000-01 -2.155357 2000-02 -0.912094 2000-03 0.358419 2000-04 0.337311 2000-05 1.036003 2000-06 -0.613236 Freq: M, dtype: float64 '''# PeriodIndex類的構(gòu)造函數(shù)還允許直接使用一組字符串 values = ['2001Q3', '2002Q2', '2003Q1'] index = pd.PeriodIndex(values, freq='Q-DEC') print(index) ''' PeriodIndex(['2001Q3', '2002Q2', '2003Q1'], dtype='period[Q-DEC]', freq='Q-DEC') '''5.2 時期的頻率轉(zhuǎn)換
# Period和PeriodIndex都可以通過asfreq方法被轉(zhuǎn)換成別的頻率 p = pd.Period('2007', freq='A-DEC') print(p) # 2007 # 轉(zhuǎn)換為一個年初或年末的一個月度時期 print(p.asfreq('M',how='start')) # 2007-01 print(p.asfreq('M',how='end')) # 2007-12# Period('2007','A-DEC')可以看做一個被劃分為多個月度時期的時間段中的游標(biāo) p=pd.Period('2007', freq='A-JUN') print(p.asfreq('M', 'start')) # 2006-07 print(p.asfreq('M', 'end')) # 2007-06# 高頻率轉(zhuǎn)換為低頻率時,超時期是由時期所屬的位置決定的 # 如,在A-JUN頻率中,月份“2007年8月”實際上是屬于周期“2008年”的 p=pd.Period('2007-08','M') print(p.asfreq('A-JUN')) # 2008# PeriodIndex或TimeSeries的評率轉(zhuǎn)換方式也是如此 rng =pd.period_range('2006','2009', freq='A-DEC') ts=Series(np.random.randn(len(rng)), index=rng) print(ts) ''' 2006 -0.718306 2007 0.273010 2008 -0.441507 2009 -1.229443 Freq: A-DEC, dtype: float64 ''' print(ts.asfreq('M', how='start')) ''' 2006-01 -0.718306 2007-01 0.273010 2008-01 -0.441507 2009-01 -1.229443 Freq: M, dtype: float64 ''' print(ts.asfreq('M', how='end')) ''' 2006-12 -0.718306 2007-12 0.273010 2008-12 -0.441507 2009-12 -1.229443 Freq: M, dtype: float64 '''???Period頻率轉(zhuǎn)換示意圖:
 
5.3 按季度計算的時期頻率
# pandas支持12中可能的季度型頻率,即Q-JAN到Q-DEC # 我的理解,頻率是哪個月份,就是那年Q4結(jié)束的月份,如本例 p=pd.Period('2012Q4', freq='Q-JAN') print(p) # 2012Q4# 在以1月結(jié)束的財年中,2012Q4是從11月到1月 print(p.asfreq('D', 'start')) # 2011-11-01 print(p.asfreq('D', 'end')) # 2012-01-31# 取該季度倒數(shù)第二個工作日下午4點的時間戳 p4pm =(p.asfreq('B', 'e') - 1).asfreq('T', 's') + 16*60 print(p4pm) # 2012-01-30 16:00 print(p4pm.to_timestamp()) # 2012-01-30 16:00:00# period_range可以用于生產(chǎn)季度型范圍 rng = pd.period_range('2011Q3','2012Q4', freq='Q-JAN') ts=Series(np.arange(len(rng)), index = rng) print(ts) ''' 2011Q3 0 2011Q4 1 2012Q1 2 2012Q2 3 2012Q3 4 2012Q4 5 Freq: Q-JAN, dtype: int32 '''new_rng=(rng.asfreq('B', 'e') -1).asfreq('T', 's') + 16*60 ts.index=new_rng.to_timestamp() print(ts) ''' 2010-10-28 16:00:00 0 2011-01-28 16:00:00 1 2011-04-28 16:00:00 2 2011-07-28 16:00:00 3 2011-10-28 16:00:00 4 2012-01-30 16:00:00 5 dtype: int32 '''???不同季度頻率之間的轉(zhuǎn)換:
 
5.4 將Timestamp轉(zhuǎn)化為Period(及其反向過程)
# 通過使用to_period方法,可以將時間戳索引的Series和DataFrame對象轉(zhuǎn)為以時期為索引 rng = pd.date_range('1/1/2000',periods=3,freq='M') ts = Series(np.random.randn(3), index=rng) pts=ts.to_period() print(ts) ''' 2000-01-31 0.563108 2000-02-29 0.784912 2000-03-31 1.014484 Freq: M, dtype: float64 ''' print(pts) ''' 2000-01 0.563108 2000-02 0.784912 2000-03 1.014484 Freq: M, dtype: float64 '''# 由于時期指的是非重疊時間區(qū)間,因此對于給定的頻率,一個時間戳只能屬于一個時期 rng = pd.date_range('1/29/2000', periods=6, freq='D') ts2=Series(np.random.randn(6), index=rng) print(ts2.to_period('M')) ''' 2000-01 -0.139087 2000-01 -0.136360 2000-01 -2.787923 2000-02 -1.520740 2000-02 -0.473269 2000-02 0.600253 Freq: M, dtype: float64 '''pts=ts.to_period() print(pts) ''' 2000-01 -0.219983 2000-02 -1.073624 2000-03 -0.681099 Freq: M, dtype: float64 ''' # 轉(zhuǎn)化為時間戳,使用to_timestamp print(pts.to_timestamp(how='end')) ''' 2000-01-31 23:59:59.999999999 -0.219983 2000-02-29 23:59:59.999999999 -1.073624 2000-03-31 23:59:59.999999999 -0.681099 dtype: float64 '''5.5 通過數(shù)組創(chuàng)建PeriodIndex
# 固定頻率的數(shù)據(jù)集通常會將時間信息分開存放在多列中 data = pd.read_csv('python_data/ch08/macrodata.csv') print(data.year) ''' 0 1959.0 1 1959.0 2 1959.0 3 1959.0 4 1960.0... 198 2008.0 199 2008.0 200 2009.0 201 2009.0 202 2009.0 Name: year, Length: 203, dtype: float64 ''' print(data.quarter) ''' 0 1.0 1 2.0 2 3.0 3 4.0 4 1.0... 198 3.0 199 4.0 200 1.0 201 2.0 202 3.0 Name: quarter, Length: 203, dtype: float64 '''# 將兩個數(shù)組以及一個頻率傳入PeriodIndex,可以將它們合并成DataFrame的一個索引 index = pd.PeriodIndex(year=data.year, quarter=data.quarter, freq='Q-DEC') print(index) ''' PeriodIndex(['1959Q1', '1959Q2', '1959Q3', '1959Q4', '1960Q1', '1960Q2','1960Q3', '1960Q4', '1961Q1', '1961Q2',...'2007Q2', '2007Q3', '2007Q4', '2008Q1', '2008Q2', '2008Q3','2008Q4', '2009Q1', '2009Q2', '2009Q3'],dtype='period[Q-DEC]', length=203, freq='Q-DEC') ''' data.index = index print(data.infl) # infl為data的其中一個屬性 ''' 1959Q1 0.00 1959Q2 2.34 1959Q3 2.74 1959Q4 0.27 1960Q1 2.31... 2008Q3 -3.16 2008Q4 -8.79 2009Q1 0.94 2009Q2 3.37 2009Q3 3.56 Freq: Q-DEC, Name: infl, Length: 203, dtype: float64 '''6、重采樣及頻率轉(zhuǎn)換
6.1 重采樣
# 重采樣是將時間序列從一個頻率轉(zhuǎn)換到另一個評率的過程 # 將高頻率數(shù)據(jù)聚合到低頻率稱為講采樣,而將低頻率數(shù)據(jù)轉(zhuǎn)換到高頻率則稱為升采樣 rng = pd.date_range('1/1/2000',periods = 100, freq='D') ts = Series(np.random.randn(len(rng)), index=rng) print(ts.resample('M').mean()) ''' 2000-01-31 0.066587 2000-02-29 -0.240131 2000-03-31 -0.126769 2000-04-30 0.387274 Freq: M, dtype: float64 ''' print(ts.resample('M', kind='period').mean()) ''' 2000-01 0.066587 2000-02 -0.240131 2000-03 -0.126769 2000-04 0.387274 Freq: M, dtype: float64 '''6.2 降采樣
# 降采樣是將數(shù)據(jù)聚合到規(guī)整的低頻率 rng =pd.date_range('1/1/2000',periods=12,freq='T') ts=Series(np.arange(12), index=rng) print(ts) ''' 2000-01-01 00:00:00 0 2000-01-01 00:01:00 1 2000-01-01 00:02:00 2 2000-01-01 00:03:00 3 2000-01-01 00:04:00 4 2000-01-01 00:05:00 5 2000-01-01 00:06:00 6 2000-01-01 00:07:00 7 2000-01-01 00:08:00 8 2000-01-01 00:09:00 9 2000-01-01 00:10:00 10 2000-01-01 00:11:00 11 Freq: T, dtype: int32 '''# 通過求和的方法將這些數(shù)據(jù)聚合到“5分鐘”塊中 print(ts.resample('5min').sum()) ''' 2000-01-01 00:00:00 10 2000-01-01 00:05:00 35 2000-01-01 00:10:00 21 Freq: 5T, dtype: int32 '''# 默認情況下面元的左邊界是包含的,因此00:00到00:05區(qū)間包含00:05,傳入closed='letf'會讓區(qū)間以左邊界閉合 # !!此處跟書中不同,書中是默認包含右邊界!! print(ts.resample('5min', closed='right').sum()) ''' 1999-12-31 23:55:00 0 2000-01-01 00:00:00 15 2000-01-01 00:05:00 40 2000-01-01 00:10:00 11 Freq: 5T, dtype: int32 '''# 時間序列是以各方面左邊界的時間戳進行標(biāo)記的,傳入label='right'即可用面元動的右邊界對其標(biāo)記 print(ts.resample('5min',label='right').sum()) ''' 2000-01-01 00:05:00 10 2000-01-01 00:10:00 35 2000-01-01 00:15:00 21 Freq: 5T, dtype: int32 '''# 如果對結(jié)果索引做一些位移,如從左邊界減去一秒,只需通過loffset設(shè)置一個字符串或日期偏移量即可 print(ts.resample('5min',loffset='-1s').sum()) ''' 1999-12-31 23:59:59 10 2000-01-01 00:04:59 35 2000-01-01 00:09:59 21 Freq: 5T, dtype: int32 '''# OHLC重采樣,金融領(lǐng)域中有一種無所不在的時間序列聚合方式 # 即計算各面元的四個值,第一個值(開盤)、最后一個值(收盤)、最大值(最高值)、最小值(最低) # 傳入how='ohlc'即可得到一個含有這四種聚合值的DataFrame print(ts.resample('5min').ohlc()) '''open high low close 2000-01-01 00:00:00 0 4 0 4 2000-01-01 00:05:00 5 9 5 9 2000-01-01 00:10:00 10 11 10 11 '''# 通過groupby進行重采樣 rng = pd.date_range('1/1/2000', periods=100, freq='D') ts = Series(np.arange(100), index=rng) print(ts) print(ts.groupby(lambda x: x.month).mean()) ''' 1 15 2 45 3 75 4 95 dtype: int32 '''print(ts.groupby(lambda x: x.weekday).mean()) ''' 0 47.5 1 48.5 2 49.5 3 50.5 4 51.5 5 49.0 6 50.0 dtype: float64 '''6.3 升采樣和差值
# 升采樣是指將數(shù)據(jù)從低頻率轉(zhuǎn)換到高頻率 frame = DataFrame(np.random.randn(2,4),index=pd.date_range('1/1/2000', periods=2, freq='W-WED'),columns=['Colorado', 'Texas', 'New York', 'Ohio']) print(frame[:5]) '''Colorado Texas New York Ohio 2000-01-05 -0.312261 -1.303667 0.166455 1.113591 2000-01-12 -0.719399 0.860489 0.927483 1.041800 '''# 將其重采樣到日頻率,默認會引入缺失值 df_daily = frame.resample('D') print(df_daily) '''DatetimeIndexResampler [freq=<Day>, axis=0, closed=left, label=left, convention=start, base=0]'''# 假如想要用前面的周型填充“非星期三”,resample的填充和差值方式跟fillna和reindex的一樣 print(frame.resample('D').ffill()) '''Colorado Texas New York Ohio 2000-01-05 -0.312261 -1.303667 0.166455 1.113591 2000-01-06 -0.312261 -1.303667 0.166455 1.113591 2000-01-07 -0.312261 -1.303667 0.166455 1.113591 2000-01-08 -0.312261 -1.303667 0.166455 1.113591 2000-01-09 -0.312261 -1.303667 0.166455 1.113591 2000-01-10 -0.312261 -1.303667 0.166455 1.113591 2000-01-11 -0.312261 -1.303667 0.166455 1.113591 2000-01-12 -0.719399 0.860489 0.927483 1.041800 '''# 這里可以只填充指定的時期數(shù)(目的是限制前面的觀測值持續(xù)使用) print(frame.resample('D').ffill(limit=2)) '''Colorado Texas New York Ohio 2000-01-05 -0.312261 -1.303667 0.166455 1.113591 2000-01-06 -0.312261 -1.303667 0.166455 1.113591 2000-01-07 -0.312261 -1.303667 0.166455 1.113591 2000-01-08 NaN NaN NaN NaN 2000-01-09 NaN NaN NaN NaN 2000-01-10 NaN NaN NaN NaN 2000-01-11 NaN NaN NaN NaN 2000-01-12 -0.719399 0.860489 0.927483 1.041800 '''# 新的日期索引完全沒有必要跟舊的相交 print(frame.resample('W-THU').ffill()) '''Colorado Texas New York Ohio 2000-01-06 -0.312261 -1.303667 0.166455 1.113591 2000-01-13 -0.719399 0.860489 0.927483 1.041800 '''6.4 通過時期進行重采樣
frame = DataFrame(np.random.randn(24,4),index=pd.period_range('1-2000','12-2001',freq='M'),columns=['Colorado', 'Texas', 'New York', 'Ohio']) print(frame[:5]) '''Colorado Texas New York Ohio 2000-01 0.778957 1.395773 -0.554445 1.233439 2000-02 0.858590 -0.382989 -0.655546 1.364961 2000-03 0.064890 -1.007406 2.427516 -0.147838 2000-04 0.654691 -2.857103 0.011106 -0.549523 2000-05 0.290338 0.226746 1.007994 0.673866 '''annual_frame = frame.resample('A-DEC').mean() print(annual_frame) '''Colorado Texas New York Ohio 2000 0.406816 -0.262081 -0.186250 0.125175 2001 0.056589 0.340477 0.154083 0.218699 '''# 升采樣稍微麻煩,因為要決定在新的頻率中各區(qū)間的哪端用于放置原來的值,像asfreq方法 print(annual_frame.resample('Q-DEC').ffill()) '''Colorado Texas New York Ohio 2000Q1 0.406816 -0.262081 -0.186250 0.125175 2000Q2 0.406816 -0.262081 -0.186250 0.125175 2000Q3 0.406816 -0.262081 -0.186250 0.125175 2000Q4 0.406816 -0.262081 -0.186250 0.125175 2001Q1 0.056589 0.340477 0.154083 0.218699 2001Q2 0.056589 0.340477 0.154083 0.218699 2001Q3 0.056589 0.340477 0.154083 0.218699 2001Q4 0.056589 0.340477 0.154083 0.218699 '''print(annual_frame.resample('Q-DEC',convention='end').ffill()) '''Colorado Texas New York Ohio 2000Q4 0.406816 -0.262081 -0.186250 0.125175 2001Q1 0.406816 -0.262081 -0.186250 0.125175 2001Q2 0.406816 -0.262081 -0.186250 0.125175 2001Q3 0.406816 -0.262081 -0.186250 0.125175 2001Q4 0.056589 0.340477 0.154083 0.218699 '''7、時間序列繪圖
close_px_all = pd.read_csv('python_data/ch09/stock_px.csv', parse_dates=True,index_col=0) close_px = close_px_all[['AAPL','MSFT','XOM']] close_px = close_px.resample('B').ffill() print(close_px.head()) '''AAPL MSFT XOM 2003-01-02 7.40 21.11 29.22 2003-01-03 7.45 21.14 29.24 2003-01-06 7.45 21.52 29.96 2003-01-07 7.43 21.93 28.95 2003-01-08 7.28 21.31 28.83 '''import matplotlib.pyplot as plt plt.plot(close_px['AAPL']) plt.grid(alpha=0.3, linestyle='dashed') plt.show()# DataFrame調(diào)用plot時,時間序列會被繪制在一個subplot上,并有圖例說明 close_px.loc['2009'].plot() # plt.savefig('10-5.png') plt.show()# 蘋果公司在2011年1月到3月間的每日股價 close_px['AAPL'].loc['01-2011':'03-2011'].plot() plt.grid(alpha=0.3, linestyle='dashed') #plt.savefig('10-6.png') plt.show()# 季度型頻率數(shù)據(jù)會用季度標(biāo)記進行格式化 appl_q=close_px['AAPL'].resample('Q-DEC').ffill() appl_q.loc['2009':].plot() plt.grid(alpha=0.3, linestyle='dashed') #plt.savefig('10-7.png') plt.show()??? ???以下圖片對應(yīng)原書中的圖片序號,按代碼輸出順序給出(其他段落同樣):
 ??? ???圖10-4 AAPL每日價格:
??? ???圖10-5 2009年股票價格:
 
??? ???圖10-6 蘋果公司在2011年1月到3月的每日股價:
 
??? ???圖10-7 蘋果公司在2009年到2011年的每季度價格:
 
8、移動窗口函數(shù)
8.1 移動窗口
# 在移動窗口上計算各種統(tǒng)計函數(shù)是一類常見于時間序列的數(shù)組變換 # rolling_mean是其中最簡單的一個,它接受一個TimeSeries或DataFrame以及一個window(表示期數(shù)) close_px_all = pd.read_csv('python_data/ch09/stock_px.csv', parse_dates=True,index_col=0) close_px = close_px_all[['AAPL','MSFT','XOM']] close_px = close_px.resample('B').ffill() close_px.AAPL.plot() close_px.AAPL.rolling(250).mean().plot() plt.grid(alpha=0.3, linestyle='dashed') plt.show()appl_std250=close_px.AAPL.rolling(250, min_periods=10).std() print(appl_std250[5:12]) ''' 2003-01-09 NaN 2003-01-10 NaN 2003-01-13 NaN 2003-01-14 NaN 2003-01-15 0.077496 2003-01-16 0.074760 2003-01-17 0.112368 Freq: B, Name: AAPL, dtype: float64 '''appl_std250.plot() plt.grid(alpha=0.3, linestyle='dashed') plt.show()# 要計算擴展窗口平均,可以將擴展窗口看做一個特殊的窗口,其長度與時間序列一樣,但只需一期(或多期)即可計算一個值 # 通過rolling().mean()定義擴展平均 expanding_mean = lambda x: x.rolling(len(x), min_periods=1).mean() # 對DataFrame調(diào)用rolling_mean(以及與之類似的函數(shù))會將轉(zhuǎn)換應(yīng)用到所有列上 close_px.rolling(60).mean().plot(logy=True) plt.grid(alpha=0.3, linestyle='dashed') plt.show()??? ???圖10-8 蘋果公司的250的股票均線:
 
??? ???圖10-9 蘋果公司的250日每日回報標(biāo)準(zhǔn)差:
 
??? ???圖10-10 各公司60日均線(對數(shù)Y軸):
 
8.2 指數(shù)加權(quán)函數(shù)
# 另一種使用固定大小窗口及相等權(quán)數(shù)觀測值得辦法是,定義一個衰減因子常量,以便使最近的觀測值擁有更大的權(quán)數(shù) fig,axes = plt.subplots(2,1, sharex=True, sharey=True, figsize=(12,7)) aapl_px = close_px.AAPL['2005': '2009']# 對比蘋果公司股價的60日移動平均和span=60的指數(shù)加權(quán)移動平均 ma60 = aapl_px.rolling(60, min_periods=50).mean() ewma60 = pd.DataFrame.ewm(aapl_px,span=60).mean() aapl_px.plot(style='k-', ax = axes[0]) ma60.plot(style='k--', ax = axes[0]) aapl_px.plot(style='k-', ax = axes[1]) ewma60.plot(style='k--', ax = axes[1]) axes[0].set_title('Simple MA') axes[1].set_title('Exponentially-weithed MA') axes[0].grid(alpha=0.3, linestyle='dashed') axes[1].grid(alpha=0.3, linestyle='dashed') plt.show()??? ???圖10-11 簡單移動平均與指數(shù)加權(quán)移動平均:
 
8.3 二次移動窗口函數(shù)
# 有些運算需(如相關(guān)系數(shù)和協(xié)方差)需要在兩個時間序列上執(zhí)行 # 通過計算百分數(shù)變化并使用rolling_corr的方式得到該結(jié)果 spx_px = close_px_all['SPX'] spx_rets = spx_px/spx_px.shift(1)-1 returns = close_px.pct_change() corr = returns.AAPL.rolling(125, min_periods=100).corr(spx_rets) corr.plot() plt.grid(alpha=0.3, linestyle='dashed') plt.show()# 計算DataFrame各列與標(biāo)準(zhǔn)普爾500指數(shù)的相關(guān)系數(shù) corr = returns.rolling(125,min_periods=100).corr(spx_rets) corr.plot() plt.grid(alpha=0.3, linestyle='dashed') plt.show()??? ???圖10-12 AAPL6個月的回報與標(biāo)準(zhǔn)普爾500指數(shù)的相關(guān)系數(shù):
 
??? ???圖10-13 3只股票6個月的回報與標(biāo)準(zhǔn)普爾500指數(shù)的相關(guān)系數(shù):
 
8.4 用戶定義的移動窗口函數(shù)
# rolling apply()函數(shù)可以在移動窗口上應(yīng)用自己設(shè)計的數(shù)組函數(shù) from scipy.stats import percentileofscore scroe_at_2percent = lambda x: percentileofscore(x, 0.02) result = returns.AAPL.rolling(250).apply(scroe_at_2percent) result.plot() plt.grid(alpha=0.3, linestyle='dashed') plt.show()??? ???圖10-14 AAPL 2%回報率的百分登記(一年窗口期):
 
總結(jié)
以上是生活随笔為你收集整理的《利用Python 进行数据分析》第十章:时间序列的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 微型计算机鸡兔同笼,奥数鸡兔同笼问题
- 下一篇: 公司数百人尽数被抓,只因旗下程序员写了这
