
やっぱりPython AIモデル用の学習データを用意するのに疲れてしまった編
手作業でAIモデル用の学習データを用意していたのですが…
回数を重ねるにつれ、AIモデル用の学習データを用意するのに疲れてしまいました。
そこで、気分転換も兼ねて、AIモデル用の学習データを作成するPythonプログラムを作ることにしました。
久しぶりのPythonなので、いろいろと忘れていることもあり思いのほか時間がかかってしまいましたが、とりあえず、できました。
作成したPythonプログラムはこんな感じ
作成したPythonプログラムで出来ることは以下の通りです。
Pythonプログラムの仕様
Stooqから日経平均株価のデータをダウンロードし、二値分類向けの学習データおよび評価データを作成
学習データおよび評価データは標準化の実施 or 未実施が選択可能
作成した学習データおよび評価データはcsv形式のファイルとして出力
学習データおよび評価データに含ませる要素はローソク足データ以外に下記から選択可能
SMA(5, 25, 75日)
ボリンジャーバンド(±2σ, ±σ, 20SMA)
MACD(MACD, Signal)
Neural Network ConsoleのRNN向けにn日分のデータを1行ベクトルとして生成
nは指定可能
評価データの日数を指定可能
ダウンロードした日経平均株価のデータはcsv形式のファイルで出力可能
株価データの取得開始および終了期間を設定可能
事前にダウンロードした株価データを基に学習データおよび評価データを作成可能
ちなみに、私が使用しているPythonのバージョンは、Python 3.9.18です。
また、作成したPythonプログラムを実行するためにpandas_datareaderをインストール(下記コマンドを実行)しておく必要があります。
pip install pandas_datareader
Pythonプログラムを実行した結果
作成したPythonプログラムは、Stock2Training4BinClass.pyのファイル名で保存しています。
先ずは、ヘルプメッセージです。
> python Stock2Training4BinClass.py --h
usage: Stock2Training4BinClass.py [-h] [--csv CSV] [--dl DL] [--elm ELM [ELM ...]] [--rnn RNN] [--s S] [--e E]
[--vnum VNUM] [--t T] [--v V] [--nostd] [--debug]
Stock data to Training data tool for AI model
optional arguments:
-h, --help show this help message and exit
--csv CSV Stock data file name(csv format)
--dl DL csv file name(Download stock data to csv file)
--elm ELM [ELM ...] Element to add to training data(Default: SMA BB MACD)
--rnn RNN Repeat parameter for RNN(Default: 1)
--s S Start date(Default: 1986-01-01)
--e E End date(Default: 2024-01-31)
--vnum VNUM Number of rows for validation data(Default: 250)
--t T Training data file name(Default: training.csv)
--v V Validation data file name(Default: validation.csv)
--nostd No standardization(Default: Excecute standardization)
--debug Debug mode
オプションの詳細は、以下の通りです。
オプションの詳細
--csv
事前にダウンロードした株価データを使用して学習データおよび評価データを作成する場合に使用
株価データを保持しているcsvファイルを指定
指定方法は"--csv abc.csv"とか
--dl
Stooqからダウンロードした株価データを保存するcsvファイルの名前を指定
--elm
学習データおよび評価データに含ませる要素を指定(デフォルトはすべて含む)
指定方法は"--elm SMS"とか"--elm BB MACD"とか
SMA: 5, 25, 75日移動平均
BB: ボリンジャーバンド
MACD: MACD
--rnn
Neural Network ConsoleのRNN用にn日分のデータを1行ベクトルとして作成(デフォルトは1日)
指定方法は"--rnn 5"とか
--s
株価データの開始年月日を指定(デフォルトは1986-01-01)
指定方法は"--s 2001-8-10"とか"--s 2010-03-05"とか
--e
株価データの終了年月日を指定(デフォルトは2024-01-31)
指定方法は--sオプションと同じ
--vnum
評価データの日数を指定(デフォルトは250日)
指定方法は"--vnum 220"とか
--t
学習データを出力するファイル名を指定(デフォルトはtraining.csv)
指定方法は"--t test_train.csv"とか
--v
評価データを出力するファイル名を指定(デフォルトはvalidation.csv)
指定方法は"--v test_val.csv"とか
--nostd
学習データおよび評価データに対して標準化を行わない場合に選択(デフォルトは未選択)
指定方法は"--nostd"
--debug
デバッグモードを有効化(デフォルトは無効)
指定方法は"--debug"
下記に、作成したPythonプログラムを実行した結果を記載します。
> python Stock2Training4BinClass.py --rnn 2
Start day: 1986-01-01
End day: 2024-01-31
WebSite: stooq
Training data element: SMA BB MACD
RNN params: 2
Number of rows for validation data: 250
Training data period: 1986-04-24 00:00:00 - 2023-01-23 00:00:00
Validation data period: 2023-01-24 00:00:00 - 2024-01-29 00:00:00
Training data csv file: training.csv
Validation data csv file: validation.csv
Done.
Neural Network Console向けの学習データはtraining.csvファイルとして、評価データはvalidation.csvファイルとして作成されます。
Neural Network Consoleで学習および評価を実行
Pythonプログラムが作成したtraining.csvとvalidation.csvをそのまま使用して、Neural Network Consoleで学習および評価を行います。
使用したAIモデルは、前回と同じく2層Affine構造としました。
以下に、学習曲線と混同行列を記載します。


これまで、私が手作業で作成してきた学習データおよび評価データに基づく学習曲線および混同行列と同レベルの結果となりました。
これまでの学習曲線および混同行列については、下記の記事を参照ください。
Pythonプログラムのソースコード
以下に、私が作成したPythonプログラムのソースコードを記載します。
'''
AIモデル向けに株価データに基づいた学習データを作成します
ラベルの出力形式は二値分類とします
学習データの作成手順
1. Stooqから株価データをダウンロード(事前にダウンロードした株価データも使用可能)
2. 学習データの作成
実行方法の一例
python filename.py
python filename.py --csv StockData
python filename.py --elm BB MACD --rnn 3
株価データのフォーマット
* 株価データのフォーマットは、下記のフォーマットとします
* 各データ間はカンマ区切りとします
* 時系列は昇順でも降順でもどちらでも良く、本プログラム内で昇順に並べ替えます
Date,Open,High,Low,Close,Volume
2023-01-31,27458.56,27494.17,27302.22,27327.11,745973100.0
...
'''
# -*- coding: utf-8 -*-
import pandas as pd
import pandas_datareader.data as web
import argparse
def main():
# 引数の処理
parser = argparse.ArgumentParser(description = 'Stock data to Training data tool for AI model')
parser.add_argument('--csv', required = False, help = 'Stock data file name(csv format)')
parser.add_argument('--dl', required = False, help = 'csv file name(Download stock data to csv file)')
parser.add_argument('--elm', required = False, nargs = '+', help = 'Element to add to training data(Default: SMA BB MACD)')
parser.add_argument('--rnn', required = False, type = int, default = 1, help = 'Repeat parameter for RNN(Default: 1)')
parser.add_argument('--s', required = False, default = '1986-01-01', help = 'Start date(Default: 1986-01-01)')
parser.add_argument('--e', required = False, default = '2024-01-31', help = 'End date(Default: 2024-01-31)')
parser.add_argument('--vnum', required = False, type = int, default = 250, help = 'Number of rows for validation data(Default: 250)')
parser.add_argument('--t', required = False, default = 'training.csv', help = 'Training data file name(Default: training.csv)')
parser.add_argument('--v', required = False, default = 'validation.csv', help = 'Validation data file name(Default: validation.csv)')
parser.add_argument('--nostd', required = False, action = 'store_true', help = 'No standardization(Default: Excecute standardization)')
parser.add_argument('--debug', required = False, action = 'store_true', help = 'Debug mode')
args = parser.parse_args()
# 指定期間の表示
DayStart = pd.to_datetime(args.s).strftime('%Y-%m-%d')
DayEnd = pd.to_datetime(args.e).strftime('%Y-%m-%d')
print('Start day:', DayStart)
print('End day:', DayEnd)
# 株価データの取得先を選択(csv file or Website)
if args.csv:
print('csv file:', args.csv)
# csvファイルのデータをDataFrameに入力
StockData = pd.read_csv(args.csv, encoding = 'utf-8')
# DataFrameのインデックスをDateに変更し、オリジナルのDataFrameも更新
StockData.set_index('Date', inplace = True)
# 指定期間のみ抽出
StockData = StockData[DayStart : DayEnd]
else:
WebSite = 'stooq'
Target = '^NKX' # 日経平均株価
print('WebSite:', WebSite)
# ウェブサイトから指定期間に対する日経平均株価のデータをダウンロードし、DataFrameに入力
StockData = web.DataReader(Target, WebSite, DayStart, DayEnd)
# 日付けを昇順に並べ替え
StockData = StockData.sort_index(ascending = True)
# 学習データの作成処理
if args.dl:
print('Output stock data to', args.dl)
# 株価データをcsvファイルに出力
StockData.to_csv(args.dl)
else:
# 学習データに追加する要素を設定
EnableSMA = True
EnableBB = True
EnableMACD = True
if args.elm:
print('Training data element:', args.elm)
EnableSMA = False
EnableBB = False
EnableMACD = False
for p in args.elm:
if 'SMA' == p: EnableSMA = True
if 'BB' == p: EnableBB = True
if 'MACD' == p: EnableMACD = True
else:
print('Training data element: SMA BB MACD')
# Volumeの列を削除
StockData = StockData.drop('Volume', axis = 1)
# SMA
if EnableSMA:
WinShort: int = 5
WinMiddle: int = 25
WinLong: int = 75
StockData['SMAShort'] = StockData['Close'].rolling(window = WinShort).mean()
StockData['SMAMiddle'] = StockData['Close'].rolling(window = WinMiddle).mean()
StockData['SMALong'] = StockData['Close'].rolling(window = WinLong).mean()
# Bollinger Band
if EnableBB:
WinBB: int = 20
SMABB = StockData['Close'].rolling(window = WinBB).mean()
StdDevBB = StockData['Close'].rolling(window = WinBB).std(ddof = 0)
StockData['BB-2Sig'] = SMABB - 2 * StdDevBB
StockData['BB-Sig'] = SMABB - StdDevBB
StockData['BBSMA'] = SMABB
StockData['BB+Sig'] = SMABB + StdDevBB
StockData['BB+2Sig'] = SMABB + 2 * StdDevBB
# MACD
if EnableMACD:
SpanShort: int = 12
SpanLong: int = 26
WinSignal: int = 9
EMAShort = StockData['Close'].ewm(span = SpanShort).mean()
EMALong = StockData['Close'].ewm(span = SpanLong).mean()
StockData['MACD'] = EMAShort - EMALong
StockData['MACDSig'] = StockData['MACD'].rolling(window = WinSignal).mean()
# RNN向けに指定分だけ各データを横に並べる処理
RNNNum = int(args.rnn)
# 出力用のDataFrame変数
OutData = StockData.copy()
if 1 < RNNNum:
print('RNN params:', RNNNum)
for i in range(RNNNum - 1):
# StockDataをコピー
TmpData = StockData.copy()
# TmpDataを上方向に1行シフト
TmpData = TmpData.shift(-1)
# OutDataの右側に結合
OutData = pd.concat([OutData, TmpData], axis = 1)
# ラベルを生成
# Closeの列を抽出
TmpClose = OutData['Close']
# RNNNum = 1の場合はSeriesをDataFrameに変換
if 1 == RNNNum: TmpClose = TmpClose.to_frame()
# 最後のCloseの列を抽出
TmpClose = TmpClose.iloc[:, -1]
# TmpCloseをコピー
TmpTmpClose = TmpClose.copy()
# TmpTmpCloseを上方向に1行シフト
TmpTmpClose = TmpTmpClose.shift(-1)
# 翌営業日(TmpTmpClose)と当日(TmpClose)の終値の差分を抽出
# NaNの情報が埋もれてしまうのを避けるため、ここで一旦NaNを削除
TmpLabel = (TmpTmpClose - TmpClose).dropna()
# 終値の差分が0以上ならラベル1、それ以外はラベル0
# 上記でNaNを削除しないと、ここでNaNがFalseに変換されてしまう
TmpLabel = (0 <= TmpLabel) * 1
# OutDataにラベルの値とLabel列を追加
OutData['Label'] = TmpLabel
# NaNを含む行を削除
OutData = OutData.dropna()
# 各データを標準化する処理
if not args.nostd:
# 標準化用のDataFrame変数
TmpOutData = OutData.copy()
# カラム(列)名を変更
TmpOutData = TmpOutData.rename(
columns = {
'Open': 'Data',
'High': 'Data',
'Low': 'Data',
'Close': 'Data'
})
if EnableSMA:
TmpOutData = TmpOutData.rename(
columns = {
'SMAShort': 'SMA',
'SMAMiddle': 'SMA',
'SMALong': 'SMA'
})
if EnableBB:
TmpOutData = TmpOutData.rename(
columns = {
'BB-2Sig': 'BB',
'BB-Sig': 'BB',
'BBSMA': 'BB',
'BB+Sig': 'BB',
'BB+2Sig': 'BB'
})
if EnableMACD:
TmpOutData = TmpOutData.rename(columns = {'MACDSig': 'MACD'})
# 平均値と標準偏差を格納するためのDataFrame
StdData = pd.DataFrame()
# 標準偏差が0となるのを避けるため、結果に影響しないであろう小さな値を加算
StdZero: float = 1.0e-15
StdData['MeanData'] = TmpOutData['Data'].mean(axis = 1).to_frame('MeanData')
StdData['StdData'] = TmpOutData['Data'].std(ddof = 0, axis = 1).to_frame('StdData') + StdZero
# SMA列用の標準化データ
if EnableSMA:
StdData['MeanSMA'] = TmpOutData['SMA'].mean(axis = 1).to_frame('MeanSMA')
StdData['StdSMA'] = TmpOutData['SMA'].std(ddof = 0, axis = 1).to_frame('StdSMA') + StdZero
# BB列用の標準化データ
if EnableBB:
StdData['MeanBB'] = TmpOutData['BB'].mean(axis = 1).to_frame('MeanBB')
StdData['StdBB'] = TmpOutData['BB'].std(ddof = 0, axis = 1).to_frame('StdBB') + StdZero
# MACD列用の標準化データ
if EnableMACD:
StdData['MeanMACD'] = TmpOutData['MACD'].mean(axis = 1).to_frame('MeanMACD')
StdData['StdMACD'] = TmpOutData['MACD'].std(ddof = 0, axis = 1).to_frame('StdMACD') + StdZero
# 各列に対して標準化を実施
ColNum: int = 0 # 列番号
for i in range(RNNNum):
for j in range(4):
OutData.iloc[:, ColNum] = (OutData.iloc[:, ColNum] - StdData['MeanData']) / StdData['StdData']
ColNum += 1
if EnableSMA:
for j in range(3):
OutData.iloc[:, ColNum] = (OutData.iloc[:, ColNum] - StdData['MeanSMA']) / StdData['StdSMA']
ColNum += 1
if EnableBB:
for j in range(5):
OutData.iloc[:, ColNum] = (OutData.iloc[:, ColNum] - StdData['MeanBB']) / StdData['StdBB']
ColNum += 1
if EnableMACD:
for j in range(2):
OutData.iloc[:, ColNum] = (OutData.iloc[:, ColNum] - StdData['MeanMACD']) / StdData['StdMACD']
ColNum += 1
# Neural Network Console用のヘッダを設定
# 説明変数用のヘッダを用意
NNCHeader = 'x__' + pd.Series(range(0, len(OutData.columns) - 1), dtype = 'str')
# 二値分類向け目的変数(ラベル)用のヘッダを追加
NNCHeader[len(NNCHeader)] = 'y:label;D;U'
# 学習データのヘッダを上書き
OutData.columns = [NNCHeader]
# 学習データをトレーニングデータとバリデーションデータに分割
print('Number of rows for validation data:', args.vnum)
TrainingData = OutData[:-args.vnum]
print('Training data period:', TrainingData.index[0], '-', TrainingData.index[-1])
ValidationData = OutData[len(OutData) - args.vnum:]
print('Validation data period:', ValidationData.index[0], '-', ValidationData.index[-1])
# Debug mode
if args.debug:
print('\nTraining data')
print(TrainingData)
print('\nValidation data')
print(ValidationData)
# トレーニングデータをcsvファイルに出力
print('Training data csv file:', args.t)
TrainingData.to_csv(args.t, index = False, float_format = '%.4f')
# バリデーションデータをcsvファイルに出力
print('Validation data csv file:', args.v)
ValidationData.to_csv(args.v, index = False, float_format = '%.4f')
print('\nDone.')
if __name__ == '__main__':
main()
#EOF
上記のPythonプログラムに対して、カスタマイズする可能性がありそうなものを下記にまとめておきます。
Pythonプログラムをカスタマイズするとしたら
変数Target: ダウンロードする対象の銘柄を指定しています
変数WinShort, WinMiddle, WinLong: SMAの期間(日数)を指定しています
変数WinBB: ボリンジャーバンドの期間(日数)を指定しています
変数SpanShort, SpanLong: MACDの期間(日数)を指定しています
変数WinSignal: MACDシグナルの期間(日数)を指定しています
今回は、SMA, ボリンジャーバンド、MACDを説明変数の要素として選択しました。
今後は、上記以外のテクニカル分析指標も追加していければと考えています。
そのための拡張性も含めて、検討したいと思います。