[sktime] 株価予測AIを作るまで:その③ 重回帰分析 [Prophet]

2021年12月10日金曜日

Artificial Intelligence

一つ一つ順を追っていきながら機械学習を使った株価予測モデルを作っていきます。
本記事では、Sktimeを使って株価データから重回帰分析を行ってみます。

アイキャッチ

概要

以下の記事で、時系列データに特化した機械学習ライブラリSktimeの導入、及び、yahoo_finance_api2を用いた日本株データ取得を行いました。 そして、Sktimeで日本株の単回帰分析を行いました。

本記事では、その続きとして重回帰分析を行っていきたいと思います。

重回帰分析とは

数多の解説記事が存在するため詳細な説明は省きますが、一言でいえば複数の入力変数から 1つの出力変数を予測することです。

今回は、株価の前日の始値、終値、出来高などの複数の入力変数を使って翌日以降の終値を予測してみます。
なお本記事で紹介するソースコードはこちらのGithubに全て載せています

免責事項
本記事は、機械学習、AIの学習を目的としており、投資を薦めるものではありません。
本記事の内容を基に投資を行って生じる、いかなる損失も本記事は一切の責任を負いません。

また、このデモはPythonで実装しています。
Pythonの実装に不安がある方、Pythonを使った機械学習について詳しく勉強したい方は、以下の書籍やオンライン講座などがおすすめです。

データの前処理

今回はyahoo_finance_api2から取得した株価データから、入力変数となる前日の始値、高値、底値、終値、出来高を作成していきます。

はじめに、必要なモジュールをインポートします。

# file: stock_multiple_regression.ipynb

import sys
import os
from yahoo_finance_api2 import share
from yahoo_finance_api2.exceptions import YahooFinanceError
import pandas as pd
import numpy as np
import pickle

from sktime.utils.plotting import plot_series
from sktime.forecasting.model_selection import temporal_train_test_split
from sktime.forecasting.base import ForecastingHorizon

from sktime.forecasting.theta import ThetaForecaster
from sktime.forecasting.fbprophet import Prophet
from sktime.performance_metrics.forecasting import mean_absolute_percentage_error

次に、yahoo_finance_api2から取得したデータを整形する関数を定義します。
処理概要はDataFrameに格納し、timestampをUTC時間に変換しています。

def data_shaping(symbol_data):
    '''
    yahoo_finance_api2のdataをDataFrameに整形
    '''
    
    # DataFrameに初期化
    df_symbol_data = pd.DataFrame(symbol_data)

    # UNIX時間をUTC時間に変換
    df_symbol_data.timestamp = pd.to_datetime(df_symbol_data.timestamp, unit='ms')
    
    return df_symbol_data

任天堂の株価を5年分取得します。

my_share = share.Share('7974.T') # 東京証券の証券コード指定:任天堂

symbol_data = None

try:
    # 5年分を1日間隔で取得
    symbol_data = my_share.get_historical(share.PERIOD_TYPE_YEAR,
    5,
    share.FREQUENCY_TYPE_DAY,
    1)
except YahooFinanceError as e:
    print(e.message)
    sys.exit(1)

# Dataframeに整形
df_symbol_data = data_shaping(symbol_data)

df_symbol_data
任天堂の株価データ

目的変数となるデータを作成します。
先頭行を削除している理由は、前日までのデータを使って翌日以降の終値を予測するため、 取得したデータの初日の終値を予測する前日のデータが存在しないためです。

# 取引日と終値のみのSeriesを生成
y = df_symbol_data['close']
index = df_symbol_data['timestamp']
y.index = pd.PeriodIndex(index, freq="D")
# 先頭行削除
y = y[1:]
y
目的変数の出力結果

次に、入力変数となるデータを作成します。

X = df_symbol_data[['open', 'high', 'low', 'volume']]
X.index = pd.PeriodIndex(index, freq="D")

前日までのデータを使って次の日以降の終値を求めるため入力変数を1日ずらします。

# 前日までのデータを使用
X = X.shift(1)
X = X[1:]
X

データの前処理の最後に学習データとテストデータに分割します。
今回は、データの5%をテストデータとして利用します。

# indexをPeriodIndexをDatetimeIndexに変更
y.index = y.index.to_timestamp()
X.index = X.index.to_timestamp()

# targetの5%をtestデータに分割
y_train, y_test, X_train, X_test = temporal_train_test_split(y, X, test_size=int(len(y) * 0.05) )
# グラフ化
plot_series(y_train.tail(100), y_test.tail(100), labels=["y_train", "y_test"])
テストデータ分割後のグラフ

青色で表されている箇所が学習データ、オレンジで表されている箇所がテストデータです。

モデルのトレーニング

今回はProphetを用いてモデルをトレーニングしてみます。
ProphetはFacebookが開発した時系列予測のためのライブラリでありSktimeから利用する事が可能となっています。

# Prophetモデル
model_name = './models/stock_close_multiple_regression_prophet.pkl'

if os.path.exists(model_name):
    print("Already exists model", model_name)
    with open(model_name, 'rb') as f:
        forecaster = pickle.load(f)
else:
    forecaster = Prophet(
        seasonality_mode='multiplicative',
        add_country_holidays={'country_name': 'JP'},
        daily_seasonality=True
    )
    forecaster.fit(y=y_train, X=X_train)
    # save model
    with open(model_name,'wb') as f:
        pickle.dump(forecaster,f)
    print("save model", model_name)

stock_close_multiple_regression_prophet.pklが出力されました。
環境にもよりますが、学習自体は1分もたたずに終了しました。

トレーニングによって作成したモデルを使ってテストデータ期間の終値を予測してみたいと思います。
まず、予測期間を示すForecastingHorizonを定義します。

# forecasting horizon
fh = ForecastingHorizon(
    y_test.index, is_relative=False
)

トレーニングしたモデルを使って翌日以降の終値を予測してみます。

# 予測
y_pred = forecaster.predict(fh=fh, X=X_test)
# 予測結果のグラフ化
plot_series(y_train.tail(100), y_test, y_pred, labels=["y_train", "y_test", "y_pred"])
Prophetの予測結果

ぱっと見ると予測できていそうですが予測結果がテストデータの1日遅れのコピーのようになっている点が気になります。

モデルが前日の値をそのまま返してしまえば予測値がそれほど外れないことを学習してしまっていそうです。

モデルの評価

最後に生成したモデルの評価を行います。
今回はMAPE(平均絶対パーセント誤差)を用います。ざっくりというと誤差の割合であるため算出結果は少ないほど精度が高いことを示しています。

# 精度検証: MAPE(平均絶対パーセント誤差)
MAPE = mean_absolute_percentage_error(y_test, y_pred)
# 精度検証: sMAPE(対照的平均絶対パーセント誤差)
SMAPE = mean_absolute_percentage_error(y_test, y_pred, symmetric=True)
print("MAPE:", MAPE, "SMAPE:", SMAPE)

# 出力結果
MAPE: 0.014812649413013869 SMAPE: 0.014812649413013869

MAPEの結果は0.014812649413013869となりました。

ちなみにProphetで終値を入力変数に翌日以降の終値を予測する単回帰分析のモデルも生成してみましたが、
こちらの結果はMAPEで0.0198925895059899となったので、やや改善していると言った程度ですね。 入力変数が銘柄単体の指標のみであると、値幅の動きが小さいこともあり有効なモデルとなりにくいかもしれません。

まとめ

本記事では、SktimeでProphetを使用して株価の終値を重回帰分析を実施してみました。
筆者自身勉強中の身であるためご指摘事項等あれば、コメント頂けると幸いです。
また今後は特徴量エンジニアリングに取り組みたいと思います。

合わせてこちらの本なども再度勉強しようと思います。

AIで副業ならココから!

まずは無料会員登録

プロフィール

メーカーで研究開発を行う現役エンジニア
組み込み機器開発や機会学習モデル開発に従事しています

本ブログでは最新AI技術を中心にソースコード付きでご紹介します


Twitter

カテゴリ

このブログを検索

ブログ アーカイブ

TeDokology