ぷそさんのプログラミング研究所

【ソースコードあり】Python|株価予測で学ぶロジスティック回帰の使い方

この記事でわかること
  • ロジスティック回帰の実装方法(ソースコードつき)
  • ロジスティック回帰での株価予測の方法
目次

ロジスティック回帰による株価予測の概要

予測は以下の流れで行います。

つまり,30日後に株価が上がるか下がるかを予測する分類モデルになります!

他の手法でも予測をしているので,ぜひご覧ください!

あわせて読みたい
【ソースコードあり】Python|株価予測で学ぶLightGBMの使い方 この記事でわかること LightGBMの実装方法(ソースコードつき) LightGBMでの株価予測の方法 【LightGBMによる株価予測の概要】 予測は以下の流れで行います。 つまり,...
あわせて読みたい
【ソースコードあり】Python|株価予測で学ぶランダムフォレストの使い方 この記事でわかること ランダムフォレストの実装方法(ソースコードつき) ランダムフォレストでの株価予測の方法 【ランダムフォレストによる株価予測の概要】 予測は...
あわせて読みたい
【ソースコードあり】Python|株価予測で学ぶディープラーニングの使い方 この記事でわかること ディープニューラルネットワークの実装方法(ソースコードつき) ディープニューラルネットワークでの株価予測の方法 【による株価予測の概要】 ...
あわせて読みたい
【ソースコードあり】Python|株価予測で学ぶニューラルネットワークの使い方 この記事でわかること ニューラルネットワークの実装方法(ソースコードつき) ニューラルネットワークでの株価予測の方法 【による株価予測の概要】 予測は以下の流れ...

事前準備

まずは,環境についてです。

  • Python 3.8.15
  • macOS Monterey 12.5

必要なライブラリは以下のようになります。ない場合にはpipcondaで入れてください。

必要なライブラリ

  • pandas
  • numpy
  • sklearn
  • datetime
  • pandas_datareader

ライブラリのインポート

データを扱うのに必要なライブラリのインポートを行います。

import pandas as pd
import numpy as np
from datetime import datetime

株価情報の取得

主要な株価指数の取得

予測のための説明変数として,日経平均株価などを取得します。

今回は,日経225,S&P500,ナスダック総合指数を取得しています。

from pandas_datareader import data
marketData = ['NIKKEI225','SP500','NASDAQCOM']
df_market = data.DataReader(marketData,'fred','2014-01-01', '2023-1-31').asfreq("D")
df_market = df_market.fillna(method='ffill')
df_market = df_market.dropna(how='any')

3行目:df_market = data.DataReader…

指数を2014年1月1日から2023年1月31日まで取得しています。

4行目:df_market = df_market.fillna…

欠損値を埋めています。

5行目:df_market = df_market.dropna…

欠損値がある場所は削除しています。

株価取得の詳しい内容については以下をご覧ください。

あわせて読みたい
【コピペ可】Pythonで株価分析|株価データの取得 Pythonを使った株価分析の基本を解説します! 【株価データを取得する】 株価データを取得するにはpandas-datareaderというライブラリを使用します。 このライブラリで...

主要な株価指数の前処理

株価指数そのままでは学習しにくいので,移動平均との乖離を計算します。

ここは精度に関係するので試行錯誤する必要があります。

# 各指数の移動平均との乖離率を算出する
for index_name in df_market.columns:
    for i in [5,10,30,60,90,120]:
        df_market[index_name + "_" + str(i) + "days_diffrol"] =\
        (df_market[index_name].rolling(i).mean() - df_market[index_name]) / df_market[index_name].rolling(i).mean()
    
    # 生データは削除する
    df_market = df_market.drop(columns=index_name)

予測する企業の株価を取得

予測したい企業の株価を取得します。

CODE=の部分は予測したい企業の株価コードを指定します。

今回は4755の企業の予測をしています。

# 予測する企業の株価データを取得
from pandas_datareader.stooq import StooqDailyReader
CODE = 4755
CODE_str = str(CODE) + ".JP"
start = datetime(2014, 1, 1)
end = datetime(2023, 1, 31)

df_target = StooqDailyReader(CODE_str, start=start, end=end).read()
df_target = df_target.sort_values('Date')
df_target = pd.DataFrame(df_target).asfreq("D", method="ffill")

5行目:start = datetime(2014, 1, 1)

取得する範囲のスタートを設定します。endも同じです。

8行目:df_target = StooqDailyReader…

データを取得します。

9行目:df_target = df_target.sort_values(‘Date’)

df_targetには最近のデータから順番に入っているので昇順にします。

10行目:df_target = pd.DataFrame…

データの欠損値処理をしています。

予測対象の作成

予測するのは,30日後に株価が上がるか下がるかです。

今回は,今日の終値30日後の終値を比較して10%以上増加するかしないかを設定しています。

分類問題なので,増加する場合に「1」,それ以外は「0」としています。

# 目的変数の作成(30日後に5 %以上上昇する時に1)
df_target["30days_after"] = df_target["Close"].shift(-30)
df_target['ratio'] = df_target['30days_after'] / df_target["Close"]
df_target['target'] = np.where(df_target['ratio'] > 1.1, 1, 0)

# 不要な行と列を削除
df_target = df_target.dropna(how='any')
df_target = df_target.drop(columns=["ratio","30days_after"])

2行目:df_target[“30days_after”] = …

Closeに入っている終値を30日ずらすことで,30日後の終値を取得しています。

3行目:df_target[‘ratio’] = …

30日後の終値を現在の終値で割ることで比を計算しています。

4行目:df_target[‘target’] = …

前述で計算した比率が10%以上増加している場合に「1」,それ以外に「0」をtargetに保存しています。

データの整理

データの結合

これまでに作成したデータを結合して1つのdataframeにします。

# データの結合
df = pd.merge(df_target, df_market, how='left', left_index=True, right_index=True)
df = df.dropna(how='any')

学習データとテストデータに分割

今回は,2021年までのデータを使って2022年の予測を行います。

# トレインとテストに分割
df_train = df[:"2021"]
df_test = df["2022":]

# 目的変数と説明変数に分割
X_train = df_train.drop("target", axis=1)
y_train = df_train["target"]
X_test = df_test.drop("target", axis=1)
y_test = df_test["target"]

モデルの作成

ロジスティック回帰での学習

いよいよ作成したデータを学習させます。

# 学習
from sklearn.linear_model import LogisticRegression
# ロジスティック回帰のインスタンス
model = LogisticRegression(penalty='l2',          # 正則化項(L1正則化 or L2正則化が選択可能)
                           dual=False,            # Dual or primal
                           tol=0.0001,            # 計算を停止するための基準値
                           C=1.0,                 # 正則化の強さ
                           fit_intercept=True,    # バイアス項の計算要否
                           intercept_scaling=1,   # solver=‘liblinear’の際に有効なスケーリング基準値
                           class_weight=None,     # クラスに付与された重み
                           random_state=None,     # 乱数シード
                           solver='lbfgs',        # ハイパーパラメータ探索アルゴリズム
                           max_iter=100,          # 最大イテレーション数
                           multi_class='auto',    # クラスラベルの分類問題(2値問題の場合'auto'を指定)
                           verbose=0,             # liblinearおよびlbfgsがsolverに指定されている場合、冗長性のためにverboseを任意の正の数に設定
                           warm_start=False,      # Trueの場合、モデル学習の初期化に前の呼出情報を利用
                           n_jobs=None,           # 学習時に並列して動かすスレッドの数
                           l1_ratio=None          # L1/L2正則化比率(penaltyでElastic Netを指定した場合のみ)
                          )

model.fit(X_train, y_train) # モデルの学習

3行目:model = LogisticRegression…

ロジスティック回帰の設定を定義しています。

21行目:model.fit(X_train, y_train)

学習データを入れて学習させます。

結果の保存

予測結果を保存して精度を確認します。

df_resultに結果をまとめます。

# 予測値と実値との比較
df_result = pd.DataFrame()
df_result["Price"] = df_target["Close"]["2022-01-01":]
df_result["true"] = y_test
df_result["Pred"] = model.predict(X_test)

5行目:df_result[“Pred”] = model.predict(X_test)

テストデータをモデルに入れた時の結果を保存しています。

結果の確認

混同行列で結果を確認してみましょう。

どれだけ正しく分類できたかを表すAccuracyを計算すると,344/366で94%となりました。

数値だけ見ると良い数字ですが,全てを「上昇しない」予測するモデルとなってしまいました。

ですので,使えるモデルにするためにはパラメータチューニングを行う必要があります。

他の精度を上げる方法は以下の方法が考えられます。

精度を上げる方法

  • 他のアルゴリズムを使用する
  • パラメータチューニングをする
  • 他の指標を使って予測する

機械学習を使ったモデルは以下の記事で紹介しています!

あわせて読みたい
【ソースコードあり】Python|株価予測で学ぶランダムフォレストの使い方 この記事でわかること ランダムフォレストの実装方法(ソースコードつき) ランダムフォレストでの株価予測の方法 【ランダムフォレストによる株価予測の概要】 予測は...

ソースコードまとめ

今回使用したコードはこちらになります。

import pandas as pd
import numpy as np
from datetime import datetime

# 市場データの取得
from pandas_datareader import data
marketData=['NIKKEI225','SP500','NASDAQCOM']
df_market = data.DataReader(marketData,'fred','2014-01-01', '2023-1-31').asfreq("D")
df_market = df_market.fillna(method='ffill')
df_market = df_market.dropna(how='any')

# 各指数の移動平均との乖離率を算出する
for index_name in df_market.columns:
    for i in [5,10,30,60,90,120]:
        df_market[index_name + "_" + str(i) + "days_diffrol"] =\
        (df_market[index_name].rolling(i).mean() - df_market[index_name]) / df_market[index_name].rolling(i).mean()
    
    # 生データは削除する
    df_market = df_market.drop(columns=index_name)

# 予測する企業の株価データを取得
from pandas_datareader.stooq import StooqDailyReader
CODE = 4755
CODE_str = str(CODE) + ".JP"
start = datetime(2014, 1, 1)
end = datetime(2023, 1, 31)

df_target = StooqDailyReader(CODE_str, start=start, end=end).read()
df_target = df_target.sort_values('Date')
df_target = pd.DataFrame(df_target).asfreq("D", method="ffill")

# 目的変数の作成(30日後に5 %以上上昇する時に1)
df_target["30days_after"] = df_target["Close"].shift(-30)
df_target['ratio'] = df_target['30days_after'] / df_target["Close"]
df_target['target'] = np.where(df_target['ratio'] > 1.1, 1, 0)

# 不要な行と列を削除
df_target = df_target.dropna(how='any')
df_target = df_target.drop(columns=["ratio","30days_after"])

# データの結合
df = pd.merge(df_target, df_market, how='left', left_index=True, right_index=True)
df = df.dropna(how='any')

# トレインとテストに分割
df_train = df[:"2021"]
df_test = df["2022":]

# 目的変数と説明変数に分割
X_train = df_train.drop("target", axis=1)
y_train = df_train["target"]
X_test = df_test.drop("target", axis=1)
y_test = df_test["target"]

# 学習
from sklearn.linear_model import LogisticRegression
# ロジスティック回帰のインスタンス
model = LogisticRegression(penalty='l2',          # 正則化項(L1正則化 or L2正則化が選択可能)
                           dual=False,            # Dual or primal
                           tol=0.0001,            # 計算を停止するための基準値
                           C=1.0,                 # 正則化の強さ
                           fit_intercept=True,    # バイアス項の計算要否
                           intercept_scaling=1,   # solver=‘liblinear’の際に有効なスケーリング基準値
                           class_weight=None,     # クラスに付与された重み
                           random_state=None,     # 乱数シード
                           solver='lbfgs',        # ハイパーパラメータ探索アルゴリズム
                           max_iter=100,          # 最大イテレーション数
                           multi_class='auto',    # クラスラベルの分類問題(2値問題の場合'auto'を指定)
                           verbose=0,             # liblinearおよびlbfgsがsolverに指定されている場合、冗長性のためにverboseを任意の正の数に設定
                           warm_start=False,      # Trueの場合、モデル学習の初期化に前の呼出情報を利用
                           n_jobs=None,           # 学習時に並列して動かすスレッドの数
                           l1_ratio=None          # L1/L2正則化比率(penaltyでElastic Netを指定した場合のみ)
                          )

model.fit(X_train, y_train) # モデルの学習
# 予測値と実値との比較
df_result = pd.DataFrame()
df_result["Price"] = df_target["Close"]["2022-01-01":]
df_result["true"] = y_test
df_result["Pred"] = model.predict(X_test)
よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

このブログでは,PythonやLaTeXの使い方などを紹介しています!
仕事でも趣味でもプログラミングをしています。
ブログは2022年8月にスタートしました。
【経歴】東京大学大学院修了→大手IT企業勤務

コメント

コメントする

目次