Pythonで時系列分析の練習(10)予測の信頼区間をグラフに表示

Pythonで時系列分析の練習(10)予測の信頼区間をグラフに表示

Pythonで時系列分析する手法をモモノキ&ナノネと一緒に学習していきます。

モモノキ&ナノネと一緒にPythonで時系列分析を覚えよう(10)




時系列分析の実践練習(予測の95%信頼区間をグラフに表示する)

前回の時系列分析の続きで、予測の95%信頼区間をグラフに追加してみよう。

予測範囲みたいなやつ?

うん、予測の95%信頼区間を帯状に塗り潰す予定だよ。コレログラムのグラフ表示みたいに。

ナノネ、前回のコード呼び出してみて。予測結果のグラフが表示できるように必要箇所だけピックアップしてね。

In [14]:
# 飛行機乗客数の時系列データ(前回使用コード抜粋 -> 次回SARIAモデル実践に利用)

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
plt.style.use('ggplot') # グラフのデザイン変更(お好みで利用)
plt.xkcd() # グラフのデザイン変更(お好みで利用、日本語は未対応)
import statsmodels.api as sm # version 0.8.0以上

# CSVファイル読み込み(事前にダウンロードしたCSVファイルを利用)
df = pd.read_csv('AirPassengers.csv')

# Pandas.Seriesにデータを格納(データに乗客数、インデックスは日付)
passengers = pd.Series(df['#Passengers'], dtype='float')
passengers.index = pd.to_datetime(df['Month'])
In [2]:
# オリジナル passengers 1949-01 ~ 1960-12
passengers_train2 = passengers['1949-01':'1959-12'] # モデル作成用データ(訓練)1年テスト用残し
passengers_test2 = passengers['1960-01':'1960-12'] # テスト用データ1年分

# SRIMAモデル(テストデータ1年を除いてモデル作成)
sarimax_train = sm.tsa.SARIMAX(passengers_train2, 
                        order=(3, 1, 3),
                        seasonal_order=(0, 1, 1, 12),
                        enforce_stationarity = False,
                        enforce_invertibility = False
                        ).fit()
In [3]:
sarimax_train2_pred = sarimax_train.predict('1959-12', '1960-12') # テストデータ1年分予測
In [4]:
plt.figure(figsize=(8, 4))

plt.plot(passengers, label="actual")
plt.plot(sarimax_train2_pred, c="b", label="model-pred", alpha=0.7)
plt.legend(loc='best')
Out[4]:
<matplotlib.legend.Legend at 0x13ab9da9160>
In [5]:
plt.figure(figsize=(8, 4))

plt.plot(passengers_test2, label="actual") # 正解
plt.plot(sarimax_train2_pred, c="b", label="predict", alpha=0.7) # 予測
plt.legend(loc='best')
Out[5]:
<matplotlib.legend.Legend at 0x13ab9e52c88>

OK、必要なとこだけピックアップした。予測まで実行しているけど必要なコードは以外に少ない。大半はデータ準備とグラフ描画。

時系列データの事前分析やモデルのパラメータチェックなどを除くと、予測に必要な処理の実装部分のコードは比較的短く書けるね。

信頼区間の範囲をグラフに表示するには、どうやればいいの?

区間の上下限値が取得できれば、なんとかなりそう。値の取得方法が分からないからグーグル先生に聞いてみる。

ポチポチ?・・・・・・・ポチポチ? ...........。

ポチポチ?.......ポチポチ?.......ポチっと、これでいけるかも。

ずいぶん苦戦したね。

get_prediction()とconf_int()を使えば信頼区間の値が取れそうだよ。

StatsModels公式ドキュメント(conf_int)
http://www.statsmodels.org/dev/generated/statsmodels.regression.linear_model.OLSResults.conf_int.html 外部サイト

①モデル変数名.get_prediction(予測開始, 予測終了)として、結果を変数で受ける。結果はstatsmodels.tsa.statespace.mlemodel.PredictionResultsWrapperという形式みたいだね。

In [6]:
predict_dy = sarimax_train.get_prediction(start ='1959-12', end='1960-12')
type(predict_dy)
Out[6]:
statsmodels.tsa.statespace.mlemodel.PredictionResultsWrapper

②受けった結果変数.conf_int(alpha=0.05)とすれば、95%信頼区間の上下値がDataFrameの形式で取得できるみたい。alphaはデフォルトで0.05だから省略可、任意の数値も指定できるよ。

In [7]:
predict_dy_ci = predict_dy.conf_int(alpha=0.05) # defalut alpah=0.05 :returns a 95% confidence interval
type(predict_dy_ci)
Out[7]:
pandas.core.frame.DataFrame
In [8]:
predict_dy_ci # lower, upper取得
Out[8]:
lower #Passengers upper #Passengers
1959-12-01 365.171708 404.342555
1960-01-01 401.752819 440.917529
1960-02-01 376.599837 426.603181
1960-03-01 424.878798 484.178452
1960-04-01 408.392347 471.907092
1960-05-01 431.429160 496.736367
1960-06-01 481.437844 549.045978
1960-07-01 549.543465 618.782603
1960-08-01 561.845352 631.615970
1960-09-01 465.089435 535.525025
1960-10-01 406.888698 478.122081
1960-11-01 361.756949 433.270359
1960-12-01 403.359057 475.098801

DataFrameの中身は上の通りで、指定した期間の信頼区間が取得できてるよ。データの1列目がlower値、2列目がupper値だね。

あと予測の平均値は.predicted_meanで取得できるよ。これまで使ってきた.predict()の結果と同じだよ。

In [9]:
predict_dy.predicted_mean # mean取得
Out[9]:
1959-12-01    384.757131
1960-01-01    421.335174
1960-02-01    401.601509
1960-03-01    454.528625
1960-04-01    440.149720
1960-05-01    464.082764
1960-06-01    515.241911
1960-07-01    584.163034
1960-08-01    596.730661
1960-09-01    500.307230
1960-10-01    442.505389
1960-11-01    397.513654
1960-12-01    439.228929
Freq: MS, dtype: float64

lowerとupper値を使ってグラフに帯状に塗り潰すには?

Matplotlibのfill_between()を使えば簡単にできるよ。引数にx値(インデックス)、y-lower値、 y-upper値を渡せば、いい感じに塗り潰してくれるよ。色とか透明度はお好みでしてね。

In [10]:
plt.figure(figsize=(8, 4))

plt.plot(passengers_test2, label="Actual")
plt.plot(predict_dy.predicted_mean, c="b", label="model-pred", alpha=0.7)

plt.fill_between(predict_dy_ci.index, predict_dy_ci.iloc[:, 0], predict_dy_ci.iloc[:, 1], color='g', alpha=0.2)
plt.legend(loc='upper left')
Out[10]:
<matplotlib.legend.Legend at 0x13ab9e84358>

できた。緑で薄く塗り潰したところが、95%信頼区間だね。

In [11]:
predict2_dy = sarimax_train.get_prediction(start ='1959-12', end='1961-12') # 2年分の未来予測

predict2_dy_ci = predict2_dy.conf_int()

plt.figure(figsize=(12, 4))
plt.plot(passengers['1959-01':], label="actual")
plt.plot(predict2_dy.predicted_mean, c="b", linestyle='--', label="model-pred", alpha=0.7)

plt.fill_between(predict2_dy_ci.index, predict2_dy_ci.iloc[:, 0], predict2_dy_ci.iloc[:, 1], color='g', alpha=0.2)
plt.legend(loc='upper left')
Out[11]:
<matplotlib.legend.Legend at 0x13ab9e6b828>

予測を1年増やして、表示期間も少しか変えてみた。

初めてにしては、それっぽい予測ができたね。

うまく予測できるか分からないけど、他のデータ使ったモデル作成にも挑戦してみてね。

飛行機乗客数を使った時系列分析の練習は以上だよ。

理解不足で説明が不足してたり正確ではないとこもあるので、もっと詳しい書籍やサイト利用して理解を深めてね。あと、利用しているパッケージの仕様が大きくかわるとコードが動作しなくなる可能性もあるので、その時は代替方法を検索で調べてみてね。

ラジャー、お疲れさまでした。

お疲れさまでした。またね。

In [12]:
# 実行環境
# import pkg_resources
# for dist in pkg_resources.working_set:
#     print(dist.project_name, dist.version)

・Python 3.6.4 |Anaconda ・notebook 5.4.0 ・matplotlib 2.1.2 ・pandas 0.22.0 ・numpy 1.14.0 ・statsmodels 0.8.0

In [15]:
# モモノキ&ナノネと一緒にPythonで時系列分析を覚えよう

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
plt.style.use('ggplot')
plt.xkcd()
import statsmodels.api as sm # version 0.8.0以上

# CSVファイル読み込み(事前にダウンロードしたCSVファイルを利用)
df = pd.read_csv('AirPassengers.csv')

# Pandas.Seriesにデータを格納
passengers = pd.Series(df['#Passengers'], dtype='float') # 乗客数
passengers.index = pd.to_datetime(df['Month']) # 日付インデックス

# 元データ分割:passengers 1949-01 ~ 1960-12
passengers_train2 = passengers['1949-01':'1959-12'] # 訓練データ(モデル作成用)
passengers_test2 = passengers['1960-01':'1960-12'] # テストデータ1年分(検証用)

# SRIMAモデル
sarimax_train = sm.tsa.SARIMAX(passengers_train2, 
                        order=(3, 1, 3), 
                        seasonal_order=(0, 1, 1, 12),
                        enforce_stationarity = False,
                        enforce_invertibility = False
                        ).fit()

# モデルによる予測
predict2_dy = sarimax_train.get_prediction(start ='1959-12', end='1961-12') # 2年分の未来予測
predict2_dy_ci = predict2_dy.conf_int() # 信頼区間取得

# グラフ表示
plt.figure(figsize=(12, 4))
plt.plot(passengers['1959-01':], label="actual") # 実データプロット
plt.plot(predict2_dy.predicted_mean, c="b", linestyle='--', label="model-pred", alpha=0.7) # 予測プロット

# 予測の95%信頼区間プロット(帯状)
plt.fill_between(predict2_dy_ci.index, predict2_dy_ci.iloc[:, 0], predict2_dy_ci.iloc[:, 1], color='g', alpha=0.2)

plt.legend(loc='upper left')
Out[15]:
<matplotlib.legend.Legend at 0x13abb411a90>




スポンサーリンク

0 件のコメント :

コメントを投稿