なぜ今「LightGBM × LSTMアンサンブル」が話題なのか
2026年に入り、個人クオンツの間で勾配ブースティング(LightGBM)と時系列ディープラーニング(LSTM)を組み合わせたアンサンブルが再び注目を集めています。理由はシンプルで、単体モデルでは過学習しやすい金融時系列に対して、性質の異なる2つのモデルを平均することで予測の分散が小さくなり、ライブ運用での挙動が安定するからです。
LightGBMはテーブル特徴量(移動平均乖離率、ボラティリティ、出来高比など)を高速に処理でき、LSTMは終値のシーケンスから「流れ」を捉えるのが得意です。両者を別アングルとして組み合わせると、相関の低いシグナルが得られ、シャープレシオが改善するケースが多く報告されています。
理論:なぜアンサンブルで分散が下がるのか
2つのモデルの予測誤差がある程度独立であるとき、平均化された誤差の分散は単体より小さくなります。これは古典的なバイアス・バリアンス分解の結果ですが、金融データのようにSN比が低い領域では特に有効です。重要なのは「ただ強いモデルを2つ並べる」のではなく、表現の異なるモデルを組み合わせることです。テーブル特徴量を見るLightGBMと、シーケンスを見るLSTMは、まさに代表的な組み合わせと言えます。
Python実装:日経平均の翌日リターン方向予測
import numpy as np
import pandas as pd
import yfinance as yf
import lightgbm as lgb
from sklearn.preprocessing import StandardScaler
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import LSTM, Dense, Dropout
df = yf.download('^N225', start='2015-01-01', end='2026-05-01', auto_adjust=True)
df['ret'] = df['Close'].pct_change()
df['ma5'] = df['Close'].rolling(5).mean() / df['Close'] - 1
df['ma20'] = df['Close'].rolling(20).mean() / df['Close'] - 1
df['vol20'] = df['ret'].rolling(20).std()
df['target'] = (df['ret'].shift(-1) > 0).astype(int)
df = df.dropna()
feat_cols = ['ret','ma5','ma20','vol20']
X_tab, y = df[feat_cols].values, df['target'].values
split = int(len(df) * 0.8)
gbm = lgb.LGBMClassifier(n_estimators=400, learning_rate=0.03, max_depth=5)
gbm.fit(X_tab[:split], y[:split])
p_gbm = gbm.predict_proba(X_tab[split:])[:, 1]
SEQ = 20
scaler = StandardScaler().fit(df[['ret']].values[:split])
ret_s = scaler.transform(df[['ret']].values).flatten()
X_seq = np.array([ret_s[i-SEQ:i] for i in range(SEQ, len(ret_s))])
y_seq = y[SEQ:]
X_seq = X_seq.reshape(-1, SEQ, 1)
s2 = split - SEQ
model = Sequential([
LSTM(32, input_shape=(SEQ, 1)),
Dropout(0.3),
Dense(1, activation='sigmoid'),
])
model.compile(optimizer='adam', loss='binary_crossentropy')
model.fit(X_seq[:s2], y_seq[:s2], epochs=15, batch_size=64, verbose=0)
p_lstm = model.predict(X_seq[s2:]).flatten()
p_ens = 0.5 * p_gbm[-len(p_lstm):] + 0.5 * p_lstm
acc = ((p_ens > 0.5).astype(int) == y_seq[s2:]).mean()
print(f'アンサンブル正解率: {acc:.3f}')
コードのポイント
LightGBMには「移動平均乖離率」「20日ボラティリティ」などのテーブル特徴量を、LSTMには「リターンの直近20日シーケンス」を渡しています。重みは0.5/0.5の単純平均ですが、検証データで最適化するとさらに改善できます。必ずウォークフォワード検証を行い、未来情報のリークを避けてください。
まとめと次のステップ
アンサンブルは魔法ではありませんが、過学習のリスクを抑えながらシグナルの安定性を高める実務的な手法です。次に試すべきは、(1) 特徴量を増やす(VIX、為替、業種指数)、(2) アンサンブル重みをベイズ最適化で探索、(3) バックテストで売買コスト・スリッページを織り込む、の3点です。コードを手元で動かし、自分の戦略のベースラインに据えてみましょう。

