Pythonで株価予測する方法|機械学習モデルの作り方と精度評価を解説
Pythonで株価予測を試す手順を初心者向けに解説。データ取得、特徴量、時系列分割、ベースライン、RandomForest、LSTM、MAE・方向正解率、過学習とデータリーク対策まで紹介します。
Pythonを使えば、株価データから特徴量を作り、機械学習モデルに学習させ、翌日の値動きを予測する実験ができます。しかし、モデルを動かすだけなら簡単でも、「未来の情報を誤って学習に使わない」「単純な予測より本当に優れているか比較する」「取引コストを含めて考える」といった検証は簡単ではありません。
本記事では、翌営業日の終値そのものではなく「翌日の騰落率」を予測する回帰問題を例にします。データ取得、特徴量作成、時系列分割、ベースライン、RandomForest、LSTMの考え方、精度評価まで順番に解説します。
Pythonで株価予測を始める前に知っておきたいこと
株価は企業業績、金利、為替、政治、災害、投資家心理など多くの要因で動きます。過去の価格だけを学習しても、未知の出来事や市場構造の変化を正確に予測できるわけではありません。
予測対象を明確にする
「株価を予測する」だけでは、目的が曖昧です。次のどれを予測するか決めます。
- 翌日の終値
- 翌日の騰落率
- 翌日が上昇するか下落するか
- 5営業日後のリターン
- 一定期間のボラティリティ
予測対象によって、回帰か分類か、必要な特徴量、評価指標が変わります。本記事では、翌日の騰落率を予測する回帰モデルを作ります。
予測期間と売買期間を合わせる
翌日予測モデルを月1回しか実行しない設計では、目的と運用が一致しません。予測する時間軸、データの更新頻度、売買判断の頻度を揃えます。
高い正解率だけを目標にしない
上昇日が全体の55%なら、毎日「上昇」と答えるだけで正解率55%になります。モデルの数字を見る前に、単純な基準予測と比較してください。
株価予測に必要なPython環境
この記事では次のライブラリを使います。
- yfinance:学習用の株価データ取得
- pandas:表形式データの加工
- NumPy:数値計算
- scikit-learn:前処理、モデル、評価
- matplotlib:結果の可視化
- TensorFlow:LSTMを試す場合のみ
基本ライブラリをインストールする
python -m pip install yfinance pandas numpy scikit-learn matplotlibLSTMも試す場合はTensorFlowを追加します。
python -m pip install tensorflow環境によって対応するPythonバージョンや必要パッケージが異なります。エラーが出た場合は、TensorFlowの公式インストール手順を確認してください。
仮想環境を作る
プロジェクトごとにライブラリを分けると、バージョン競合を減らせます。
python -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install --upgrade pip株価データを取得する
例として、トヨタ自動車の調整済み日足を取得します。
import yfinance as yf
data = yf.download(
"7203.T",
start="2016-01-01",
end="2026-01-01",
interval="1d",
auto_adjust=True,
progress=False,
)
if data.empty:
raise RuntimeError("株価データを取得できませんでした")
print(data.head())
print(data.tail())
print(data.shape)学習期間が短いと、上昇相場や下落相場の一部しか含まれない可能性があります。一方、古すぎるデータを含めると、現在と市場構造が異なる場合があります。期間を変えて結果が安定するか確認しましょう。
列が階層構造になった場合
ライブラリのバージョンや取得方法によって、列がMultiIndexになる場合があります。
import pandas as pd
if isinstance(data.columns, pd.MultiIndex):
data.columns = data.columns.get_level_values(0)
print(data.columns)実際の列を確認し、Close、High、Low、Volumeが取得できているか確認します。
株価データの全体像を確認する
モデルを作る前に、欠損値、重複、データ型、外れ値を確認します。
print(data.info())
print(data.isna().sum())
print("重複:", data.index.duplicated().sum())
print(data.describe())日付順に並べる
data = data[~data.index.duplicated(keep="last")]
data = data.sort_index()時系列モデルでは順番が重要です。日付が降順のまま計算すると、過去と未来の関係を逆に扱う危険があります。
グラフで異常値を確認する
import matplotlib.pyplot as plt
data["Close"].plot(figsize=(12, 5), title="Close Price")
plt.grid(True)
plt.tight_layout()
plt.show()急激な価格変化があった場合は、実際の値動きか、株式分割・欠損・データ異常かを確認します。
目的変数を作る
翌日の騰落率を目的変数Targetにします。
data["Return_1d"] = data["Close"].pct_change()
data["Target"] = data["Return_1d"].shift(-1)shift(-1)によって、各行に翌日のリターンを対応させています。最後の行は翌日データがないため欠損します。
分類問題にする場合
上昇・下落を予測したい場合は、翌日の騰落率が0より大きいかでラベルを作れます。
data["Target_Up"] = (data["Target"] > 0).astype(int)ただし、0.01%の上昇と3%の上昇が同じ「上昇」になります。目的に応じて、手数料を超える上昇だけを1にするなどの設計が必要です。
株価予測の特徴量を作る
特徴量はモデルへ入力する情報です。最初は価格から計算できる単純な指標に絞ります。
data["Return_5d"] = data["Close"].pct_change(5)
data["MA5"] = data["Close"].rolling(5).mean()
data["MA25"] = data["Close"].rolling(25).mean()
data["MA75"] = data["Close"].rolling(75).mean()
data["MA5_Gap"] = data["Close"] / data["MA5"] - 1
data["MA25_Gap"] = data["Close"] / data["MA25"] - 1
data["Volatility_20d"] = data["Return_1d"].rolling(20).std()
data["Volume_Change"] = data["Volume"].pct_change()過去の情報だけで計算する
特徴量に翌日の終値、未来の高値、全期間の平均などが混ざるとデータリークになります。予測時点で入手できる情報だけを使ってください。
特徴量を増やしすぎない
特徴量が多いほど優れたモデルになるとは限りません。似た移動平均を大量に追加すると、過学習や解釈の難しさにつながります。まず少数でベースラインを作り、追加効果を検証します。
外部データを使う場合
為替、指数、金利、決算などを追加できますが、公開時刻に注意します。決算数値を発表前の日付へ紐付けると、未来情報を使った不正な検証になります。
欠損値と無限値を処理する
移動平均の先頭や目的変数の末尾には欠損値が生じます。
import numpy as np
feature_columns = [
"Return_1d",
"Return_5d",
"MA5_Gap",
"MA25_Gap",
"Volatility_20d",
"Volume_Change",
]
dataset = data[feature_columns + ["Target"]].replace(
[np.inf, -np.inf],
np.nan,
)
dataset = dataset.dropna()
X = dataset[feature_columns]
y = dataset["Target"]欠損値を安易に0で埋めると、「データなし」を「変化なし」と解釈してしまいます。欠損理由を確認して処理方法を決めます。
学習データと検証データを時系列で分割する
通常のランダム分割は、未来のデータを学習し、過去を評価する状態を作る可能性があります。時系列では古い期間を学習、後の期間を検証に使います。
split_index = int(len(dataset) * 0.8)
X_train = X.iloc[:split_index]
X_test = X.iloc[split_index:]
y_train = y.iloc[:split_index]
y_test = y.iloc[split_index:]
print(X_train.index.min(), X_train.index.max())
print(X_test.index.min(), X_test.index.max())scikit-learnのTimeSeriesSplitは、時間順序を保った交差検証に利用できます。通常の交差検証では学習に未来データが入り得るため、時系列専用の分割を使います。
TimeSeriesSplitの例
from sklearn.model_selection import TimeSeriesSplit
tscv = TimeSeriesSplit(n_splits=5)
for fold, (train_idx, test_idx) in enumerate(tscv.split(X), start=1):
print(
fold,
X.index[train_idx[0]],
X.index[train_idx[-1]],
X.index[test_idx[0]],
X.index[test_idx[-1]],
)ベースライン予測を作る
複雑なモデルを評価する前に、単純な予測を用意します。翌日のリターンを常に0と予測する例です。
import numpy as np
from sklearn.metrics import mean_absolute_error
baseline_pred = np.zeros(len(y_test))
baseline_mae = mean_absolute_error(y_test, baseline_pred)
print("Baseline MAE:", baseline_mae)機械学習モデルのMAEがベースラインより悪ければ、複雑にした意味がありません。
前日と同じ方向を予測する基準
方向予測では、前日の方向が続くと仮定する方法や、常に多数派を答える方法も比較対象になります。
RandomForestで株価予測モデルを作る
まずはニューラルネットワークより扱いやすいRandomForestRegressorを試します。
from sklearn.ensemble import RandomForestRegressor
model = RandomForestRegressor(
n_estimators=300,
max_depth=5,
min_samples_leaf=10,
random_state=42,
n_jobs=-1,
)
model.fit(X_train, y_train)
pred = model.predict(X_test)random_stateを固定すると再現しやすくなります。木を深くしすぎると学習データへ過剰適合するため、検証期間の成績を見ながら調整します。
予測値と実測値を並べる
import pandas as pd
result = pd.DataFrame(
{
"Actual": y_test,
"Predicted": pred,
},
index=y_test.index,
)
print(result.tail())株価予測の精度を評価する
評価指標は1つだけでなく、誤差と方向の両面を確認します。
MAEを計算する
MAEは予測誤差の絶対値平均です。
from sklearn.metrics import mean_absolute_error
mae = mean_absolute_error(y_test, pred)
print("Model MAE:", mae)
print("Baseline MAE:", baseline_mae)値が小さいほど、平均的な誤差が小さいことを示します。ただし、利益が出ることを直接示す指標ではありません。
RMSEを計算する
大きな誤差をより強く評価したい場合はRMSEを使います。
from sklearn.metrics import mean_squared_error
rmse = mean_squared_error(y_test, pred) ** 0.5
print("RMSE:", rmse)方向正解率を計算する
direction_accuracy = ((pred > 0) == (y_test.to_numpy() > 0)).mean()
print("Direction Accuracy:", direction_accuracy)方向正解率が高くても、小さな上昇だけ当てて大きな下落を外す場合があります。MAE、RMSE、損益シミュレーションを合わせて確認します。
期間別に評価する
全期間の平均だけでなく、年別、上昇相場、下落相場、高ボラティリティ期間で成績を確認します。特定期間だけ良いモデルは、環境が変わると機能しない可能性があります。
予測結果をグラフで確認する
import matplotlib.pyplot as plt
result.plot(
figsize=(12, 6),
title="Actual vs Predicted Return",
)
plt.axhline(0, color="black", linewidth=1)
plt.grid(True)
plt.tight_layout()
plt.show()予測値が常に0付近へ集中していないか、急落時に大きく外していないかを見ます。散布図や残差も確認すると、モデルの偏りを発見しやすくなります。
特徴量の重要度を確認する
importance = pd.Series(
model.feature_importances_,
index=feature_columns,
).sort_values(ascending=False)
print(importance)重要度が高いことは因果関係を意味しません。似た特徴量があると重要度が分散することもあります。将来も同じ関係が続くとは限りません。
LSTMで株価予測する考え方
LSTMはRNNの一種で、時系列の連続したパターンを扱うニューラルネットワークです。TensorFlow公式の時系列チュートリアルでも、tf.keras.layers.LSTMを使った例が紹介されています。
LSTMへ渡すデータ形状
一般的にLSTMは、サンプル数 × 時間ステップ × 特徴量数の3次元データを受け取ります。過去20日から翌日を予測するなら、20日分を1つの窓として切り出します。
import numpy as np
def make_sequences(X_values, y_values, window=20):
X_seq = []
y_seq = []
for i in range(window, len(X_values)):
X_seq.append(X_values[i - window:i])
y_seq.append(y_values[i])
return np.array(X_seq), np.array(y_seq)標準化は学習期間だけで行う
全期間で標準化してから分割すると、検証期間の統計量が学習へ漏れます。
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)時系列窓へ変換する前後のどちらで処理するかを決め、検証期間ではfitせずtransformだけを使います。
シンプルなLSTMモデル
import tensorflow as tf
lstm_model = tf.keras.Sequential(
[
tf.keras.layers.Input(shape=(20, len(feature_columns))),
tf.keras.layers.LSTM(32),
tf.keras.layers.Dropout(0.2),
tf.keras.layers.Dense(1),
]
)
lstm_model.compile(
optimizer="adam",
loss="mae",
)このコードだけで高精度になるわけではありません。窓幅、特徴量、学習率、エポック数、モデル容量を調整し、必ず時系列の検証期間で比較します。
EarlyStoppingを使う
early_stopping = tf.keras.callbacks.EarlyStopping(
monitor="val_loss",
patience=10,
restore_best_weights=True,
)検証損失が改善しなくなったら学習を止め、過学習を抑えます。ただし、検証データを何度も見て調整すると、その期間へ過剰適合するため、最後のテスト期間を別に残す方法が安全です。
RandomForestとLSTMはどちらを選ぶべきか
| 比較項目 | RandomForest | LSTM |
|---|---|---|
| 実装難易度 | 比較的低い | 高い |
| 計算量 | 比較的小さい | 大きい |
| 標準化 | 必須ではない場合が多い | 通常必要 |
| 時系列窓 | 不要 | 通常必要 |
| 解釈 | 特徴量重要度を確認可能 | 難しい |
| 少量データ | 試しやすい | 過学習しやすい |
初心者は、ベースライン、線形モデル、RandomForestを試してからLSTMへ進むと、複雑化による改善を判断できます。
ウォークフォワード検証を行う
1回だけ学習・検証を分けると、分割日によって結果が変わります。ウォークフォワード検証では、時間の進行に合わせて学習期間を伸ばし、次の期間を繰り返し評価します。
学習1 → 検証1
学習1+検証1 → 検証2
学習1+検証1+検証2 → 検証3実運用に近い検証ですが、モデルの再学習回数が増えるため計算時間も増えます。ハイパーパラメータを検証期間へ合わせすぎないよう、調整用期間と最終テスト期間を分けます。
売買シミュレーションで確認する項目
予測精度が高くても、売買コストを含めると利益が残らない場合があります。
- 売買手数料
- スプレッド
- スリッページ
- 税金
- 約定できる時刻
- 売買単位
- 配当・分割
- 取引停止やストップ高・ストップ安
「当日の終値を見て、その終値で売買する」バックテストは実行不能な場合があります。予測を計算できる時刻と、実際に注文できる時刻を揃えてください。
株価予測で起きやすい失敗
ランダム分割を使う
未来データが学習に入り、実際より高い精度が出る可能性があります。時系列順で分割します。
全期間で標準化する
検証期間の平均や標準偏差が学習へ漏れます。学習期間でfitし、検証期間はtransformだけを使います。
同じ検証期間で何度も調整する
検証期間へ過学習します。調整用と最終評価用を分けます。
ベースラインと比較しない
複雑なモデルが「常に0」と答える予測より悪い場合があります。必ず単純モデルを用意します。
価格だけで将来が決まると考える
市場環境や企業情報の変化を価格系列だけで完全に捉えることはできません。予測の不確実性を前提にします。
1銘柄・1期間だけで判断する
異なる銘柄や期間で再現するか確認します。ただし、対象を増やすだけでデータ品質が上がるわけではありません。
株価予測モデルを自動実行する場合
毎日予測する場合は、データ取得、前処理、予測、保存、監視を一連の処理にします。
モデルと前処理をセットで保存する
学習時と予測時で特徴量の順番や標準化方法が変わると、正しい予測ができません。モデルだけでなく、特徴量一覧、スケーラー、学習期間、ライブラリバージョンも保存します。
入力データを検査する
最新日、行数、欠損値、異常値を確認し、条件を満たさなければ予測を停止します。古い株価を新しいデータとして扱わないようにします。
予測履歴を残す
予測日時、対象日、予測値、モデルバージョン、後日の実測値を保存します。実運用後の精度低下を検知するために必要です。
VPSを利用する場合
ローカルPCの電源に依存せず定期実行できますが、APIキー、SSH鍵、OS更新、ログ、バックアップの管理が必要です。初めての場合はVPSとは何かを確認してください。
株価予測の精度を改善する手順
- 目的変数と予測時点を明確にする
- 単純なベースラインを作る
- 時系列分割を行う
- 少数の特徴量でモデルを作る
- MAE・RMSE・方向正解率を確認する
- ウォークフォワード検証を行う
- 取引コストを含める
- 異なる期間で再現性を確認する
- 改善しなければ複雑化しない
LSTMやディープラーニングを使うこと自体を目的にせず、ベースラインからどれだけ改善したかを判断します。
よくある質問
Pythonで株価を正確に予測できますか?
将来の価格を常に正確に当てることはできません。過去データで一定の関係を学習できても、市場環境が変わると成績が低下します。
株価予測にはLSTMが最適ですか?
常に最適とは限りません。データ量や特徴量によっては、線形モデルや木系モデルが同等以上になる場合があります。複数モデルを同じ条件で比較してください。
予測精度は何%あればよいですか?
一律の基準はありません。クラス比率、予測期間、手数料、利益と損失の大きさで意味が変わります。方向正解率だけでなく、誤差と損益も確認します。
株価予測に必要なデータ期間は?
モデルと時間軸によります。長ければ必ず良いわけではありません。複数の相場局面を含み、検証用期間を確保できる長さが必要です。
株価予測コードを自動売買へ使えますか?
学習用コードをそのまま実運用へ使うのは危険です。データ配信契約、注文API、認証、障害対応、リスク上限、監視、法令・規約を別途確認する必要があります。
まとめ
Pythonによる株価予測では、モデル選びより先に、目的変数、特徴量の時点、時系列分割、ベースライン、評価方法を正しく設計することが重要です。
最初は翌日の騰落率を対象に、単純な特徴量とRandomForestで検証してください。その後、十分なデータと検証設計を用意できた段階でLSTMを比較します。精度が高く見えても、データリーク、過学習、取引コストを確認するまでは投資成果を示すものではありません。
株価取得と前処理が初めての方は、Pythonで株価分析する方法とPythonで株価を取得するAPI比較から進めると理解しやすくなります。