Numpyだけで重回帰分析 機械学習 株価予測
scikit-learnを使えば簡単ですが最初はどのようになっているか、Numpyだけで重回帰分析も勉強になります。
説明変数は過去n日の対数リターンを使います。
データの読み込み
import numpy as np import pandas as pd from sklearn.model_selection import train_test_split import yfinance as yf code = '2432.T' df = yf.download(code, start="2010-12-20", end="2023-02-03")
Date | Open | High | Low | Close | Adj Close | Volume |
---|---|---|---|---|---|---|
2023-01-27 00:00:00+09:00 | 1808.0 | 1813.0 | 1794.0 | 1796.0 | 1796.0 | 302400 |
2023-01-30 00:00:00+09:00 | 1793.0 | 1806.0 | 1791.0 | 1799.0 | 1799.0 | 341400 |
2023-01-31 00:00:00+09:00 | 1797.0 | 1821.0 | 1797.0 | 1818.0 | 1818.0 | 410100 |
2023-02-01 00:00:00+09:00 | 1819.0 | 1827.0 | 1801.0 | 1802.0 | 1802.0 | 367000 |
2023-02-02 00:00:00+09:00 | 1797.0 | 1803.0 | 1786.0 | 1789.0 | 1789.0 | 363500 |
ベースラインの作成、学習
def prepare_lags(_data): '''ラグ計算''' #入力として使用する日数(ラグというらしい) lags = 5 cols = [] for lag in range(1, lags + 1): col = f'lag_{lag}' _data[col] = _data['returns'].shift(lag) cols.append(col) _data.dropna(inplace=True) return _data, cols def fit(_data): '''Numpyのlinalg.lstsqで重回帰分析''' return np.linalg.lstsq(_data[cols], _data['returns'], rcond=None)[0] #対数リターン df['returns'] = np.log(df['Adj Close'] / df['Adj Close'].shift(1)) #欠損値の行を削除 df.dropna(inplace=True) # 学習、検証分割 train, test = train_test_split(df, train_size=0.7, shuffle=False) data, cols = prepare_lags(train) #係数生成 reg = fit(data) print(reg)
array([ 0.06145026, -0.02996533, 0.00528902, 0.00780436, 0.01727923])
予測
np.dot: 内積
np.sign: 引数にnumpy.ndarrayを指定する。負の値は-1、正の値は1、0は0となるnumpy.ndarrayが返される。
# 予測 data['prediction'] = np.dot(data[cols], reg) data['prediction_sign'] = np.sign(data['prediction'])
対数リターンと予測値を表示、線形回帰では予測値と大きくズレている
方向性が重要
data[['returns', 'prediction']].iloc[lags:].plot(figsize=(15, 6))
正解率
hits = np.sign(data['returns'] * data['prediction']).value_counts() hits.values[0] / sum(hits)
0.5067178502879078
バックテスト
#予測ポジションとリターンをかけて収益率を計算 data['strategy'] = data['prediction_sign'] * data['returns'] # 株価と戦略のグロスパフォーマンスをプロット data[['returns', 'strategy']].cumsum().apply(np.exp).plot(figsize=(10, 6)) # 株価と戦略のグロスパフォーマンスを算出 data[['returns', 'strategy']].sum().apply(np.exp)
returns 0.845186 strategy 2.931524 dtype: float64
テストデータで検証
data, cols = prepare_lags(test) data['prediction'] = np.dot(data[cols], reg) data['prediction_sign'] = np.sign(data['prediction']) hits = np.sign(data['returns'] * data['prediction']).value_counts() print('ヒット率: ', hits.values[0] / sum(hits)) data['strategy'] = data['prediction_sign'] * data['returns'] data[['returns', 'strategy']].cumsum().apply(np.exp).plot(figsize=(10, 6)) data[['returns', 'strategy']].sum().apply(np.exp)
ヒット率: 0.5092378752886836 returns 0.850081 strategy 2.575374 dtype: float64
まとめ
かなり勉強になるのでおすすめです。