2019年7月30日火曜日

Kerasによるニューラルネットワークモデルの構築方法

概要

Kerasによるニューラルネットワークモデルの構築方法素のメモです。

用語

・Anaconda:データサイエンスおよび機械学習関連アプリケーション(大規模データ処理、予測分析、科学計算)のためのPythonおよびRプログラミング言語のフリーでオープンソースのディストリビューション
・Python:機械学習プログラミングに人気のプログラミング言語。
・Keras:Pythonで書かれたオープンソースニューラルネットワークライブラリ。tensorflowをラッピングして作られている。
・ニューラルネットワーク:脳機能を模して考案された機械学習のアルゴリズムの1つ。
・xlrd:pythonでxlsxファイルを読み書きするためのライブラリ

事前準備(前提とする環境)

・Windows10 Professional
・Anaconda
・Python3(バージョン3.7.2)
・Keras2.1.5

手順

学習させるデータ

学習の題材には日経平均株価を扱いたいと思います。そこで、日経平均株価の情報をエクセル形式で準備します。 説明変数は、「日付」「終値」「始値」「高値」「安値」「前日比」「5日移動平均」「25日移動平均」「75日移動平均」「14日RSI」です。予測値は、「翌日の日経平均株価」です。
用意するデータ
ファイル論理名 ファイル物理名 概要
日経平均株価学習データ nikkei225.xlsx ニューラルネットワークモデルに学習させるデータセット
日経平均データファイル定義 nikkei225_def.xlsx データセットのファイル定義
日経平均株価学習結果テストデータ nikkei225_test.xlsx 学習結果のテスト用データ

xlrdのインストール

xlrdをインストールします。xlrdを用いて、エクセル形式の日経平均株価を読み込みます。
$ pip install xlrd

エクセルデータ読み込みプログラム作成(importXLSX.py)

まずはxlsファイルを読み込み、0~1の値に正規化するプログラムを作成します。
著者のプログラム能力不足により若干残念ですが、例えば以下みたいな感じで。
import pandas as pd
import keras
from keras.preprocessing.text import one_hot

# dateFlg:0の場合->日付データをそのまま学習、1の場合->日付データは無視して学習
# stringFlg:0の場合->文字列データをそのまま学習、1の場合->文字列データは無視して学習
def getData(fileDefinition, filename, dateFlg, stringFlg, superviser):
    # xlsxファイルの定義ファイルの読み込みを行う
    csv_def = pd.read_excel(fileDefinition, encoding='utf-8')

    # xlsxファイルの読み込みを行う
    csv_data = pd.read_excel(filename, encoding='utf-8')

    # 正規化処理(型毎に0~1の値になるように正規化)
    for raw in csv_def:
        array = []

        # Date型の場合
        if(csv_def[raw][0] == 'Date'):
            max = 0
            min = 9999999
            for value in csv_data[raw]:
                if dateFlg == 0:
                    if pd.isnull(value):
                        tmpValue = -1
                    else:
                        tmpValue = one_hot(value, len(csv_data[raw]) + 1)[0]
                    # 正規化するための最大値取得
                    if max < tmpValue:
                        max = tmpValue
                    # 正規化するための最小値取得
                    if min > tmpValue:
                        min = tmpValue
                else:
                    tmpValue = 0
                array.append(tmpValue)

        # float型の場合
        elif(csv_def[raw][0] == 'float'):
            max = 0.0
            min = 9999999.999
            for value in csv_data[raw]:
                if pd.isnull(value):
                    tmpValue = 0.0
                else:
                    tmpValue = value
                # 正規化するための最大値取得
                if max < tmpValue:
                    max = tmpValue
                # 正規化するための最小値取得
                if min > tmpValue:
                    min = tmpValue
                array.append(tmpValue)

        # long型の場合
        elif(csv_def[raw][0] == 'long'):
            max = 0
            min = 9999999
            for value in csv_data[raw]:
                if pd.isnull(value):
                    tmpValue = 0.0
                else:
                    tmpValue = value
                # 正規化するための最大値取得
                if max < tmpValue:
                    max = tmpValue
                # 正規化するための最小値取得
                if min > tmpValue:
                    min = tmpValue
                array.append(tmpValue)

        # String型の場合
        if(csv_def[raw][0] == 'String'):
            max = 0
            min = 9999999
            for value in csv_data[raw]:
                if stringFlg == 0:
                    if pd.isnull(value):
                        tmpValue = -1
                    else:
                        tmpValue = one_hot(value, len(csv_data[raw]) + 1)[0]
                    # 正規化するための最大値取得
                    if max < tmpValue:
                        max = tmpValue
                    # 正規化するための最小値取得
                    if min > tmpValue:
                        min = tmpValue
                else:
                    tmpValue = 0
                array.append(tmpValue)

        # 学習データの場合は0~1の値に正規化を行う
        result = []
        if max != 0 and raw != superviser:
            if max == min:
                min = 0
            for value in array:
                result.append((value - min) / (max - min))
        else:
            result = array

        csv_data[raw] = result

    print(csv_data)

    return csv_data

def setSupData(superviser, data):
    svData = pd.DataFrame()
    lnData = pd.DataFrame()
    for raw in data:
        if raw == superviser:
            # 指定されたカラムの場合は教師データとして扱う
            svData[raw] = data[raw]
        else:
            # 指定されたカラム以外の場合は学習データとして扱う
            lnData[raw] = data[raw]

    return lnData, svData

# このプログラム単体でも実行可能です
if __name__ == '__main__':
    data = getData('nikkei225_def.xlsx', 'nikkei225.xlsx', 1, 1, '翌日日経平均')

モデル作成プログラム作成(createModel.py)

続いて、ニューラルネットワークモデルをプログラムを作成します。
著者のプログラム能力不(ry
実行が完了すると、「nikkei225.h5」というファイルが生成されます(これがニューラルネットワークモデルになります)。
import sys
import datetime
import importXLSX as ic
from keras.models import Sequential
from keras.layers import Dense, Dropout, BatchNormalization

def getData(fileDefinition, trainFilename, testFileName, superviser):
    # 入力データの作成 -------------------------------------------------------------------------
    # 入力データの全件取得
    print(datetime.datetime.today(), ' トレーニング用データの取得を開始します')
    trainData = ic.getData(fileDefinition, trainFilename, 1, 1, superviser)

    # 学習データと教師データの作成(Pandas)
    print(datetime.datetime.today(), ' トレーニング用データから学習データと教師データを作成します')
    x_train, y_train = ic.setSupData(superviser, trainData)

    # テストデータの作成 -----------------------------------------------------------------------
    # テスト用データの全件取得
    print(datetime.datetime.today(), ' テスト用データを作成します')
    testData = ic.getData(fileDefinition, testFileName, 1, 1, superviser)

    # テストデータと正解データの作成(Pandas)
    print(datetime.datetime.today(), ' テスト用データからテストデータと正解データを作成します')
    x_test, y_test = ic.setSupData(superviser, testData)

    return x_train, y_train, x_test, y_test


def createModel(x_train, y_train, x_test, y_test):
    '''
    モデルの作成
    '''
    print(datetime.datetime.today(), ' モデルを作成します')
    model = Sequential()

    model.add(Dense(x_train.shape[1], activation='sigmoid'))
    model.add(BatchNormalization())
    model.add(Dropout(0.8))
    model.add(Dense(179, activation='sigmoid'))
    model.add(BatchNormalization())
    model.add(Dropout(0.8))
    model.add(Dense(179, activation='sigmoid'))
    model.add(BatchNormalization())
    model.add(Dropout(0.8))
    model.add(Dense(1))

    model.compile(loss='mean_squared_error', optimizer='adam')
    model.fit(x_train.values, y_train.values, epochs=500, batch_size=32, verbose=1, validation_split=0.1)
    score = model.evaluate(x_test.values, y_test.values, verbose=0)
    print('Test MSE : ', score)

    return model


def main(fileDefinition, trainFilename, testFileName, modelName, superviser):
    # パラメータの表示
    print(datetime.datetime.today(), ' fileDefinition(データ定義) : ', fileDefinition)
    print(datetime.datetime.today(), ' trainFilename(トレーニングデータ) : ', trainFilename)
    print(datetime.datetime.today(), ' testFileName(テストデータ) : ', testFileName)
    print(datetime.datetime.today(), ' modelName(作成するモデル名称) : ', modelName)
    print(datetime.datetime.today(), ' superviser(予測対象項目) : ', superviser)

    # 入力データとテストデータの作成
    x_train, y_train, x_test, y_test = getData(fileDefinition, trainFilename, testFileName, superviser)

    # モデルの作成
    model = createModel(x_train, y_train, x_test, y_test)

    # モデルの保存
    print(datetime.datetime.today(), ' モデルを保存します')
    model.save(modelName)


# 動かす際は、下記コメントアウト内の文字列をコマンドライン引数として与えてください
# python createModel.py nikkei225_def.xlsx nikkei225.xlsx nikkei225_test.xlsx nikkei225.h5 翌日日経平均
if __name__ == '__main__':
    args = sys.argv
    main(args[1], args[2], args[3], args[4], args[5])

計算実行プログラム(run.py)

最後に、作成したニューラルネットワークモデルを用いて予測を実行します。
import sys
import datetime
import importXLSX as ic
import keras
from keras.models import load_model

def main(modelName, fileDefinition, preFileName, superviser):
    '''
    パラメータの表示
    '''
    print(datetime.datetime.today(), ' modelName(用いるモデル名称) : ', modelName)
    print(datetime.datetime.today(), ' fileDefinition(データ定義) : ', fileDefinition)
    print(datetime.datetime.today(), ' preFileName(検証データ) : ', preFileName)
    print(datetime.datetime.today(), ' superviser(予測対象項目) : ', superviser)

    '''
    予測データの取得
    '''
    # 予測データの取得
    preData = ic.getData(fileDefinition, preFileName, 1, 1, superviser)

    x_pre, dummy = ic.setSupData(superviser, preData)

    '''
    モデルの作成
    '''
    # モデル生成
    model = load_model(modelName)

    '''
    予測の実行
    '''
    predicted = model.predict(x_pre) 
    print(predicted)

# python rarun.py nikkei225.h5 nikkei225_def.xlsx nikkei225_test.xlsx 翌日日経平均
if __name__ == '__main__':
    args = sys.argv
    main(args[1], args[2], args[3], args[4])
結果は以下のコマンドラインの値になります。日経平均予測に必要なデータ項目も全然足りていないし、ニューラルネットワークのハイパーパラメーターのチューニングも全然していないため、予測値がマイナスになるものもあり全然です。が、Kerasの使い方はこんな感じです。
>
$ python rarun.py nikkei225.h5 nikkei225_def.xlsx nikkei225_test.xlsx 翌日日経平均
Using TensorFlow backend.
2019-05-24 17:44:41.663010  modelName(用いるモデル名称) :  nikkei225.h5
2019-05-24 17:44:41.665976  fileDefinition(データ定義) :  nikkei225_def.xlsx
2019-05-24 17:44:41.665976  preFileName(検証データ) :  nikkei225_test.xlsx
2019-05-24 17:44:41.666974  superviser(予測対象項目) :  翌日日経平均
2019-05-24 17:44:42.156586: I tensorflow/core/platform/cpu_feature_guard.cc:140] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX AVX2
[[ 10371.795 ]
 [-50451.01  ]
 [ 17245.732 ]
 [   523.5143]
 [ 16382.622 ]
 [ 15044.639 ]
 [ -6003.2383]
 [-17564.129 ]
 [ -4260.0283]
 [ 17274.5   ]
 [ 17795.049 ]
 [ 18401.918 ]
 [ 19743.291 ]
 [  4336.625 ]
 [ 22392.877 ]
 [ 22660.785 ]
 [ 23163.428 ]
 [ 22441.758 ]]

0 件のコメント:

コメントを投稿

FX自動トレード_2021年6月実績

      概要 2021年6月が終わり、FX自動トレードによる収益実績を取り纏めましたので振り返ってみたいと思います。 2021年6月結果 2021年6月の実績は、実利利益額:\66,761、実績利益率は1.42%でした。 今月もボラが全く出ず。利益率の連続過去最低記録更新は免...