機械学習で株価予測 【Python】

Machine Learning

機械学習で株価予測を行ってみます。株価データは日経平均株価を使います。また、機械学習は、Python のランダムフォレスト等を使います。

以下の環境で動作確認をしています。
環境: Windows パソコン、Anaconda、Python 3.x (scikit-learn のインストール済み)

背景 ~ 機械学習で株価予測をトライ!

以前に、CSV ファイルを使って機械学習を行う Python のスクリプトについてまとめています(下記の関連リンク参照)。
なんらかの CSV 形式(テキスト形式)の数値データさえあれば、ランダムフォレストなどのアルゴリズムを設定し、機械学習と予測を実行することが可能です。
この応用例として、株価データを使った予測をしてみます。

機械学習では、学習に用いるデータの項目を増やしていくと、予測の精度を向上できる可能性があります。
また、機械学習のモデルとしては、ランダムフォレストなど以外にも、下記の関連リンクで示したように、ディープラーニングを使う選択肢も考えられます。

しかしながら、機械学習の項目数をいたずらに増やすと、ノイズや複雑度が増し、汎用性が失われていく傾向があります。また、Tensorflow 等のディープラーニングを用いると、プログラミングの複雑度が高くなります。他の人がすぐには使えないプログラム、メンテナンスが困難なプログラムになってしまいがちです。

そこでまずは、最もシンプルなケースとして、年、月、日、曜日の4つのデータのみに基づいて、各日付での株価を機械学習させてみます。機械学習のモデルも、ランダムフォレスト程度の簡単なものとします。この機械学習後のモデルを使って、将来の株価予測をしてみます。

とてもシンプルな事例ですので、教師データとして用いる項目を追加するなど、応用が容易です。学習モデルの変更も比較的容易です。
また、最も簡単な例について考察を加えておいたほうが、いったい何が可能なのか、限界・問題点は何か、見極めや見通しが明確になるというメリットがあります。

株価データは、一例として日経平均の日次データ(下記外部リンク参照。過去約3年分)を使うことにします。
プログラムはそのまま動くと思いますが、日経平均のデータについては著作権が関わる可能性があります。
そこで数値データそのものについては、サイト上での転載はせず、株価データを扱う際の一般的なポイントについて考察、言及することにします。

なお、機械学習で予測した結果については、何らの責任も負いかねます。ご理解をいただきますようお願いいたします。

設定手順

分析用フォルダおよび Python スクリプトの設定

① 以下を参考に、パソコンに株価分析用のフォルダを作成してください。
C:\user\stock_market_analysis1
② ①のフォルダにデータ用のフォルダ “data1” を作成してください。
株価データはこのフォルダに入れます。また、機械学習時に生成される出力結果等も、このフォルダ内に生成されます。
C:\user\stock_market_analysis1\data1
③ ①のフォルダの中に以下の4つのテキストファイルを作成し、末尾のサンプルスクリプトを貼りつけて保存してください。
・ 01_get_profile1.py
・ 02_learning1.py
・ 03_generate_date_list1.py
・ 04_predict1.py

実行方法

株価データの取得、ダウンロード

④ 下記の外部リンクを参照し、株価データ(”nikkei_stock_average_daily_jp.csv”、日次データ)を取得してください。
ダウンロードしたファイルは、②のフォルダ “data1” に入れてください。
ファイル名を変更した場合は、スクリプトを修正する必要があります。

機械学習の実施、予測

⑤ コマンドプロンプト(または、Anaconda Prompt)を起動し、③で設定した4つの Python スクリプトを順次(ファイル名冒頭の数字の順で)、実行してください。

→ 予測データ(csv3.csv)が生成されたら成功です!

★ 予測データは Excel などに貼りつけ、グラフ化するなどしてみてください。
★ また、以下の記載を参照し、機械学習実行時の正解率を調整したり、予測したい日付の範囲を変えるなど、微調整をしてみてください。
★ 必要により、機械学習に用いる教師データについて、新たな項目を追加してみてください。

予測の一例(株価予測)

上記の要領で機械学習を実行し、予測を行った一例を以下に示します。結果については、何らの責任も負いませんので、ご理解をいただきますようお願いいたします。


図1 機械学習の実行後、予測を行った一例(株価推移)

備考
・ 2019年1月~2022年7月中旬までの株価データについて機械学習を行いました。
・ 株価データは、500円区切りで丸めたものを使用しています。
・ 機械学習のモデルは Random Forest Classifier (fitting_model n1 = 6番)を使っています。変更も可能です。
・ 機械学習実行時、score が 50% を越える程度となるようパラメータを調整しています。
・ 株価予測を行う日付の範囲は、2020年7月以降の約3年としています。
日付の範囲が、機械学習を行った時期と重なるよう設定しています。これは、機械学習の学習の程度を表示させ、確認するためです。図1の赤線より右側が、将来の予測(機械学習を実行していない入力値に対する予測)に対応しています。
・ 機械学習実行時の入力データは、あえて、年月日、曜日のみとしています。そのため、予測結果は信頼度、妥当性のある結果とはなっていません。

使用するファイルについて

使用するファイルついてまとめると、以下となります。

ファイル名 概要
nikkei_stock_average_daily_jp.csv
(ダウンロードしたデータの一例)
株価データの一例。他サイトなどからダウンロードしたままの CSV ファイル。
入手先ごとに文字コードやファイル形式が統一されていないため、いったん機械学習に用いるフォーマット(csv1.csv)に整形し、使用する。
また、複数のデータを入手して、1つの機械学習用の教師データ(csv1.csv)にまとめ、使用するようにしてもよい。
01_get_profile1.py ダウンロード/入手した CSV ファイルを読み込み、機械学習に必要な項目を抽出、整形し、機械学習用の教師データ(csv1.csv)を出力する。
csv1.csv 機械学習での教師データ用の csv ファイル。ダウンロードしたデータから生成する。
入力データ(col1 ~ col4、年月日と曜日)と正解データ(col5、株価)の両方が入っている。
02_learning1.py 機械学習を実行する python スクリプト。機械学習の学習段階で使う。
教師データ(csv1.csv)を読み込んで機械学習を実行し、学習済みモデルを出力する。
現状では、4つの列(col1 ~ col4)を入力データとし、5つめの列(col5、正解データ)を出力するよう、設定している。スクリプトを修正することで、入力データの項目数(列数)を任意に増減することが可能。
03_generate_date_list1.py 予測をしたい期間に応じて、入力データ(年月日と曜日)のリストを生成するスクリプト。4つの列(col1 ~ col4)の入力データのリストを生成し、予測用のリスト(csv2.csv)として出力する。
予測をする期間を変える場合は、このスクリプトを修正する。
csv2.csv 予測をしたい年月日・曜日を記載したリスト。スクリプトで自動生成する。
教師データ(csv1.csv)と入力データ部分の列の構成(col1 ~ col4、年月日と曜日)が完全に同等となっている。しかし、正解データ(col5)は入っていない。
04_predict1.py 予測用の python スクリプト。機械学習後の使用段階で使う。
予測をしたい年月日のリスト(csv2.csv)を読み込んで、予測を行う。予測した結果は、ファイル(csv3.csv)に出力する。
csv3.csv 機械学習での予測結果を記載したファイル。
指定された年月日、曜日(csv2.csv)に対し、機械学習モデルを使って予測した結果が末尾の列に追記されたものとなっている。

各スクリプトについて

機械学習のスクリプトと予測日について

・ 機械学習のスクリプトの主要部は、末尾の関連リンクに挙げている「CSV ファイルを読み込んで機械学習と予測をする 【scikit-learn】」とほぼ同等です。
・ 上記のスクリプトに加え、ダウンロードした株価データを処理するスクリプトと、予測する日付ファイルを生成するスクリプトの2つを追加しています。

・ 東京証券取引所の営業日は、月~金、祝日を除くとなっています。したがって、ダウンロードした株価データには土日や祝日のデータが含まれていません。土日、祝日についてはデータがないため機械学習ができないという、抜けのあるデータとなっています。
そこで、機械学習は得られたデータのみで行うこととし、株価の予測をおこなう段階では、指定期間のカレンダーから土日を除いたリストを使っています。
つまり、株価予測をする段階では、月曜日から金曜日までの間であれば、取引所が営業していない祝日であっても、強制的に株価予測を実行します。

教師データ(csv1.csv)の生成について

・ ダウンロードした日経平均の日次データ(2022年7月)から、機械学習用の教師データ(csv1.csv)を作成しています。
・ 教師データ(csv1.csv)は、5つの列(col1 ~ col5)としています。5列としたのは一例であり、列の追加は容易です。
・ 前半の4つの列(col1 ~ col4)は、説明変数(入力用データ)であって、順に、年、月、日、曜日の4つに対応しています。
・ 5つめの列(col5)は、目的変数(学習させるデータ)であって、日経平均株価を丸めたものとしています。
具体的には、日経平均株価の終値を所定の価格幅(val1 = 250円、500円、1000円、5,000円)単位で区切って、端数を切り捨てたものを学習用データとします。

株価の端数を丸める理由は、学習、予測する価格幅を必要な程度に調整できるようにし、機械学習の実行時の正解率(score)と予測時の価格幅を微調整できるようにするためです。
具体的には、たとえば、日経平均株価は最近は2万円程度となっており、0.01 円単位で記載されています。この状態のまま機械学習をさせると、7桁分の数値のすべてを予測させることになります。
7桁分の数値を完全に正解する確率は、低い値(数%以下、0に近い値)となります。すると、機械学習実行時にいくらパラメータを振っても正解率を向上させることができなくなります。データを増やしても、有意な特徴をつかむことができなくなり、機械学習が難しくなります。

しかし、株価を予測するにあたっては、0.01 円単位の数値は実用上意味がなく不要です。
一方、たとえば、1万円単位で予測をさせる(1万円単位以下はすべて切り捨てる)ことにしたとします。すると、機械学習の結果はおそらく、現在の平均株価に近い 20,000円を予測し続けることになります。予測は 100% に近い確率で、ほぼ的中するであろうということになります。
実際に、5,000円区切りで教師データを作成して機械学習を実行してみると、98% 前後の正解率(score)となりました。
以降、1,000円、500円、250円区切りで機械学習を実行すると、正解率は次第に下がり、それぞれ、76%、53%、23% 程度となりました。(2022年7月の時点で。なお、機械学習の実行ごとに数%~10%前後の変動、バラつきが生じます。)

細かく的中させようとすると正解が難しくなるため、いくら機械学習を行っても学習が難しくなります。一方、金額の区切りが粗くてよいのであれば、正解しやすくなるため、機械学習時の正解率は上げやすくなります。しかし反面、予測も粗くなるため、予測結果からは有意な情報が得られにくくなります。
したがって、金額の区切りについてはトレードオフの関係があるといえます。そこで、区切り額をスクリプト上で設定できるようにし、ちょうどよいあたりで微調整をすればよいことになります。
実際に株価予測を使う場面では、500円~250円前後の区切り幅の程度で予測ができれば十分と考えられます。そこで、サンプルスクリプトでは val1 = 500円で設定しています。必要により、コメントアウトしている部分を変更し、調整してみてください。

また、教師データ(csv1.csv)で、日経平均株価を 500円単位で丸めた数値を使用しているため、予測データ(csv3.csv)も、500円刻みでの予測をするようになります。
したがって、実際の株価データに比べると、図1の予測データのグラフは500円刻み(ギザギザ)になっています。もっとスムーズなグラフを取得したい場合は、教師データでの500円刻みを 250円等に細かくすることで変更が可能です。
しかしながら上述のとおり、刻み幅を細かくしすぎると、機械学習実施時の正解率が下がって機械学習の効果が下がることになります。いくら学習を繰り返しても、過去の学習データをいくら増やしても、正解率を上げることが難しくなり、過去のデータから特徴を学習する(抽出する)ことが難しくなる、といえます。

日付の生成(csv2.csv)について

スクリプト 03_generate_date_list1.py で、予測を行う年月日、曜日を設定しています。期間を変更する場合は、このスクリプトを修正してください。

スクリプトでは、スクリプトを実行している当日の日付を取得し、この日付の約2年前を開始日、期間を約3年とし、日付データ(csv2.csv)を生成しています。
すでに機械学習済みの過去のデータを出力しているのは、過去のデータについて学習の程度を確認するためです。
出力させる日を固定する場合は、スクリプトでコメントアウトしている部分(2022年7月1日としている行)に差し替え、日付を設定してください。

機械学習を実行している期間については、過去の実際の株価とは完全には一致しませんが、おおかた、過去の株価推移に合った結果となると思います。教師データや機械学習の実行時に異常があれば、わかるようにしています。
後半の1年分については、機械学習を行っていない将来の日付を生成しています。
04_predict1.py を実行すると、このリスト(csv2.csv)に記載されている年月日に対し、株価予測を行います。

考察

全体の推移について

図1で、赤線より右側(2022年7月末以降)が、将来について予測した結果となっています。
将来の日付は、教師データにはもともと入っていません。したがって、学習済みモデルからすると、過去に学習したことのない入力(年月日)に対し、予測している、ということになります。
過去(2022年7月以前)2年分の年月日についても予測をさせています。この期間については機械学習を実行しているため、おおかた、実際の株価変動に対応する結果になっています。

権利落ち日などの再現性について

一例として、配当の権利確定日が集中する、3月末、9月末を確認すると、権利確定日が過ぎて権利落ち日となると、株価が下落する様子が再現できていることがわかります。(予測が的中するかは別として。)
このように、期末になると下落する傾向がある/上昇する傾向があるなどの、一方向の動きをする変動については、過去数年間の傾向を学習し、将来の日付に対しても、その傾向を再現(予測)している、と考えられます。
権利落ちのみならず、日経平均株価の季節性についても、同様に機械学習自体は可能と考えられます。

日経平均株価の予想、推移について

図1を見ると、将来を予測した秋以降(2022年9月から11月)、日経平均の予想額が日々、大きく変動しており、不自然な挙動となっています。つまり、1日ごとの株価変動、株価の飛びが過去に例を見ないほど大きくなっています。
そこで、学習に用いた過去3年の株価推移をみると、2020年はコロナの影響で株価が低迷しており、2020年11月を境に株価が上がり安定しています。2021年はコロナからの回復のため、株価が比較的、高いレンジで推移しています。
これを月別で見ると、月(9月から11月)としては同時期であっても、各年で株価自体が大きく異なっています。こうした飛びのある株価データを用いて機械学習を行ったため、株価予測が大きく変動し、不自然になっていると考えられます。
つまり、各年での日経平均株価が大きく異なると、株価を予想したときのバラつきも当然ながら大きくなるといえます。
こうした影響を低減するには、日経平均株価そのものを機械学習の対象(目的変数)とするのではなく、日々の変動額(例えば、(終値)-(始値)、あるいは変動率)を機械学習の対象とするほうが適していると考えられます(スクリプトの修正も容易です)。日経平均株価の絶対額での縛りがなくなるためです。

しかし、日々の変動額を機械学習の対象とすると、使う場面では参考になりますが、学習対象(日々の変動額)は正負の値をとるため、ランダムノイズ、ランダムウォークのような挙動となります。
すると、日経平均株価が全体としてどう推移するのか把握しづらくなります。
株価予測の全体の推移から機械学習のモデルの妥当性をまずは判断したい、日経平均株価の季節性を含めた全体の推移をまず把握したい、といった目的に対しては適切ではなくなります。
今回のスクリプトは、目的の1つに、シンプルに株価予想をすると何が問題か、課題を抽出することとしています。そこで、問題があることは把握した上で、あえて、この設定としています。

なお、株価の変動額はランダムウォークに似た挙動になっていますが、権利落ち日近辺では株価が下がる傾向がみられるなど、完全なランダムウォークからは少し外れた挙動となっているようです。
いいかえると、完全なランダムから外れた恣意的な売買がされているのであれば(売買の癖を機械学習で見抜くことで)、そこから利益が得られる可能性があると考えられます(同時に、失敗する可能性もあります)。

一過性の社会的な事象の影響について ~ 世界的な危機、ショックの影響

また、図1で、将来の予測(2023年3月近辺)を確認すると、2023年3月9日前後に株価が急落しています。
学習に用いた過去のデータを確認すると、2020年の3月には、コロナウイルスの急拡大により、株価が急落しています。また、2022年の3月には、ウクライナ戦争が開始したことで、株価が急落しています。
こうした、社会的に影響の大きな一過性の出来事があると、再現性のない出来事であるにもかかわらず、機械学習をしてしまうことになります。
こうした学習モデルを用いて将来予測をすると、3月には株価が急落するなどといった”誤った”予想をしやすくなることになります。
今回の学習データの範囲には含まれていませんが、過去、よく知られている世界的な危機、ショックとしては、リーマンショック(2008年)、同時多発テロ(2001年)、アジア通貨危機(1997年)などがあります。

本来は、権利落ちのように毎年、共通して生じる現象と、個別の社会現象とを完全に分離し、共通して生じる現象の部分についてのみ機械学習をさせたいところです。しかし、株価変動の内訳を、要因ごとに完全に分離して抽出することは原理的に難しいであろうことがわかります。

企業業績について

企業業績についても上記と同様のことがいえます。
企業業績の発表が集中する時期には、増配/減配などが公開されます。したがって、株価変動が大きくなりやすいと考えられます。
ところが、たとえば、学習対象を最近の過去3年のデータなどとすると、時期がコロナ収束後の回復時期と重なります。企業業績がコロナ以前の状態に回復しただけであったとしても、学習モデルは、今後も企業決算が改善し続けると予想しやすくなる、と考えられます。(教師用データの年数を増やせば改善できるか。。)
他にも、インフレ/デフレか、円安/円高かなどによっても、売上高や営業利益などの企業業績に影響が生じます。データを取得する時期の取り方によって、予測結果が影響を受けると考えられます。

入力データが必要かつ十分でないと機械学習のモデルが歪むという問題

計算結果を見ると、権利落ち程度であれば、機械学習により下落分をある程度の確度で予測できるのではないかという印象があります。
しかし、企業業績の変動による株価変動は、当然ながら、市場環境(資源高/安、円安/円高など)やその業種により強く影響を受けると考えられます。こうした環境要因は、今回の教師データ(説明変数)には入っていません。

すると本来は、環境要因であったはずの要因を、日付要因とみなして機械学習してしまうことになります。
たとえば、天然ガス高騰による企業業績の悪化があったとし、たまたま高騰が生じたのが4月以降だったとします。ところが、資源価格や企業業績は、入力データ(説明変数)には入っていません。すると、機械学習のモデルは、4月、5月といった時期的要因として価格変動を機械学習してしまうことになります。
必要かつ十分な入力データがそろっていないと、学習モデルが歪んでしまう、妥当なものではなくなるといえます。

理想をいえば、たとえば日経平均株価に一定額(500円等)以上の影響を与えうるすべてのパラメータであって、互いに完全に独立しているものを抽出したいところです。そのパラメータのみをもって(=ノイズは完全に排除して)、株価変動を完全に分解すればよいと考えられます。
しかし、現実には無理があると考えられます。
仮に、たとえ、株価に影響しそうな項目(説明変数)の数を増やしていったとしても、すべてのパラメータ(経営者や社員の能力、営業現場の状況、市場環境、海外の影響、競合との力関係、製品・サービスの品質レベルなど)を、重複することなく、定量的に、取得、設定、網羅するには限界があると考えられます。
どのような機械学習のアルゴリズムを使うにせよ(ランダムフォレストであろうが、Tensorflow であろうが)、株価のように、影響を与えうるパラメータが無数にある場合、常について回る問題といえます。
この点は、将棋やチェスのように、すべての情報が盤面から得られるといった類の問題とは大きく異なっているといえます。

個人的な所感

上記のように、何が可能か、何が問題なのかをハッキリさせて、メリット/デメリットがあることを踏まえた上で予測結果を活用するのであれば、非常に有用といえます。
とくに、株価の増減幅について、過去の事例に基づいた予測が具体的な数値として得られますので、ある程度の確率で許容範囲を超える下落が予測されるとき、先に売却を済ませてしてしまうなど、売買判断の参考にはなると考えられます。

また、入力データの項目数を増やすなど、Python でのプログラミングも容易です。

詳細は省略しますが、米国の恐怖指数(VIX指数)などを入れた機械学習も試しに行ってみました。
前述のとおり、一過性の世界的な危機、ショックについては、季節や時期に対する再現性が乏しいといえます。時間軸を基準とする上記の機械学習のモデルでは扱いにくい側面があります。
これらの事象は、VIX 指数や為替などとの相関を評価しておくなど、世界的な影響度を評価するスクリプトを別途作って、切り分けて分析・評価・予測するようにしたほうがよさそうです。

従来であれば、機関投資家や大手企業でなければできなかったような分析や予測が、個人であっても可能になってきており、着眼点や分野によっては、大手だからといって必ずしも有利だとはいえない状況が生じている、と考えられます。(現状のところ個人的にも、含み損益、売却損益など、プラスになってますし。。)

まとめ

過去の株価推移のデータを使って、機械学習で株価予測を行ってみました。Python のスクリプトをまとめ、株価予測の結果について考察を行いました。

ネット検索をすると、機械学習で株価を扱ったサイトが多数ヒットします。しかしながら、最新の株価データを使って、すぐに動く程度のスクリプトを記載したサイトは少ないようです。また、現状の機械学習の技術について、何が可能か、何が課題か、端的に記載したサイトも少ないようです。
そこで、できるだけシンプルに動くスクリプトと各ポイントについてまとめてみました。

なお、CSVファイルで機械学習を行うスクリプトや、Tensorflow を用いた深層学習のサンプルなどについて、以下の関連リンクにまとめています。もし、関心があるようでしたら、参照してみてください。

関連リンク
・ CSV ファイルを読み込んで機械学習と予測をする 【scikit-learn】
・ Raspberry Pi で物体検出をやってみた 【Tensorflow Lite】
・ フルーツでの物体検出をやってみた 【YOLOv5】
・ スマホ議決権行使をパソコンで行う方法 【QUOカードを当てよう】
・ ConoHa の株主優待の設定をやってみた 【GMOインターネット】

外部リンク
・ 日経平均プロフィル 日経平均株価
★ リンク先の「関連データ」「日次データ(CSV)」となっている欄で、CSV のアイコンをクリックし、日経平均の日次データ “nikkei_stock_average_daily_jp.csv” をダウンロードしてください。
ダウンロードした csv ファイルを上記の “data1” フォルダに入れて、Python のスクリプトを実行することで、機械学習の教師ファイル(csv1.csv)を生成します。
・ JPX日本取引所グループ 営業時間・休業日一覧

サンプルスクリプト

01_get_profile1.py:ダウンロードした株価データから必要な項目を抽出し、教師データ(csv1.csv)を生成するスクリプト


import matplotlib.pyplot as plt1 
import os 
import pandas as pd1 
import glob 
from operator import itemgetter 
import pickle 
from datetime import date 
import copy as cp1 

def read1( file1 ): 
#   with open( file1, 'r', encoding='utf-8' ) as f1: 
    with open( file1, 'r', encoding='shift_jis' ) as f1: 
        str1 = f1.read()
    return str1 

def get_a1( file1 ): 
    a1 = read1( file1 ).strip().replace( "\n\n", "\n" ).replace( " ", "" ).replace( '"', '' ).split( "\n" ) 
    for i1 in range( len( a1 ) ): 
        a1[i1] = a1[i1].split( "," ) 
    return a1 

def write1( file1, str1 ): 
    with open( file1, 'w', encoding='utf-8' ) as f1: 
        f1.write( str1 ) 
    return 0 

def write_html1( file1, a0, a1 ): 
    df1 = pd1.DataFrame( a1 ) 
    if len( a0 ) == len( a1[0] ): 
        df1.columns= a0 
    df1.to_html( file1, escape=False ) 

def get_nikkei1( file1 ): 
    a1 = get_a1( file1 ) 
    a2 = [] 
    ave1 = float( a1[1][1] ) 
    for i1 in range( len(a1)-2 ): 
        val1 = float( a1[i1+1][1] ) 
        val2 = val1/ave1 - 1.0 
        val3 = float( a1[i1+1][2] ) 
        val4 = ( val1 - val3 ) / val3 
        a2.append( [ a1[i1+1][0], val1, round( ave1, 2 ), round( 100.0*val2, 1), round( 100.0*val4, 1 )  ] ) 
        ave1 = 0.99*ave1 + val1*0.01 
    a2.reverse() 
    return a2

def learning_list1( a1 ): 
#   val1 = 5000   # score: 98% 
#   val1 = 1000   # score: 76% 
    val1 =  500   # score: 53% 
#   val1 =  250   # score: 23% 
    a2 = [] 
    for i1 in range( len( a1 ) ): 
        date1 = a1[i1][0].split( "/" ) 
        weekday1 = date( int(date1[0]), int(date1[1]), int(date1[2]) ).weekday() + 1 
        val2 = a1[i1][1] 
        a3 = [ date1[0], date1[1], date1[2], weekday1, int( val2/val1 ) * val1 ] 
        a2.append( a3 ) 
    a2 = [[ "col1", "col2", "col3", "col4", "col5" ]] + a2 
    return a2 

def join1( a1 ): 
    for i1 in range( len( a1 ) ): 
        a1[i1] = ",".join(list(map( str, a1[i1] ))) 
    return "\n".join( a1 ) 

path1 = os.path.dirname(__file__) + "/data1/" 

file1 = path1 + "nikkei_stock_average_daily_jp.csv" 
a1 = get_nikkei1( file1 ) 

file1 = path1 + "nikkei1.html" 
write_html1( file1, [ "date", "nikkei", "average", "ave%", "day%" ], a1 ) 

a2 = learning_list1( a1 ) 

for i1 in range( 10 ): 
    print( a2[i1] ) 

str1 = join1( a2 ) 

file1 = path1 + "csv1.csv" 
write1( file1, str1 ) 

02_learning1.py: 教師データ(csv1.csv)に基づき、機械学習を実行するスクリプト


import os 
import numpy as np1
import pandas as pd1
import joblib as jl1 
import sklearn 
from sklearn.linear_model import LinearRegression
from sklearn.svm import SVC
from sklearn.svm import LinearSVC 
from sklearn.linear_model import LogisticRegression 
from sklearn.neighbors import KNeighborsClassifier 
from sklearn.ensemble import RandomForestClassifier 
from sklearn.model_selection import train_test_split 

def read_csv1( file1 ): 
    return pd1.read_csv( file1 ) 

def split1( csv1, header1, header2 ): 
    csv1 = csv1.reindex( np1.random.permutation( csv1.index ) ).reset_index( drop=True )    # randomize 
    x1 = csv1.loc[:, header1 ]
    y1 = csv1.loc[:, header2 ]
    x1_train, x2_test, y1_train, y2_test = train_test_split( x1, y1, random_state=0 )
    y1_train = y1_train.values.ravel() 
    y2_test  = y2_test.values.ravel() 
    return x1_train, x2_test, y1_train, y2_test

def fit1( x0_train, y0_train, file1, n1 ): 
    if os.path.exists( file1 ): 
        model0 = jl1.load( file1 )
    else: 
        model0 = "" 
    all_models1 = [ 
        model0,                                                                       # 0: only read existing model 
        LinearRegression(),                                                           # 1: linear regression 
        SVC(),                                                                        # 2: support vector machine 
        LinearSVC( max_iter=1000 ),                                                   # 3: linear suppoort vector machine 
        LogisticRegression( max_iter=10000 ),                                         # 4: logistic regression 
        KNeighborsClassifier( n_neighbors = 1 ),                                      # 5: kneighbors classifier 
        RandomForestClassifier(),                                                     # 6: random forest 1 (default) 
        RandomForestClassifier( min_samples_leaf=2, random_state=0, max_depth=100 )   # 7: random forest 2 (customized) 
    ] 
    model1 = all_models1[ n1 ]                                           # fitting model 
    model1.fit( x0_train, y0_train )                                     # learning 
    jl1.dump( model1, file1 )                                            # save the model 
    return model1 

def predict_score1( model1, x0_test, y0_test ): 
    y1_pred = model1.predict( x0_test ) 
    # print( "predict" )
    # print( y1_pred ) 
    # print( type( y1_pred ) ) 
    # print( "answer" )
    # print( y0_test.T )
    # print( y0_test.to_numpy().T[0])
    # print( type( y0_test ) ) 
    return model1.score( x0_test, y0_test )

path1 = os.path.dirname(__file__) + "/data1/" 

file1 = path1 + "csv1.csv" 
csv1 = read_csv1( file1 )                                                 # read csv file 

print( csv1 ) 

header1 = ["col1","col2","col3","col4"]                                   # csv header 1 
header2 = ["col5"]                                                        # csv header 2 

x1_train, x2_test, y1_train, y2_test = split1( csv1, header1, header2 )   # split 

file1 = path1 + 'fitting_model1.sav' 

n1 = 6                                                                    # fitting model 0-7 
model1 = fit1( x1_train, y1_train, file1, n1 )                            # training 

s1 = predict_score1( model1, x2_test, y2_test )                           # test 
print( "score: " + str( s1*100.0 ) + " %"  ) 

03_generate_date_list1.py: 株価予測のための日付リスト(csv2.csv)を生成するスクリプト


import os 
import datetime as dt1 

def write1( file1, str1 ): 
    with open( file1, 'w', encoding='utf-8' ) as f1: 
        f1.write( str1 ) 
    return 0 

def generate_date_list1(): 
    date1 = dt1.datetime.now() 
    # date1 = dt1.date( 2022, 7, 1 ) 
    print( date1 ) 
    del1 = dt1.timedelta( days=1 ) 
    del2 = dt1.timedelta( days=365*2 ) 
    # del2 = dt1.timedelta( days=365 ) 
    # del2 = dt1.timedelta( days=31 ) 
    date2 = date1 - del2 
    # date2 = date1 
    a1 = [] 
    for i1 in range( 365*3 ): 
        y1 = date2.year 
        m1 = date2.month 
        d1 = date2.day 
        wd1= date2.weekday() + 1 
        if wd1 < 6: 
            str1 = str(y1).zfill(4) + "," + str(m1).zfill(2) + "," + str(d1).zfill(2) + "," + str(wd1).zfill(2) 
            a1.append( str1 ) 
        date2 = date2 + del1 
    str1 = "col1,col2,col3,col4\n" + "\n".join( a1 ) 
    return str1 

str1 = generate_date_list1() 

print( str1 ) 

path1 = os.path.dirname(__file__) + "/data1/" 
file1 = path1 + "csv2.csv" 

write1( file1, str1 ) 

04_predict1.py: 日付リスト(csv2.csv)に基づき予想株価(csv3.csv)を出力するスクリプト


import os 
import sklearn 
import pandas as pd1
import joblib as jl1 

def predict1( file1, file2, header1 ): 
    x1 = pd1.read_csv( file1 ).loc[:, header1] 
    model1 = jl1.load( file2 )                                       # load model 
    y1 = model1.predict( x1 )                                        # predict 
    # y1 = ( y1+0.5 ).astype(int) 
    xy1 = x1.assign( col5 = y1 ) 
    return xy1 

def write_csv1( a1, file1 ): 
    return a1.to_csv( file1 ) 

path1 = os.path.dirname(__file__) + "/data1/" 

file1 = path1 + "csv2.csv" 
file2 = path1 + 'fitting_model1.sav' 
header1 = ["col1","col2","col3","col4"]                              # csv header 1 
a1 = predict1( file1, file2, header1 )                               # predict 
print( a1 ) 

file2 = path1 + "csv3.csv"                                           # save the predicted result 
write_csv1( a1, file2 ) 

タイトルとURLをコピーしました