重線形回帰を用いた翌日の株価予測

2021年10月26日

2022年10月21日の様々な指標を入力にして重線形回帰を用いて翌日の株価を予測してみた。ちなみに、結果が何かに利用できるものではないと思われる。なぜなら当日の株価と翌日の株価はそんなに変わらないのに対して、時価総額とかEPSには株価の要素が間接的に含まれているので、このままでは何も使えないだろうなというのが結論です。

ライブラリのインポート

In [1]:
import numpy as np
import pandas as pd
import statsmodels.api as sm
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
import seaborn as sns
import japanize_matplotlib
sns.set(font='Hiragino Sans')

データの読み込み

In [2]:
raw_data = pd.read_csv('technical_stock_20221021.csv')
#主市場や指数採用銘柄は関係なさそうなので除外
raw_data = raw_data.drop(['主市場','指数採用銘柄'],axis=1)
raw_data.head()
Out[2]:
証券コード 時価総額 売買単位 業種 信用残-買 信用残-売 前週比-買 前週比-売 PER PER変化率-1年前 … RCI-売 MACD-日足-買 MACD-日足-売 MACD-週足-買 MACD-週足-売 ノーマルストキャスティクス-買 ノーマルストキャスティクス-売 スローストキャスティクス-買 スローストキャスティクス-売 翌日株価
0 2637 0 1 その他 11914.0 0.0 -1515.0 -9.0 NaN NaN … False False False False False False False False True 1776
1 2638 0 1 その他 209.0 0.0 -283.0 0.0 NaN NaN … False False False False False False False False False 2299
2 2639 0 1 その他 10215.0 0.0 0.0 0.0 NaN NaN … False False False False False False False False False 1867
3 2640 0 1 その他 1225.0 32.0 -96.0 22.0 NaN NaN … False False False False False False False False True 2593
4 2641 0 1 その他 844.0 0.0 126.0 0.0 NaN NaN … False False False False False False False False False 2054

5 rows × 92 columns

前処理

変数の記述統計量の確認

In [3]:
raw_data.describe(include='all')
Out[3]:
証券コード 時価総額 売買単位 業種 信用残-買 信用残-売 前週比-買 前週比-売 PER PER変化率-1年前 … RCI-売 MACD-日足-買 MACD-日足-売 MACD-週足-買 MACD-週足-売 ノーマルストキャスティクス-買 ノーマルストキャスティクス-売 スローストキャスティクス-買 スローストキャスティクス-売 翌日株価
count 4018.000000 4.018000e+03 4018.000000 4018 4.018000e+03 4.018000e+03 4.018000e+03 4.018000e+03 3006.000000 2940.000000 … 4018 4018 4018 4018 4018 4018 4018 4018 4018 4018.000000
unique NaN NaN NaN 34 NaN NaN NaN NaN NaN NaN … 2 2 2 2 2 2 2 2 2 NaN
top NaN NaN NaN 通信業 NaN NaN NaN NaN NaN NaN … False False False False False False False False False NaN
freq NaN NaN NaN 521 NaN NaN NaN NaN NaN NaN … 3630 3926 3819 3909 3756 3089 3604 3365 3362 NaN
mean 5537.419861 1.952574e+11 92.910652 NaN 5.737528e+05 1.077455e+05 3.844164e+03 2.718718e+03 41.688194 2.438476 … NaN NaN NaN NaN NaN NaN NaN NaN NaN 6471.327775
std 2469.057889 9.486625e+11 29.319665 NaN 2.364949e+06 6.421045e+05 2.200048e+05 3.802257e+05 144.078901 27.183514 … NaN NaN NaN NaN NaN NaN NaN NaN NaN 38918.099391
min 1301.000000 0.000000e+00 1.000000 NaN 0.000000e+00 0.000000e+00 -3.780800e+06 -1.921990e+07 1.080000 -82.120000 … NaN NaN NaN NaN NaN NaN NaN NaN NaN 0.000000
25% 3434.250000 5.548750e+09 100.000000 NaN 2.890000e+04 0.000000e+00 -4.100000e+03 -7.000000e+02 10.730000 -10.792500 … NaN NaN NaN NaN NaN NaN NaN NaN NaN 738.500000
50% 5698.500000 1.753400e+10 100.000000 NaN 1.170000e+05 2.900000e+03 0.000000e+00 0.000000e+00 16.870000 -1.650000 … NaN NaN NaN NaN NaN NaN NaN NaN NaN 1405.000000
75% 7604.750000 6.925475e+10 100.000000 NaN 3.698500e+05 5.092500e+04 3.900000e+03 1.000000e+02 30.572500 9.587500 … NaN NaN NaN NaN NaN NaN NaN NaN NaN 2620.750000
max 9997.000000 3.236078e+13 1000.000000 NaN 7.414765e+07 2.398530e+07 7.696600e+06 1.142390e+07 3154.550000 316.670000 … NaN NaN NaN NaN NaN NaN NaN NaN NaN 740000.000000

11 rows × 92 columns

欠損値の扱い

In [4]:
raw_data.isnull().sum().sort_values(ascending=False)
Out[4]:
PER変化率-5年前    1527
PER変化率-3年前    1404
配当利回-5年前      1112
PER変化率-1年前    1078
配当利回-1年前      1068
              ... 
信用残-売            0
信用残-買            0
業種               0
売買単位             0
翌日株価             0
Length: 92, dtype: int64

5年前には上場してなかった等の理由でNaNのデータが数多くあるが、結果的に1000件もあると思われるので、NaNが含まれる銘柄は全て削除

In [5]:
data = raw_data.dropna(axis=0)
In [6]:
data.describe(include='all')
Out[6]:
証券コード 時価総額 売買単位 業種 信用残-買 信用残-売 前週比-買 前週比-売 PER PER変化率-1年前 … RCI-売 MACD-日足-買 MACD-日足-売 MACD-週足-買 MACD-週足-売 ノーマルストキャスティクス-買 ノーマルストキャスティクス-売 スローストキャスティクス-買 スローストキャスティクス-売 翌日株価
count 1523.000000 1.523000e+03 1523.0 1523 1.523000e+03 1.523000e+03 1.523000e+03 1.523000e+03 1523.000000 1523.000000 … 1523 1523 1523 1523 1523 1523 1523 1523 1523 1523.000000
unique NaN NaN NaN 31 NaN NaN NaN NaN NaN NaN … 2 2 2 2 2 2 2 2 2 NaN
top NaN NaN NaN 卸売業 NaN NaN NaN NaN NaN NaN … False False False False False False False False False NaN
freq NaN NaN NaN 169 NaN NaN NaN NaN NaN NaN … 1383 1484 1451 1483 1417 1251 1383 1367 1281 NaN
mean 5657.988181 1.629514e+11 100.0 NaN 2.561689e+05 5.850401e+04 3.235916e+03 -8.540775e+03 24.345069 4.008109 … NaN NaN NaN NaN NaN NaN NaN NaN NaN 2476.342088
std 2432.407552 6.641912e+11 0.0 NaN 5.774443e+05 2.730431e+05 7.093146e+04 5.002839e+05 36.290122 23.445367 … NaN NaN NaN NaN NaN NaN NaN NaN NaN 4136.072478
min 1301.000000 1.272000e+09 100.0 NaN 0.000000e+00 0.000000e+00 -9.422000e+05 -1.921990e+07 1.390000 -55.110000 … NaN NaN NaN NaN NaN NaN NaN NaN NaN 0.000000
25% 3539.500000 1.216750e+10 100.0 NaN 2.800000e+04 2.000000e+02 -2.850000e+03 -9.500000e+02 10.565000 -8.730000 … NaN NaN NaN NaN NaN NaN NaN NaN NaN 932.000000
50% 5903.000000 3.139600e+10 100.0 NaN 9.020000e+04 6.300000e+03 1.000000e+02 0.000000e+00 15.160000 -0.700000 … NaN NaN NaN NaN NaN NaN NaN NaN NaN 1633.000000
75% 7714.000000 9.715450e+10 100.0 NaN 2.461000e+05 4.740000e+04 3.600000e+03 2.500000e+02 25.505000 10.090000 … NaN NaN NaN NaN NaN NaN NaN NaN NaN 2709.500000
max 9997.000000 1.635572e+13 100.0 NaN 8.833600e+06 6.529200e+06 1.738600e+06 2.960900e+06 780.520000 187.860000 … NaN NaN NaN NaN NaN NaN NaN NaN NaN 67740.000000

11 rows × 92 columns

確率密度関数

In [7]:
sns.distplot(data['翌日株価'])
Out[7]:
<AxesSubplot:xlabel='翌日株価', ylabel='Density'>

指数関数っぽい分布になっており、数多くの外れ値が含まれるため、上位の1%を除外する。

外れ値の処理

In [8]:
q = data['翌日株価'].quantile(0.99)
data_1 = data[data['翌日株価']<q]
data_1.describe(include='all')
Out[8]:
証券コード 時価総額 売買単位 業種 信用残-買 信用残-売 前週比-買 前週比-売 PER PER変化率-1年前 … RCI-売 MACD-日足-買 MACD-日足-売 MACD-週足-買 MACD-週足-売 ノーマルストキャスティクス-買 ノーマルストキャスティクス-売 スローストキャスティクス-買 スローストキャスティクス-売 翌日株価
count 1507.000000 1.507000e+03 1507.0 1507 1.507000e+03 1.507000e+03 1.507000e+03 1.507000e+03 1507.000000 1507.000000 … 1507 1507 1507 1507 1507 1507 1507 1507 1507 1507.000000
unique NaN NaN NaN 31 NaN NaN NaN NaN NaN NaN … 2 2 2 2 2 2 2 2 2 NaN
top NaN NaN NaN 卸売業 NaN NaN NaN NaN NaN NaN … False False False False False False False False False NaN
freq NaN NaN NaN 169 NaN NaN NaN NaN NaN NaN … 1369 1468 1435 1467 1402 1236 1370 1351 1271 NaN
mean 5650.969476 1.207076e+11 100.0 NaN 2.545132e+05 5.805627e+04 3.442734e+03 -8.669210e+03 24.105660 3.872143 … NaN NaN NaN NaN NaN NaN NaN NaN NaN 2136.177173
std 2439.078700 3.025534e+11 0.0 NaN 5.780153e+05 2.739997e+05 7.108248e+04 5.029167e+05 36.304264 23.297671 … NaN NaN NaN NaN NaN NaN NaN NaN NaN 1878.356657
min 1301.000000 1.272000e+09 100.0 NaN 0.000000e+00 0.000000e+00 -9.422000e+05 -1.921990e+07 1.390000 -55.110000 … NaN NaN NaN NaN NaN NaN NaN NaN NaN 0.000000
25% 3530.500000 1.198650e+10 100.0 NaN 2.785000e+04 2.000000e+02 -2.700000e+03 -9.000000e+02 10.560000 -8.770000 … NaN NaN NaN NaN NaN NaN NaN NaN NaN 928.500000
50% 5819.000000 3.076300e+10 100.0 NaN 9.020000e+04 6.000000e+03 1.000000e+02 0.000000e+00 15.040000 -0.760000 … NaN NaN NaN NaN NaN NaN NaN NaN NaN 1616.000000
75% 7715.500000 9.386900e+10 100.0 NaN 2.398500e+05 4.650000e+04 3.600000e+03 2.000000e+02 24.955000 9.895000 … NaN NaN NaN NaN NaN NaN NaN NaN NaN 2650.500000
max 9997.000000 5.169911e+12 100.0 NaN 8.833600e+06 6.529200e+06 1.738600e+06 2.960900e+06 780.520000 187.860000 … NaN NaN NaN NaN NaN NaN NaN NaN NaN 15680.000000

11 rows × 92 columns

In [9]:
sns.distplot(data_1['翌日株価'])
Out[9]:
<AxesSubplot:xlabel='翌日株価', ylabel='Density'>
In [10]:
sns.distplot(data_1['EPS'])
Out[10]:
<AxesSubplot:xlabel='EPS', ylabel='Density'>
In [11]:
q = data_1['EPS'].quantile(0.99)
data_2 = data_1[data_1['EPS']<q]
In [12]:
sns.distplot(data_2['EPS'])
Out[12]:
<AxesSubplot:xlabel='EPS', ylabel='Density'>
In [13]:
sns.distplot(data_2['時価総額'])
Out[13]:
<AxesSubplot:xlabel='時価総額', ylabel='Density'>
In [14]:
q = data_2['時価総額'].quantile(0.99)
data_3 = data_2[data_2['時価総額']<q]
data_3.describe(include='all')
Out[14]:
証券コード 時価総額 売買単位 業種 信用残-買 信用残-売 前週比-買 前週比-売 PER PER変化率-1年前 … RCI-売 MACD-日足-買 MACD-日足-売 MACD-週足-買 MACD-週足-売 ノーマルストキャスティクス-買 ノーマルストキャスティクス-売 スローストキャスティクス-買 スローストキャスティクス-売 翌日株価
count 1476.000000 1.476000e+03 1476.0 1476 1.476000e+03 1.476000e+03 1.476000e+03 1.476000e+03 1476.000000 1476.000000 … 1476 1476 1476 1476 1476 1476 1476 1476 1476 1476.000000
unique NaN NaN NaN 31 NaN NaN NaN NaN NaN NaN … 2 2 2 2 2 2 2 2 2 NaN
top NaN NaN NaN 卸売業 NaN NaN NaN NaN NaN NaN … False False False False False False False False False NaN
freq NaN NaN NaN 166 NaN NaN NaN NaN NaN NaN … 1343 1437 1407 1437 1374 1208 1341 1321 1247 NaN
mean 5636.272358 9.834614e+10 100.0 NaN 2.512797e+05 5.711734e+04 4.074187e+03 -8.714973e+03 24.253977 3.734492 … NaN NaN NaN NaN NaN NaN NaN NaN NaN 2063.066396
std 2429.833375 1.839100e+11 0.0 NaN 5.709989e+05 2.761975e+05 7.114622e+04 5.081625e+05 36.598359 23.125441 … NaN NaN NaN NaN NaN NaN NaN NaN NaN 1766.278368
min 1301.000000 1.272000e+09 100.0 NaN 0.000000e+00 0.000000e+00 -9.422000e+05 -1.921990e+07 2.950000 -55.110000 … NaN NaN NaN NaN NaN NaN NaN NaN NaN 0.000000
25% 3537.750000 1.178050e+10 100.0 NaN 2.745000e+04 2.000000e+02 -2.625000e+03 -9.000000e+02 10.567500 -8.792500 … NaN NaN NaN NaN NaN NaN NaN NaN NaN 920.750000
50% 5733.000000 2.997500e+10 100.0 NaN 8.880000e+04 5.800000e+03 1.000000e+02 0.000000e+00 15.095000 -0.795000 … NaN NaN NaN NaN NaN NaN NaN NaN NaN 1594.500000
75% 7643.750000 8.858500e+10 100.0 NaN 2.366500e+05 4.462500e+04 3.700000e+03 2.000000e+02 25.055000 9.880000 … NaN NaN NaN NaN NaN NaN NaN NaN NaN 2596.250000
max 9997.000000 1.306616e+12 100.0 NaN 8.833600e+06 6.529200e+06 1.738600e+06 2.960900e+06 780.520000 187.860000 … NaN NaN NaN NaN NaN NaN NaN NaN NaN 15680.000000

11 rows × 92 columns

In [15]:
sns.distplot(data_3['時価総額'])
Out[15]:
<AxesSubplot:xlabel='時価総額', ylabel='Density'>
In [16]:
data_cleaned = data_3.reset_index(drop=True)
In [17]:
data_cleaned.describe(include='all')
Out[17]:
証券コード 時価総額 売買単位 業種 信用残-買 信用残-売 前週比-買 前週比-売 PER PER変化率-1年前 … RCI-売 MACD-日足-買 MACD-日足-売 MACD-週足-買 MACD-週足-売 ノーマルストキャスティクス-買 ノーマルストキャスティクス-売 スローストキャスティクス-買 スローストキャスティクス-売 翌日株価
count 1476.000000 1.476000e+03 1476.0 1476 1.476000e+03 1.476000e+03 1.476000e+03 1.476000e+03 1476.000000 1476.000000 … 1476 1476 1476 1476 1476 1476 1476 1476 1476 1476.000000
unique NaN NaN NaN 31 NaN NaN NaN NaN NaN NaN … 2 2 2 2 2 2 2 2 2 NaN
top NaN NaN NaN 卸売業 NaN NaN NaN NaN NaN NaN … False False False False False False False False False NaN
freq NaN NaN NaN 166 NaN NaN NaN NaN NaN NaN … 1343 1437 1407 1437 1374 1208 1341 1321 1247 NaN
mean 5636.272358 9.834614e+10 100.0 NaN 2.512797e+05 5.711734e+04 4.074187e+03 -8.714973e+03 24.253977 3.734492 … NaN NaN NaN NaN NaN NaN NaN NaN NaN 2063.066396
std 2429.833375 1.839100e+11 0.0 NaN 5.709989e+05 2.761975e+05 7.114622e+04 5.081625e+05 36.598359 23.125441 … NaN NaN NaN NaN NaN NaN NaN NaN NaN 1766.278368
min 1301.000000 1.272000e+09 100.0 NaN 0.000000e+00 0.000000e+00 -9.422000e+05 -1.921990e+07 2.950000 -55.110000 … NaN NaN NaN NaN NaN NaN NaN NaN NaN 0.000000
25% 3537.750000 1.178050e+10 100.0 NaN 2.745000e+04 2.000000e+02 -2.625000e+03 -9.000000e+02 10.567500 -8.792500 … NaN NaN NaN NaN NaN NaN NaN NaN NaN 920.750000
50% 5733.000000 2.997500e+10 100.0 NaN 8.880000e+04 5.800000e+03 1.000000e+02 0.000000e+00 15.095000 -0.795000 … NaN NaN NaN NaN NaN NaN NaN NaN NaN 1594.500000
75% 7643.750000 8.858500e+10 100.0 NaN 2.366500e+05 4.462500e+04 3.700000e+03 2.000000e+02 25.055000 9.880000 … NaN NaN NaN NaN NaN NaN NaN NaN NaN 2596.250000
max 9997.000000 1.306616e+12 100.0 NaN 8.833600e+06 6.529200e+06 1.738600e+06 2.960900e+06 780.520000 187.860000 … NaN NaN NaN NaN NaN NaN NaN NaN NaN 15680.000000

11 rows × 92 columns

In [18]:
data_corr = data_cleaned.corr()
sns.heatmap(data_corr, vmax=1, vmin=-1, center=0)
Out[18]:
<AxesSubplot:>
In [19]:
data_corr["翌日株価"].sort_values(ascending = False)
Out[19]:
翌日株価         1.000000
株価           0.997146
EPS          0.603882
時価総額         0.439605
株価変化率-3年前    0.385891
               ...   
配当利回-5年前    -0.162346
配当利回-3年前    -0.166533
配当利回-1年前    -0.169757
配当利回        -0.280374
売買単位              NaN
Name: 翌日株価, Length: 91, dtype: float64

相関を求めてみると上記の通り、株価と翌日株価の相関は極めて高い。当たり前だが。

最小二乗法の前提の確認

線形回帰分析するにあたって、以下の条件が必要であることを先の投稿で述べた。これらが今回はどうかを調べてみる。

1, 自己相関がないこと。 こちらは、今回は時系列のデータではないので、自己相関はないと思われる。

2, 多重共線性が無いこと。 こちらはこのあとで確認

3, 線形性が無いこと。 こちらはこのあとで確認

4, 内成性が無いこと。 後ほど確認

線形性の確認

In [20]:
f, (ax1, ax2, ax3) = plt.subplots(1, 3, sharey=True, figsize =(15,3))
ax1.scatter(data_cleaned['EPS'],data_cleaned['翌日株価'])
ax1.set_title('翌日株価 and EPS')
ax2.scatter(data_cleaned['時価総額'],data_cleaned['翌日株価'])
ax2.set_title('翌日株価 and 時価総額')
ax3.scatter(data_cleaned['PSR'],data_cleaned['翌日株価'])
ax3.set_title('翌日株価 and PSR')
plt.show()

正直、線形性があるとは言えないので、線形回帰分析を進めるのには向かないと思われるがこのまま進めようかなと思う。

また、3つ目のPSRは外れ値を除外していないので、EPSや時価総額と比較すると外れ値が多く含まれることがわかる。本来はこれらも外れ値は除外した方がいいと思われる。

多重共線性の確認

In [21]:
from statsmodels.stats.outliers_influence import variance_inflation_factor
#多重共線性を調べる変数の指定。カテゴリ変数以外を全て指定
variables = data_cleaned[['証券コード', '時価総額', '売買単位', '信用残-買', '信用残-売',
'前週比-買', '前週比-売', 'PER', 'PER変化率-1年前', 'PER変化率-3年前', 'PER変化率-5年前',
'EPS', 'PBR', 'PBR変化率-1年前', 'PBR変化率-3年前', 'PBR変化率-5年前', '配当利回',
'配当利回-1年前', '配当利回-3年前', '配当利回-5年前', 'ROE', 'ROA', '売上高',
'売上高変化率-Y0Y', 'PSR', '売上高営業利益率', '売上高経常利益率', '売上債権回転率', '経常利益',
'経常利益変化率-YoY', '自己資本比率', '前期最終損益', '有利子負債自己資本利率', 'EV/EBITDA倍率',
'流動比率', '当座比率', 'PCFR', '棚卸資産回転率', '信用残/売買高レシオ', '株価',
'株価変化率-1営業日前', '株価変化率-5営業日前', '株価変化率-20営業日前', '株価変化率-3ヶ月前',
'株価変化率-6ヶ月前', '株価変化率-1年前', '株価変化率-3年前', '株価変化率-5年前', '年初来安値からの上昇率',
'年初来高値からの下落率', '平均売買代金-5日', '平均売買代金-20日', '出来高増加率-5営業日前',
'出来高増加率-20営業日前', '出来高増加率-3ヶ月前', '出来高増加率-6ヶ月前', '出来高増加率-1年前',
'売買代金増加率-5日', '売買代金増加率-20営業日前', '売買代金増加率-3ヶ月前', '売買代金増加率-6ヶ月前',
'売買代金増加率-1年前', '株価移動平均線からの乖離率-5営業日', '株価移動平均線からの乖離率-20営業日',
'株価移動平均線からの乖離率-75営業日', 'RSI', 'サイコロジカルライン', 'ノーマルストキャスティクス','翌日株価']]
vif = pd.DataFrame()
vif["VIF"] = [variance_inflation_factor(variables.values, i) for i in range(variables.shape[1])]
vif["Features"] = variables.columns
In [22]:
vif
Out[22]:
VIF Features
0 1.126990 証券コード
1 7.017660 時価総額
2 0.000000 売買単位
3 2.102424 信用残-買
4 3.022840 信用残-売
… … …
64 22.454859 株価移動平均線からの乖離率-75営業日
65 5.334506 RSI
66 1.727773 サイコロジカルライン
67 3.210365 ノーマルストキャスティクス
68 189.606644 翌日株価

69 rows × 2 columns

VIF=1:多重共線性はない。
1 < VIF < 5: が問題ない。
5 < VIF: 多重共線性あり
になるらしい。ということで、5超を除外

In [23]:
multicollinearity_columns = vif[vif["VIF"]>5]["Features"].to_list()
#翌日株価が除外されると元も子もないので、それは残す
multicollinearity_columns.remove('翌日株価')
multicollinearity_columns
Out[23]:
['時価総額',
 'PER',
 'PER変化率-1年前',
 'PER変化率-5年前',
 'PBR',
 'PBR変化率-1年前',
 'PBR変化率-3年前',
 'PBR変化率-5年前',
 '配当利回-1年前',
 'ROE',
 'ROA',
 'PSR',
 '売上高営業利益率',
 '売上高経常利益率',
 '経常利益',
 '前期最終損益',
 '流動比率',
 '当座比率',
 'PCFR',
 '株価',
 '株価変化率-20営業日前',
 '株価変化率-3ヶ月前',
 '株価変化率-6ヶ月前',
 '株価変化率-3年前',
 '株価変化率-5年前',
 '年初来安値からの上昇率',
 '平均売買代金-5日',
 '平均売買代金-20日',
 '出来高増加率-5営業日前',
 '出来高増加率-20営業日前',
 '出来高増加率-3ヶ月前',
 '出来高増加率-6ヶ月前',
 '出来高増加率-1年前',
 '売買代金増加率-5日',
 '売買代金増加率-20営業日前',
 '売買代金増加率-3ヶ月前',
 '売買代金増加率-6ヶ月前',
 '売買代金増加率-1年前',
 '株価移動平均線からの乖離率-20営業日',
 '株価移動平均線からの乖離率-75営業日',
 'RSI']
In [24]:
data_no_multicollinearity = data_cleaned.drop(multicollinearity_columns,axis=1)

ダミー変数の作成

カテゴリー変数をダミー変数に変換

In [25]:
data_preprocessed = pd.get_dummies(data_no_multicollinearity, drop_first=True)
In [26]:
data_preprocessed.head()
Out[26]:
証券コード 売買単位 信用残-買 信用残-売 前週比-買 前週比-売 PER変化率-3年前 EPS 配当利回 配当利回-3年前 … 業種_輸送用機器 業種_通信業 業種_金属製品 業種_鉄鋼 業種_鉱業 業種_陸運業 業種_電気機器 業種_電気・ガス業 業種_非鉄金属 業種_食料品
0 1301 100 12300.0 4400.0 200.0 -3700.0 -19.83 356.95 2.66 7.68 … 0 0 0 0 0 0 0 0 0 0
1 1352 100 13800.0 200.0 0.0 -100.0 -52.80 95.36 2.16 -10.91 … 0 0 0 0 0 0 0 0 0 0
2 1376 100 5100.0 300.0 -500.0 300.0 -2.71 123.09 1.96 -5.39 … 0 0 0 0 0 0 0 0 0 0
3 1377 100 55000.0 90900.0 -700.0 -1100.0 -7.46 171.24 1.11 10.95 … 0 0 0 0 0 0 0 0 0 0
4 1379 100 43000.0 42700.0 1200.0 -500.0 -21.55 128.83 3.09 -1.18 … 0 0 0 0 0 0 0 0 0 0

5 rows × 80 columns

線形回帰モデル

入力とターゲットの宣言

In [27]:
targets = data_preprocessed['翌日株価']
inputs = data_preprocessed.drop(['翌日株価'],axis=1)

データの標準化

In [28]:
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
scaler.fit(inputs)
Out[28]:
StandardScaler()
In [29]:
inputs_scaled = scaler.transform(inputs)

訓練データとテストデータの分割

In [30]:
from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test = train_test_split(inputs_scaled, targets, test_size=0.2, random_state=42)

回帰の作成

In [31]:
reg = LinearRegression()
reg.fit(x_train,y_train)
Out[31]:
LinearRegression()
In [32]:
y_hat = reg.predict(x_train)
In [33]:
plt.scatter(y_train, y_hat, alpha=0.2)
plt.xlabel('Targets (y_train)',size=18)
plt.ylabel('Predictions (y_hat)',size=18)
plt.xlim(0,10000)
plt.ylim(0,10000)
plt.show()
In [34]:
sns.distplot(y_train - y_hat)
plt.title("Residuals PDF", size=18)
Out[34]:
Text(0.5, 1.0, 'Residuals PDF')
In [35]:
reg.score(x_train,y_train)
Out[35]:
0.5991354959994877

この結果から対して結果は良くないことがわかる。

重みとバイアス

In [36]:
reg.intercept_
Out[36]:
2100.937523470217
In [37]:
reg.coef_
Out[37]:
array([ 5.65537855e+01,  6.75991218e+13, -1.50814644e+02,  8.85501067e+01,
        9.36071710e+00,  2.63214869e+01,  7.39409768e+01,  1.11544283e+03,
       -4.37991004e+02,  2.68164062e+00, -9.26064453e+01,  2.00360840e+02,
       -2.29887695e+01,  1.64862671e+01, -1.49462891e+00,  2.51492065e+02,
        8.16845703e+01,  1.54619165e+03,  1.19190674e+01, -7.46171875e+01,
       -7.12236328e+01, -5.90527344e+00,  1.38160645e+02,  9.32331543e+01,
       -8.24353027e+01, -4.15258789e+01, -2.62832031e+01,  9.18906250e+01,
       -4.74220459e+02, -8.31796875e+01,  5.55623047e+02,  2.60449219e+00,
       -2.55224609e+01,  1.28562012e+01,  4.48881836e+01, -3.96137695e+01,
        2.34729004e+01, -4.29575195e+01,  4.11289062e+01, -4.45507812e+00,
        5.15625000e+01,  5.46718750e+01,  2.75927734e+00,  2.03647461e+01,
        7.13662415e+01, -1.25468750e+01,  3.97265625e+01, -1.20781250e+01,
        2.79960938e+01,  3.46152344e+01,  6.01894531e+01,  5.16191406e+01,
        7.13363037e+01, -3.45136719e+01,  3.50649414e+01, -4.62734375e+01,
        3.49765625e+01,  7.89443359e+01, -2.22617188e+01, -5.69453125e+01,
       -2.93671875e+01,  9.03808594e+01, -2.28984375e+01,  5.75781250e+00,
        2.80546875e+01,  3.51215820e+01,  3.06914062e+01,  6.21035156e+01,
        4.35893555e+01,  1.33105469e+00,  1.61474609e+01, -1.57375488e+01,
        6.79294128e+01,  4.87968750e+01,  2.78710938e+00,  9.35566406e+01,
       -5.05781250e+01,  7.98632812e+00,  1.32812500e+00])
In [38]:
reg_summary = pd.DataFrame(inputs.columns.values, columns=['Features'])
reg_summary['Weights'] = reg.coef_
pd.options.display.max_rows = 999
weight = reg_summary.sort_values('Weights')
weight
Out[38]:
Features Weights
28 ベータ(対TOPIX) -4.742205e+02
8 配当利回 -4.379910e+02
2 信用残-買 -1.508146e+02
10 配当利回-5年前 -9.260645e+01
29 ベータ(対日経平均) -8.317969e+01
24 株価移動平均線からの乖離率-5営業日 -8.243530e+01
19 信用残/売買高レシオ -7.461719e+01
20 株価変化率-1営業日前 -7.122363e+01
59 業種_小売業 -5.694531e+01
76 業種_電気・ガス業 -5.057812e+01
55 業種_倉庫・運輸関連業 -4.627344e+01
37 DMI-週足-買 -4.295752e+01
25 サイコロジカルライン -4.152588e+01
35 DMI-日足-買 -3.961377e+01
53 業種_パルプ・紙 -3.451367e+01
60 業種_建設業 -2.936719e+01
26 ノーマルストキャスティクス -2.628320e+01
32 デッドクロス -2.552246e+01
12 売上高変化率-Y0Y -2.298877e+01
62 業種_水産・農林業 -2.289844e+01
58 業種_卸売業 -2.226172e+01
71 業種_金属製品 -1.573755e+01
45 ノーマルストキャスティクス-買 -1.254688e+01
47 スローストキャスティクス-買 -1.207812e+01
21 株価変化率-5営業日前 -5.905273e+00
39 RCI-買 -4.455078e+00
14 経常利益変化率-YoY -1.494629e+00
78 業種_食料品 1.328125e+00
69 業種_輸送用機器 1.331055e+00
31 ゴールデンクロス 2.604492e+00
9 配当利回-3年前 2.681641e+00
42 MACD-日足-売 2.759277e+00
74 業種_陸運業 2.787109e+00
63 業種_海運業 5.757812e+00
77 業種_非鉄金属 7.986328e+00
4 前週比-買 9.360717e+00
18 棚卸資産回転率 1.191907e+01
33 一目均衡雲抜け上 1.285620e+01
70 業種_通信業 1.614746e+01
13 売上債権回転率 1.648627e+01
43 MACD-週足-買 2.036475e+01
36 DMI-日足-売 2.347290e+01
5 前週比-売 2.632149e+01
48 スローストキャスティクス-売 2.799609e+01
64 業種_石油・石炭製品 2.805469e+01
66 業種_精密機器 3.069141e+01
49 業種_その他製品 3.461523e+01
56 業種_化学 3.497656e+01
54 業種_不動産業 3.506494e+01
65 業種_空運業 3.512158e+01
46 ノーマルストキャスティクス-売 3.972656e+01
38 DMI-週足-売 4.112891e+01
68 業種_証券業 4.358936e+01
34 一目均衡雲抜け下 4.488818e+01
73 業種_鉱業 4.879688e+01
40 RCI-売 5.156250e+01
51 業種_ゴム製品 5.161914e+01
41 MACD-日足-買 5.467188e+01
0 証券コード 5.655379e+01
50 業種_ガラス・土石製品 6.018945e+01
67 業種_繊維製品 6.210352e+01
72 業種_鉄鋼 6.792941e+01
52 業種_サービス業 7.133630e+01
44 MACD-週足-売 7.136624e+01
6 PER変化率-3年前 7.394098e+01
57 業種_医薬品 7.894434e+01
16 有利子負債自己資本利率 8.168457e+01
3 信用残-売 8.855011e+01
61 業種_機械 9.038086e+01
27 スローストキャスティクス 9.189062e+01
23 年初来高値からの下落率 9.323315e+01
75 業種_電気機器 9.355664e+01
22 株価変化率-1年前 1.381606e+02
11 売上高 2.003608e+02
15 自己資本比率 2.514921e+02
30 ベータ(対東証業種指数) 5.556230e+02
7 EPS 1.115443e+03
17 EV/EBITDA倍率 1.546192e+03
1 売買単位 6.759912e+13

テスト

In [40]:
y_hat_test = reg.predict(x_test)
In [41]:
plt.scatter(y_test, y_hat_test, alpha=0.2)
plt.xlabel('Targets (y_test)',size=18)
plt.ylabel('Predictions (y_hat_test)',size=18)
plt.xlim(0,10000)
plt.ylim(0,10000)
plt.show()
In [42]:
df_pf = pd.DataFrame(y_hat_test, columns=['Prediction'])
y_test = y_test.reset_index(drop=True)
df_pf['Target'] = y_test
df_pf['Residual'] = df_pf['Target'] - df_pf['Prediction']
df_pf['Difference%'] = np.absolute(df_pf['Residual']/df_pf['Target']*100)
df_pf.describe()
Out[42]:
Prediction Target Residual Difference%
count 296.000000 296.000000 296.000000 296.000000
mean 2203.479002 2014.635135 -188.843867 inf
std 3547.919796 1781.616737 3518.790111 NaN
min -969.482765 0.000000 -57629.676021 0.205091
25% 1112.367119 871.000000 -593.865653 14.814455
50% 1759.599477 1542.000000 -132.005542 31.267568
75% 2770.810114 2580.250000 436.503750 66.109053
max 58174.676021 15680.000000 10362.737654 inf

残差を見ると、それなりにばらつきがあることがわかる。おそらくそれなりに丁寧にデータを整理すればもうちょっと精度は良くなるのかなとも思う。

Follow me!