見出し画像

主成分分析を用いて日経平均株価を予測してみた


注意。

あくまでも、機械学習やディープラーニングでの結果となり、将来の株価を約束するものではありません。参考として活用できる可能性はありますが、活用に伴う損失については自己責任でお願いします。

今回のテーマは主成分分析

と、いうことで今回は日経平均、ドル円、ダウ、SP500,米国金利を用いて主成分分析を行い、その寄与率を元に翌5日間の日経平均の予測を立てたいと思います。まずはコードをchatGPTにいつも通り作成をお願いしました。

import numpy as np
import pandas as pd
import yfinance as yf
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler
import datetime

# シンボルリスト
symbols = ['USDJPY=X', '^N225', '^GSPC', '^DJI', '^TNX', '^FVX']

# 開始日と終了日
start = '2023-01-01'
end = datetime.datetime.now().strftime('%Y-%m-%d')

# データのダウンロード
data = yf.download(symbols, start=start, end=end)['Close']

# 欠損値の処理(前方埋め後に残るNaNを削除)
data = data.ffill().dropna()

# データのスケーリング
scaler = StandardScaler()
data_scaled = scaler.fit_transform(data)

# PCAの実行
pca = PCA(n_components=2)  # 例として、2つの主成分に次元を削減
principal_components = pca.fit_transform(data_scaled)

# 主成分のDataFrameを作成
principal_df = pd.DataFrame(data=principal_components, columns=['Principal Component 1', 'Principal Component 2'], index=data.index)

# 寄与率の表示
print(pca.explained_variance_ratio_)

結果は、[0.71223896 0.25504818]ということで、第一主成分が71%第二種成分が25.5%ということを表しています。ただし、何がどうなってこうなっているかは予測するしかないので、一旦ここは不明な状態で先に進めます。

機械学習を活用し、主成分分析で乖離値を計算

今回は、主成分分析で出た結果をもとに元の日経平均の価格と適正と思われる日経平均を算出し比べてみます。また、その乖離値を出しわかりやすくチャート形式でグラフにします。まずはコード。

from sklearn.linear_model import LinearRegression
import matplotlib.pyplot as plt

# 日経平均の終値を従属変数として取得
n225_prices = data['^N225']

# データの整形(PCAの主成分と日経平均価格のデータフレームをマージ)
model_data = principal_df.copy()
model_data['N225_Actual'] = n225_prices

# NaN値の削除
model_data.dropna(inplace=True)

# 線形回帰モデルの構築
X = model_data[['Principal Component 1', 'Principal Component 2']]
y = model_data['N225_Actual']
model = LinearRegression()
model.fit(X, y)

# 適正価格の予測
model_data['N225_Predicted'] = model.predict(X)

# 乖離の計算
model_data['Discrepancy'] = model_data['N225_Actual'] - model_data['N225_Predicted']

# チャートの可視化
plt.figure(figsize=(14, 7))
plt.plot(model_data['N225_Actual'], label='Actual N225 Price', color='blue')
plt.plot(model_data['N225_Predicted'], label='Predicted N225 Price', color='green')
plt.title('N225 Actual vs Predicted Price')
plt.legend()
plt.show()

plt.figure(figsize=(14, 7))
plt.plot(model_data['Discrepancy'], label='Discrepancy between Actual and Predicted Price', color='red')
plt.title('Discrepancy over Time')
plt.axhline(y=0, color='black', linestyle='--')
plt.legend()
plt.show()

続いて結果

割と乖離があるので、この想定価格を元に短期売買をするのは少し危険かもしれません。ただ、トレンドを押さえるヒントになるかもしれませんね。

ディープラーニングで予測をしていきます。

まずは、データを訓練させ学習させます。

import numpy as np
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, LSTM, Dropout
from sklearn.preprocessing import MinMaxScaler
from sklearn.model_selection import train_test_split

# 乖離データの準備
discrepancy_data = model_data['Discrepancy'].values.reshape(-1, 1)

# データのスケーリング
scaler = MinMaxScaler(feature_range=(0, 1))
scaled_data = scaler.fit_transform(discrepancy_data)

# 訓練データとテストデータの生成関数
def create_dataset(dataset, look_back=60):
    X, Y = [], []
    for i in range(len(dataset)-look_back-5):
        a = dataset[i:(i+look_back), 0]
        X.append(a)
        Y.append(dataset[i + look_back:i + look_back + 5, 0])
    return np.array(X), np.array(Y)

# データセットの生成
look_back = 60
X, y = create_dataset(scaled_data, look_back)

# 訓練データとテストデータに分割
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# データの形状を変更(LSTMに適した形へ)
X_train = np.reshape(X_train, (X_train.shape[0], X_train.shape[1], 1))
X_test = np.reshape(X_test, (X_test.shape[0], X_test.shape[1], 1))

# LSTMモデルの構築
model = Sequential()
model.add(LSTM(units=50, return_sequences=True, input_shape=(look_back, 1)))
model.add(Dropout(0.2))
model.add(LSTM(units=50))
model.add(Dropout(0.2))
model.add(Dense(5))  # 次の5日間の乖離を予測

# モデルのコンパイル
model.compile(optimizer='adam', loss='mean_squared_error')

# モデルの訓練
model.fit(X_train, y_train, epochs=100, batch_size=32)

# 予測
predicted_discrepancy = model.predict(X_test)
predicted_discrepancy = scaler.inverse_transform(predicted_discrepancy)

# 予測された乖離の最初のサンプルを抽出
predicted_sample = predicted_discrepancy[0]
actual_sample = scaler.inverse_transform(y_test[0].reshape(-1, 1))

# 日数を表す配列を作成
days = range(1, 6)

# 予測と実際の乖離をプロット
plt.figure(figsize=(10,6))
plt.plot(days, actual_sample, label="Actual Discrepancy", marker='o')
plt.plot(days, predicted_sample, label="Predicted Discrepancy", marker='x')
plt.title("Comparison of Actual and Predicted Discrepancy")
plt.xlabel("Day")
plt.ylabel("Discrepancy")
plt.legend()
plt.show()

学習させ、5日間の乖離値となります。この結果を元に予測金額を計算してもらいます。ちなみに本日4月8日の日経平均の終値は39347円でした。

# 最新の乖離データの準備(ここではダミーデータを例として使用)
# 実際には、最新の乖離データを使用してください
latest_discrepancy_data = scaled_data[-60:]  # 最新60日分のスケール済み乖離データ

# データの形状を調整
latest_discrepancy_data_reshaped = np.reshape(latest_discrepancy_data, (1, latest_discrepancy_data.shape[0], 1))

# 未来の乖離を予測
predicted_future_discrepancy = model.predict(latest_discrepancy_data_reshaped)
predicted_future_discrepancy = scaler.inverse_transform(predicted_future_discrepancy)

# 予測された乖離を現在の日経平均価格に適用して適正価格を計算
current_n225_price = 39347  # 本日の日経平均価格
predicted_prices = current_n225_price + predicted_future_discrepancy[0]

# 未来の適正価格を表示
for i, price in enumerate(predicted_prices, 1):
    print(f"Day {i}: Predicted N225 Price: {price}")

結果

1/1 [==============================] - 0s 22ms/step
Day 1: Predicted N225 Price: 39472.16796875
Day 2: Predicted N225 Price: 39446.14453125
Day 3: Predicted N225 Price: 39497.6328125
Day 4: Predicted N225 Price: 39425.484375
Day 5: Predicted N225 Price: 39396.63671875

と、いうことで明日4/9の日経平均は39472円で、以下続きます。
基本横ばいとなっていますが、同じように明日、明後日と同じように計算した時にどのように価格となるのか、またどのくらい価格が乖離するのか少しエクセルを用いて実践してまとめたいと思います。

この記事が気に入ったらサポートをしてみませんか?