ランダムフォレストで、株価の予測を行ってみる。
実装したコード
# ライブラリのインポート
from datetime import datetime, timedelta
import numpy as np
import pandas as pd
from pandas_datareader import data
import matplotlib.pyplot as plt
%matplotlib inline
# ワーニングを非表示にする設定(任意)
import warnings
warnings.simplefilter('ignore')
# 最大表示行数の指定(任意:ここでは10行を指定)
pd.set_option('display.max_rows', 10)
# pandas_datareaderを使って、2018年始から2021年末までの日経平均株価データの取得
start = '2018-01-01'
end = '2022-06-03'
data_master = data.DataReader('7419.JP', 'stooq', start, end)
data_master
data_master = data_master[::-1]
data_master
# 曜日情報を追加(0:月曜日〜4:金曜日)
data_master['weekday'] = data_master.index.weekday
data_master
plt.figure(figsize=(10,6))
plt.plot(data_master['Close'], label='Close', color='orange')
plt.xlabel('Date')
plt.ylabel('JPY')
plt.legend()
plt.show()
# data_techinicalにデータをコピー
data_technical = data_master.copy()
# 移動平均を追加
SMA1 = 5 #短期5日
SMA2 = 10 #中期10日
SMA3 = 15 #長期15日
data_technical['SMA1'] = data_technical['Close'].rolling(SMA1).mean() #短期移動平均の算出
data_technical['SMA2'] = data_technical['Close'].rolling(SMA2).mean() #中期移動平均の算出
data_technical['SMA3'] = data_technical['Close'].rolling(SMA3).mean() #長期移動平均の算出
# 特徴量を描画して確認
plt.figure(figsize=(10, 6))
plt.plot(data_technical['Close'], label='Close', color='orange')
plt.plot(data_technical['SMA1'], label='SMA1', color='red')
plt.plot(data_technical['SMA2'], label='SMA2', color='blue')
plt.plot(data_technical['SMA3'], label='SMA3', color='green')
plt.xlabel('Date')
plt.ylabel('JPY')
plt.legend()
plt.show()
# 特徴量を描画して確認(x軸の拡大)
plt.figure(figsize=(10, 6))
plt.plot(data_technical['Close'], label='Close', color='orange')
plt.plot(data_technical['SMA1'], label='SMA1', color='red')
plt.plot(data_technical['SMA2'], label='SMA2', color='blue')
plt.plot(data_technical['SMA3'], label='SMA3', color='green')
plt.xlabel('Date')
plt.ylabel('JPY')
plt.legend()
xmin = datetime(2018,1,1)
xmax = datetime(2022,6,3)
plt.xlim([xmin,xmax])
plt.show()
# OpenとCloseの差分を実体Bodyとして計算
data_technical['Body'] = data_technical['Open'] - data_technical['Close']
# 前日終値との差分Close_diffを計算
data_technical['Close_diff'] = data_technical['Close'].diff(1)
# 目的変数となる翌日の終値Close_nextの追加
data_technical['Close_next'] = data_technical['Close'].shift(-1)
data_technical
data_technical = data_technical.dropna(how='any')
data_technical
# 木曜日のデータを抜き出す
data_technical = data_technical[data_technical['weekday'] == 3]
data_technical
# 必要なカラムを抽出
data_technical = data_technical[['High', 'Low', 'Open', 'Close', 'Body',
'Close_diff', 'SMA1', 'SMA2', 'SMA3', 'Close_next']]
data_technical
# 2018年〜2021年を学習用データとする
train = data_technical['2018-01-01' : '2021-12-31']
train
# 2022年をテストデータとする
test = data_technical['2022-01-01' :]
test
# 学習用データとテストデータそれぞれを説明変数と目的変数に分離する
X_train = train.drop(columns=['Close_next']) #学習用データ説明変数
y_train = train['Close_next'] #学習用データ目的変数
X_test = test.drop(columns=['Close_next']) #テストデータ説明変数
y_test = test['Close_next'] #テストデータ目的変数
# 線形回帰モデルのLinearRegressionをインポート
from sklearn.ensemble import RandomForestRegressor
# 時系列分割のためTimeSeriesSplitのインポート
from sklearn.model_selection import TimeSeriesSplit
# 予測精度検証のためMSEをインポート
from sklearn.metrics import mean_squared_error as mse
from sklearn.metrics import r2_score
# 時系列分割交差検証
valid_scores = []
tscv = TimeSeriesSplit(n_splits=4)
for fold, (train_indices, valid_indices) in enumerate(tscv.split(X_train)):
X_train_cv, X_valid_cv = X_train.iloc[train_indices], X_train.iloc[valid_indices]
y_train_cv, y_valid_cv = y_train.iloc[train_indices], y_train.iloc[valid_indices]
# 線形回帰モデルのインスタンス化
model = RandomForestRegressor()
# モデル学習
model.fit(X_train_cv, y_train_cv)
# 予測
y_valid_pred = model.predict(X_valid_cv)
# 予測精度(RMSE)の算出
score = np.sqrt(mse(y_valid_cv, y_valid_pred))
# 予測精度スコアをリストに格納
valid_scores.append(score)
print(f'valid_scores: {valid_scores}')
cv_score = np.mean(valid_scores)
print(f'CV score: {cv_score}')
model = RandomForestRegressor()
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
score = np.sqrt(mse(y_test, y_pred))
print(f'RMSE: {score}')
r2 = r2_score(y_test, y_pred)
print(f'r2_score:{r2}')
# 実際のデータと予測データをデータフレームにまとめる
df_result = test[['Close_next']]
df_result['Close_pred'] = y_pred
df_result
# 実際のデータと予測データの比較グラフ作成
plt.figure(figsize=(10, 6))
plt.plot(df_result[['Close_next', 'Close_pred']])
plt.plot(df_result['Close_next'], label='Close_next', color='orange')
plt.plot(df_result['Close_pred'], label='Close_pred', color='blue')
plt.xlabel('Date')
plt.ylabel('JPY')
xmin = df_result.index.min()
xmax = df_result.index.max()
plt.legend()
plt.show()
ぼく的ポイント
model = RandomForestRegressor()
内容:ランダムフォレストをインスタンス化する
得られた結果
RMSE: 33.9072792541881
r2_score:0.9669547184021459
結果からわかること
- 二乗平均平方根誤差の数値としては、これまで実装した中で最もよかった。
まとめ
モデルの作成のステップ以外は、どのアルゴリズムも手順は同じであることが分かった。いろんなアルゴリズムを実装して、精度を比較するのは骨が折れるなと思っていたが、これで簡単になった。
参考サイト
株で儲けたい-線形回帰以外でも時価総額を予測してみる | データ駆動はじめ