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-09

2014-08-01
2014-07-31

2014-08-01 00:00:00
2014-08-31 23:59:59.999999999

2014-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-21 2016-10-21 00:00:00 2016-10-21 23:59:59.999999999
2016-10-22 2016-10-22 00:00:00 2016-10-22 23:59:59.999999999
2016-10-23 2016-10-23 00:00:00 2016-10-23 23:59:59.999999999
2016-10-24 2016-10-24 00:00:00 2016-10-24 23:59:59.999999999
2016-10-25 2016-10-25 00:00:00 2016-10-25 23:59:59.999999999
2016-10-26 2016-10-26 00:00:00 2016-10-26 23:59:59.999999999
2016-10-27 2016-10-27 00:00:00 2016-10-27 23:59:59.999999999
2016-10-28 2016-10-28 00:00:00 2016-10-28 23:59:59.999999999
2016-10-29 2016-10-29 00:00:00 2016-10-29 23:59:59.999999999
2016-10-30 2016-10-30 00:00:00 2016-10-30 23:59:59.999999999
2016-10-31 2016-10-31 00:00:00 2016-10-31 23:59:59.999999999
2016-11-01 2016-11-01 00:00:00 2016-11-01 23:59:59.999999999
2016-11-02 2016-11-02 00:00:00 2016-11-02 23:59:59.999999999
2016-11-03 2016-11-03 00:00:00 2016-11-03 23:59:59.999999999
2016-11-04 2016-11-04 00:00:00 2016-11-04 23:59:59.999999999
2016-11-05 2016-11-05 00:00:00 2016-11-05 23:59:59.999999999
2016-11-06 2016-11-06 00:00:00 2016-11-06 23:59:59.999999999
2016-11-07 2016-11-07 00:00:00 2016-11-07 23:59:59.999999999
2016-11-08 2016-11-08 00:00:00 2016-11-08 23:59:59.999999999
2016-11-09 2016-11-09 00:00:00 2016-11-09 23:59:59.999999999
2016-11-10 2016-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()