SVMで翌日の株価の上昇/下降を予測します。
SVM
サポートベクターマシン(英: support vector machine, SVM)は、教師あり学習を用いるパターン認識モデルの一つである。分類や回帰へ適用できる。1963年に Vladimir N. Vapnik, Alexey Ya. Chervonenkis が線形サポートベクターマシンを発表し[1]、1992年に Bernhard E. Boser, Isabelle M. Guyon, Vladimir N. Vapnik が非線形へと拡張した。
出典: フリー百科事典『ウィキペディア(Wikipedia)』
クラス1とクラス-1に属する多数のデータがあり、それぞれデータをベクトルとして考えます。
このクラスを分類するための超平面を考えます。
結局クラス 1 に属するいくつかの点との距離の中の最小値とクラス -1 に属するいくつかの点との距離の中の最小値とが等しくなるように超平面が位置しなければならず、
このようにマージンが最大となるような超平面を特定するベクトル、つまり距離が最小値となるようなベクトルをサポートベクトルと呼び、この手法がサポートベクターマシーンと呼ばれる所以になります。
さらに、カーネル法と呼ばれる手法を使い非線形分類問題を線形分類問題に変換することで、SVMではそのままでは解くことができない非線形分類問題を解くことができます。
カーネル法(カーネルほう、英: kernel method)はパターン認識において使われる手法の一つで、 判別などのアルゴリズムに組み合わせて利用するものである。よく知られているのは、サポートベクターマシンと組み合わせて利用する方法である。
出典: フリー百科事典『ウィキペディア(Wikipedia)』
サポートベクターマシンとは[カーネル法による非線形サポートベクターマシン]
Python では、sklearn
のおかげで、SVMを簡単に扱うことができます。
import numpy as np import pandas as pd import datetime import numpy as np import pandas as pd import sklearn from sklearn.preprocessing import StandardScaler from sklearn.svm import SVC from sklearn.metrics import confusion_matrix from pandas_datareader import data as pdr import yfinance as yf import requests_cache # override pandas_datareader yf.pdr_override() # casche for downloaded data expire_after = datetime.timedelta(days=3) session = requests_cache.CachedSession(cache_name='cache', backend='sqlite', expire_after=expire_after) def calc_daily_pct_change(data): pct_change = data.pct_change() return pct_change def create_dataset(stock, start, ende, lags=40): df = pdr.get_data_yahoo(stock, start, end) df_lag = pd.DataFrame(index=df.index) df_lag['today'] = df['Adj Close'] df_lag['Volume'] = df['Volume'] for i in range(1, lags+1): df_lag[f'lag_close_{i}'] = df['Adj Close'].shift(i) df_lag[f'lag_vol_{i}'] = df['Volume'].shift(i) df_ret = pd.DataFrame(index=df_lag.index) df_ret['today'] = df_lag['today'].pct_change() for i in range(1, lags+1): df_ret[f'lag_close_{i}'] = df_lag[f'lag_close_{i}'].pct_change() df_ret[f'lag_vol_{i}'] = df_lag[f'lag_vol_{i}'].pct_change() df_ret.dropna(inplace=True) df_ret['up_or_down'] = np.sign(df_ret['today']) # drop rows where col 'up_or_down'==0 to redress the balance df_ret = df_ret[df_ret['up_or_down'] != 0] return df_ret if __name__ == '__main__': start = datetime.datetime(2000, 1, 1) end = datetime.datetime(2020, 1, 1) data = create_dataset('GE', start, end) # print(data.describe()) # print(data['up_or_down'].value_counts()) X = data.drop(['today', 'up_or_down'], axis=1) y = data['up_or_down'] start_test = datetime.datetime(2019, 1, 1) X_train = X[X.index < start_test] X_test = X[X.index >= start_test] y_train = y[y.index < start_test] y_test = y[y.index >= start_test] # standardize scaler = StandardScaler() X_train_scaled = scaler.fit_transform(X_train) X_test_scaled = scaler.transform(X_test) model = SVC( C=1000000.0, kernel='rbf', degree=3, gamma=0.0001, coef0=0.0, shrinking=True, probability=True, cache_size=200, class_weight=None, max_iter=-1, decision_function_shape='ovr', random_state=0 ) model.fit(X_train_scaled, y_train) pred = model.predict(X_test_scaled) pred_prob = model.predict_proba(X_test_scaled) # [-1. 1.] # print(model.classes_) # Accuracy 0.520 print(f'Accuracy {model.score(X_test_scaled, y_test):.3f}') # [[62 58] # [61 67]] print(confusion_matrix(pred, y_test)) # # 上手くいっていない
ロジスティック回帰やk近傍法よりも正答率が悪くなってしまいました。
ハイパーパラメータを調整することで多少は改善できるかもしれませんが、単純な日次データのみから機械学習で株価を予測するのは難しいと思われます。