pandasで時系列データを扱う(pandas.Seriesとpandas.DataFrameを使って時系列データを扱う)2
「pandasで時系列データを扱う(pandas.Seriesとpandas.DataFrameを使って時系列データを扱う)1」の続き。
全部で下記を実施予定。
1.時系列データとDatetimeIndex
2.指定した頻度の時系列データを作成する方法
3.日付のoffsetsを使用して新しい日付を計算する方法
4.指定した期間で時系列データを扱う方法
5.時系列データのlagを取る方法
6.時系列データの頻度を変更する方法
7.時系列データのresampling(upsamplingとdownsampling)
前回は1と2と3を実施。
4.指定した期間で時系列データを扱う方法
・pandas.Periodを使用する。
Periodオブジェクトはstart timeとend timeから成り、作成する時は開始日付と頻度を指定して作成する。
指定した頻度での日付の加算・減算も可能。
#coding:utf-8 import pandas as pd ## periodを使用する # 月毎のデータ augYYYYMM = pd.Period( '2014-08', freq='M' ) print augYYYYMM # 指定した頻度で加算される print augYYYYMM+1 # 日毎のデータ augYYYYMMDD = pd.Period( '2014-08', freq='D' ) print augYYYYMMDD # 指定した頻度で減算される print augYYYYMMDD-1 # それぞれstart_timeとend_timeを表示する print augYYYYMM.start_time print augYYYYMM.end_time print augYYYYMMDD.start_time print augYYYYMMDD.end_time
実行結果は次。
2014-08
2014-092014-08-01
2014-07-312014-08-01 00:00:00
2014-08-31 23:59:59.9999999992014-08-01 00:00:00
2014-08-01 23:59:59.999999999
・pandas.period_rangeを使用する
前回「pandas.date_range」を使用した。これはstartもしくはendの片方を指定し、同時に頻度を指定することで指定期間のDatetimeIndexを取得するメソッドだった。
今回は、startとendを指定し、同時に頻度を指定することで、指定期間の指定頻度のPeriodIndexを取得するpandas.period_rangeメソッドを使用する。
#coding:utf-8 import pandas as pd ### periodIndexを取得する periodRange = pd.period_range( start = '2016-10-20', end = '2016-11-10', freq = 'D' ) print periodRange
実行結果は次。
PeriodIndex(['2016-10-20', '2016-10-21', '2016-10-22', '2016-10-23',
'2016-10-24', '2016-10-25', '2016-10-26', '2016-10-27',
'2016-10-28', '2016-10-29', '2016-10-30', '2016-10-31',
'2016-11-01', '2016-11-02', '2016-11-03', '2016-11-04',
'2016-11-05', '2016-11-06', '2016-11-07', '2016-11-08',
'2016-11-09', '2016-11-10'],
dtype='period[D]', freq='D')
PeriodIndexはDatetimeIndexとは異なり、indexのラベルがPeriodオブジェクトである。
次のようにfor文で繰り返す。
#coding:utf-8 import pandas as pd ### periodIndexを取得する periodRange = pd.period_range( start = '2016-10-20', end = '2016-11-10', freq = 'D' ) ### for文で繰り返しフォーマットして出力する for period in periodRange: print "{0} {1} {2} {3}".format(period, period.freq, period.start_time, period.end_time)
結果は次。
2016-10-20
2016-10-20 00:00:00 2016-10-20 23:59:59.999999999
2016-10-212016-10-21 00:00:00 2016-10-21 23:59:59.999999999
2016-10-222016-10-22 00:00:00 2016-10-22 23:59:59.999999999
2016-10-232016-10-23 00:00:00 2016-10-23 23:59:59.999999999
2016-10-242016-10-24 00:00:00 2016-10-24 23:59:59.999999999
2016-10-252016-10-25 00:00:00 2016-10-25 23:59:59.999999999
2016-10-262016-10-26 00:00:00 2016-10-26 23:59:59.999999999
2016-10-272016-10-27 00:00:00 2016-10-27 23:59:59.999999999
2016-10-282016-10-28 00:00:00 2016-10-28 23:59:59.999999999
2016-10-292016-10-29 00:00:00 2016-10-29 23:59:59.999999999
2016-10-302016-10-30 00:00:00 2016-10-30 23:59:59.999999999
2016-10-312016-10-31 00:00:00 2016-10-31 23:59:59.999999999
2016-11-012016-11-01 00:00:00 2016-11-01 23:59:59.999999999
2016-11-022016-11-02 00:00:00 2016-11-02 23:59:59.999999999
2016-11-032016-11-03 00:00:00 2016-11-03 23:59:59.999999999
2016-11-042016-11-04 00:00:00 2016-11-04 23:59:59.999999999
2016-11-052016-11-05 00:00:00 2016-11-05 23:59:59.999999999
2016-11-062016-11-06 00:00:00 2016-11-06 23:59:59.999999999
2016-11-072016-11-07 00:00:00 2016-11-07 23:59:59.999999999
2016-11-082016-11-08 00:00:00 2016-11-08 23:59:59.999999999
2016-11-092016-11-09 00:00:00 2016-11-09 23:59:59.999999999
2016-11-102016-11-10 00:00:00 2016-11-10 23:59:59.999999999
最後に、PeriodIndexをSeriesのindexとして使用してSeries型のデータを作成する。
#coding:utf-8 import pandas as pd import numpy as np ### periodIndexを取得する periodRange = pd.period_range( start = '2016-10-20', end = '2016-11-10', freq = 'D' ) periodRangeSeries = pd.Series( data=np.random.randn(len(periodRange)), index=periodRange ) print periodRangeSeries
実行結果は次。
2016-10-20 -0.252482
2016-10-21 1.240022
2016-10-22 -0.230966
2016-10-23 -1.590936
2016-10-24 1.601141
2016-10-25 -0.575829
2016-10-26 0.099768
2016-10-27 -0.911231
2016-10-28 0.815598
2016-10-29 -1.186225
2016-10-30 0.515085
2016-10-31 -0.537140
2016-11-01 1.289884
2016-11-02 -2.020320
2016-11-03 2.418930
2016-11-04 -0.937541
2016-11-05 -0.054052
2016-11-06 0.678914
2016-11-07 -0.344491
2016-11-08 0.570634
2016-11-09 0.008888
2016-11-10 -0.021297
Freq: D, dtype: float64
5.時系列データのlagを取る方法
ここではpandas.DataFrame.shiftを使ったlagの取り方を試す。
日次変化率を求めるのによく使われる。
#coding:utf-8 import pandas as pd import datetime as dt import numpy as np import pandas_datareader.data as pdd # 期間設定 date_from = dt.date(2016, 9, 24) date_to = dt.date(2016, 10, 6) # 株価取得 aapl = pdd.DataReader('AAPL', "yahoo", date_from, date_to) print "aapl" print aapl ## panda.shift関数を使用してlagを取る # データを未来の方向にずらす aaplShiftedForward = aapl.shift(1) print "" print "aaplShiftedForward" print aaplShiftedForward # データを過去の方向にずらす aaplShiftedBack = aapl.shift(-1) print "" print "aaplShiftedBack" print aaplShiftedBack
実行結果は次。
aapl
Open High Low Close Volume \
Date
2016-09-26 111.639999 113.389999 111.550003 112.879997 29869400
2016-09-27 113.000000 113.180000 112.339996 113.089996 24607400
2016-09-28 113.690002 114.639999 113.430000 113.949997 29641100
2016-09-29 113.160004 113.800003 111.800003 112.180000 35887000
・・・・・・・・aaplShiftedForward
Open High Low Close Volume \
Date
2016-09-26 NaN NaN NaN NaN NaN
2016-09-27 111.639999 113.389999 111.550003 112.879997 29869400.0
2016-09-28 113.000000 113.180000 112.339996 113.089996 24607400.0
2016-09-29 113.690002 114.639999 113.430000 113.949997 29641100.0
・・・・・・・・aaplShiftedBack
Open High Low Close Volume \
Date
2016-09-26 113.000000 113.180000 112.339996 113.089996 24607400.0
2016-09-27 113.690002 114.639999 113.430000 113.949997 29641100.0
2016-09-28 113.160004 113.800003 111.800003 112.180000 35887000.0
・・・・・・・・
2016-10-04 113.400002 113.660004 112.690002 113.050003 21453100.0
2016-10-05 113.699997 114.339996 113.129997 113.889999 28779300.0
2016-10-06 NaN NaN NaN NaN NaN
日次変化率を求めるには次のようにする。
# 日次変化率を求める print aapl/aaplShiftedForward-1
Open High Low Close Volume Adj Close
Date
2016-09-26 NaN NaN NaN NaN NaN NaN
2016-09-27 0.012182 -0.001852 0.007082 0.001860 -0.176167 0.001860
2016-09-28 0.006106 0.012900 0.009703 0.007605 0.204560 0.007605
2016-09-29 -0.004662 -0.007327 -0.014370 -0.015533 0.210718 -0.015533
2016-09-30 -0.006186 -0.003779 0.000000 0.007755 0.013712 0.007755
2016-10-03 0.002223 -0.002823 0.004293 -0.004688 -0.403454 -0.004688
・・・・・・・・
6.時系列データの頻度を変更する方法
pandas.DataFrame.asfreqを使用する。
#coding:utf-8 import pandas as pd import datetime as dt import numpy as np import pandas_datareader.data as pdd # 期間設定 date_from = dt.date(2016, 9, 24) date_to = dt.date(2016, 10, 6) # 株価取得 aapl = pdd.DataReader('AAPL', "yahoo", date_from, date_to) # 頻度を変換する(1時間毎) aapl_H = aapl.asfreq('H') print aapl_H # ffillを使って前方へのデータの穴埋めを行う aapl_H_ffill = aapl.asfreq('H', method='ffill') print aapl_H_ffill # bfillを使って後方へのデータの穴埋めを行う aapl_H_bfill = aapl.asfreq('H', method='bfill') print aapl_H_bfill
1時間毎に変換した結果は次。
Open High Low Close \
Date
2016-09-26 00:00:00 111.639999 113.389999 111.550003 112.879997
2016-09-26 01:00:00 NaN NaN NaN NaN
2016-09-26 02:00:00 NaN NaN NaN NaN
・・・・・・・・・
2016-09-26 23:00:00 NaN NaN NaN NaN
2016-09-27 00:00:00 113.000000 113.180000 112.339996 113.089996
2016-09-27 01:00:00 NaN NaN NaN NaN
ffillで前方を穴埋めした結果が次。
Open High Low Close Volume \
Date
2016-09-26 00:00:00 111.639999 113.389999 111.550003 112.879997 29869400
2016-09-26 01:00:00 111.639999 113.389999 111.550003 112.879997 29869400
2016-09-26 02:00:00 111.639999 113.389999 111.550003 112.879997 29869400
2016-09-26 03:00:00 111.639999 113.389999 111.550003 112.879997 29869400
・・・・・・・・・・・・・
bfillで後方穴埋めした結果が次。
Open High Low Close Volume \
Date
2016-09-26 00:00:00 111.639999 113.389999 111.550003 112.879997 29869400
2016-09-26 01:00:00 113.000000 113.180000 112.339996 113.089996 24607400
2016-09-26 02:00:00 113.000000 113.180000 112.339996 113.089996 24607400
2016-09-26 03:00:00 113.000000 113.180000 112.339996 113.089996 24607400
・・・・・・・・・・・・・
7.時系列データのresampling(upsamplingとdownsampling)
これは以前「Pythonでの時系列データの扱い6 〜 データの再サンプリング(ダウンサンプリングとアップサンプリング)」で書いたネタと同じ。
ここではAAPLの株価を元に、株価の日次変化率(日次リターン)を求め、そのデータをresamplingする。
まずは日次リターンと、その累積を求める。
#coding:utf-8 import pandas as pd import datetime as dt import numpy as np import pandas_datareader.data as pdd # 期間設定 date_from = dt.date(2016, 9, 24) date_to = dt.date(2016, 10, 6) # 株価取得 aapl = pdd.DataReader('AAPL', "yahoo", date_from, date_to) # データを未来の方向にずらす aaplShiftedForward = aapl.shift(1) # 日次変化率(日次リターン)を求める aaplyDailyReturn = aapl/aaplShiftedForward-1 print aaplyDailyReturn # 日次リターンの累積(該当期間のリターン)を求める aaplCumulativeReturn = (1+aaplyDailyReturn).cumprod() print aaplCumulativeReturn
日次リターンの累積結果は下記。
Open High Low Close Volume Adj Close
Date
2016-09-26 NaN NaN NaN NaN NaN NaN
2016-09-27 1.012182 0.998148 1.007082 1.001860 0.823833 1.001860
2016-09-28 1.018363 1.011024 1.016853 1.009479 0.992357 1.009479
2016-09-29 1.013615 1.003616 1.002241 0.993799 1.201464 0.993799
2016-09-30 1.007345 0.999824 1.002241 1.001506 1.217939 1.001506
2016-10-03 1.009584 0.997002 1.006544 0.996811 0.726556 0.996811
2016-10-04 1.012719 1.008114 1.009682 1.001063 0.995561 1.001063
2016-10-05 1.015765 1.002381 1.010220 1.001506 0.718230 1.001506
2016-10-06 1.018452 1.008378 1.014164 1.008948 0.963504 1.008948
次に、調整終値について同様のことをして、resampleする。
#coding:utf-8 import pandas as pd import datetime as dt import numpy as np import pandas_datareader.data as pdd # 期間設定 date_from = dt.date(2016, 9, 24) date_to = dt.date(2016, 10, 6) # 株価取得 aapl = pdd.DataReader('AAPL', "yahoo", date_from, date_to) # 終値の日次リターンを求める aaplAdjCloseDailyReturn = aapl['Adj Close']/aapl['Adj Close'].shift(1)-1 print aaplAdjCloseDailyReturn # 終値の日次リターンの累積を求める aaplAdjCloseCumulativeDailyReturn = (1+aaplAdjCloseDailyReturn).cumprod() print aaplAdjCloseCumulativeDailyReturn # 月次OHLCにdownsamplingする aaplAdjCloseCumulativeMontylyReturn = aaplAdjCloseCumulativeDailyReturn.resample('M'. how='ohlc') print aaplAdjCloseCumulativeMontylyReturn
結果は次。
Backend TkAgg is interactive backend. Turning interactive mode on.
Date
2016-09-26 NaN
2016-09-27 0.001860
2016-09-28 0.007605
2016-09-29 -0.015533
2016-09-30 0.007755
2016-10-03 -0.004688
2016-10-04 0.004266
2016-10-05 0.000443
2016-10-06 0.007430
Name: Adj Close, dtype: float64
Date
2016-09-26 NaN
2016-09-27 1.001860
2016-09-28 1.009479
2016-09-29 0.993799
2016-09-30 1.001506
2016-10-03 0.996811
2016-10-04 1.001063
2016-10-05 1.001506
2016-10-06 1.008948
Name: Adj Close, dtype: float64
FutureWarning: how in .resample() is deprecated
the new syntax is .resample(...).ohlc()
aaplAdjCloseCumulativeMontylyReturn = aaplAdjCloseCumulativeDailyReturn.resample('M', how='ohlc')
open high low close
Date
2016-09-30 1.001860 1.009479 0.993799 1.001506
2016-10-31 0.996811 1.008948 0.996811 1.008948
ここでresample('M', how='ohlc')は将来deprecatedされるので以下のように書き直す。
aaplAdjCloseCumulativeMontylyReturn = aaplAdjCloseCumulativeDailyReturn.resample('M').ohlc()