ロジスティック回帰で、翌日の株価の上昇/下降を予測します。
ロジスティック回帰
ロジスティック回帰(ロジスティックかいき、英: Logistic regression)は、ベルヌーイ分布に従う変数の統計的回帰モデルの一種である。
出典: フリー百科事典『ウィキペディア(Wikipedia)』
2つに分類する問題を解くときに使う回帰の手法で、確率が出力されます。
どういったものかは、以下が分かりやすいです。
Python では、sklearn を使うことで簡単にロジスティック回帰を行うことができます。
sklearn.linear_model.LogisticRegression
GEを対象に、過去40日間の前日比の株価と取引量の変化率を使い、当日の株価が上がるか下がるかを予測してみます。
2000年から2019年を学習データ、2019年から1年間をテストデータとして使います。
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.linear_model import LogisticRegression
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 = LogisticRegression(solver='lbfgs', multi_class='auto')
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.560
print(f'Accuracy {model.score(X_test_scaled, y_test):.3f}')
# [[80 66]
# [43 59]]
print(confusion_matrix(pred, y_test))
# 上手くいっていない
# 確率が0.6より大きい場合のみに限定して混同行列を見てみる。
df_test = pd.DataFrame(y_test)
df_test['prob_down'] = pred_prob.transpose()[0]
bound = 0.60
test_over_bound = df_test[(df_test['prob_down'] > bound) | (df_test['prob_down'] < (1-bound))].copy()
test_over_bound['pred'] = test_over_bound['prob_down'].map(lambda x: -1. if x>bound else 1.)
# confusion matrix when prob>0.6
# [[20 24]
# [11 14]]
print(f'confusion matrix when prob>{bound}')
print(confusion_matrix(test_over_bound['pred'], test_over_bound['up_or_down']))
# 計算するとこの場合で accuracy は 0.568
# 上手くいっていない。
上手くいきませんでした。