ぺーぱーの日々

上機嫌でいること、夢中でいることを目標に、今日も色んなことに手を出します。

MENU

株価予測をやってみた(ランダムフォレスト)

ランダムフォレストで、株価の予測を行ってみる。

実装したコード

# ライブラリのインポート
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()

# OpenCloseの差分を実体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

結果からわかること

  • 二乗平均平方根誤差の数値としては、これまで実装した中で最もよかった。

まとめ

モデルの作成のステップ以外は、どのアルゴリズムも手順は同じであることが分かった。いろんなアルゴリズムを実装して、精度を比較するのは骨が折れるなと思っていたが、これで簡単になった。

参考サイト

株で儲けたい-線形回帰以外でも時価総額を予測してみる | データ駆動はじめ