2017年10月24日火曜日

人工知能の学習データの量と正解率

女子競艇レースの予測にレーサーの勝率を使用した場合

https://python-8.blogspot.jp/2017/10/python.htmlの続きでレース予測に使用する学習用データを増やし場合の予測結果をまとめました。

学習用データ 学習データ数 検証 正解率
2015~2016年 3427 381 48%
2016年 1785 199 52%
2016年後半のみ 900 100 49%

上図の通り女子競艇レースの結果を2015~2016年、2016年、2016年後半のみの3種類を学習用データとして与え、正解率への影響を調べてみました。学習データにはレーサーの勝率のみを使用しています。予測プログラムは以下の通りになります。


from keras.models import Sequential
from keras.layers.core import Dense, Dropout, Activation
from keras.callbacks import EarlyStopping
import pandas as pd, numpy as np
import psycopg2,sys

class SQL:
    """ SQL script """
    def __init__(self) :
        self.SQL = "SELECT COUNT(*) "
        self.SQL = self.SQL + "FROM SAMPLE_1 ;"
    def pastData(self,date) :
        self.SQL = "SELECT * "
        self.SQL = self.SQL + "FROM SAMPLE_1 "
        self.SQL = self.SQL + "WHERE DATE_PART('YEAR',date) = '"
        self.SQL = self.SQL + date
        self.SQL = self.SQL + "' ORDER BY date ;"
    def predictData(self,date):
        self.SQL = "SELECT * "
        self.SQL = self.SQL + "FROM SAMPLE_1 "
        self.SQL = self.SQL + "WHERE date = '"
        self.SQL = self.SQL + date
        self.SQL = self.SQL + "' ;"

def execute_SQL_pandas(SQL) :
    """ Read race result from DataBase """
    try :
        conn = psycopg2.connect(database="ddddddd", user="uuuuu", password="xxxxx", host="127.0.0.1", port="oooo")    
        results = pd.read_sql(SQL,conn)        
        return results
    except psycopg2.OperationalError as e:        
        print('Unable to connect!\n{0}').format(e)
        sys.exit(1)    
    finally:
        if conn:
            conn.close()

def predict(pastData,predictData) :
    """Predict boat race """
    #過去のレース結果にこれから始まるデータを追加する
    pastData = pastData.append(predictData, ignore_index=True)
    #レーサー毎の勝率を正規化する
    pastData["white_racer"] /= max(pastData['white_racer']) 
    pastData["black_racer"] /= max(pastData['black_racer']) 
    pastData["red_racer"] /= max(pastData['red_racer']) 
    pastData["blue_racer"] /= max(pastData['blue_racer']) 
    pastData["yellow_racer"] /= max(pastData['yellow_racer']) 
    pastData["green_racer"] /= max(pastData['green_racer']) 
    #学習用のデータを一つにまとめる
    inputData = pastData[["white_racer",
                          "black_racer",
                          "red_racer",
                          "blue_racer",
                          "yellow_racer",
                          "green_racer"
                  ]].as_matrix()
    #結果の識別(今回は6種類)
    label_no = 6
    label = {"1":[1,0,0,0,0,0], 
             "2":[0,1,0,0,0,0], 
             "3":[0,0,1,0,0,0], 
             "4":[0,0,0,1,0,0], 
             "5":[0,0,0,0,1,0],
             "6":[0,0,0,0,0,1]}
    #結果をラベルに置き換える
    resultLabel = np.empty((len(pastData),label_no))
    for i, v in enumerate(pastData["result"]):
        resultLabel[i] = label[v]
    #訓練データとテストデータを分ける 
    n = int(len(pastData)/3)*2 + 1
    trainIn, trainLabel = inputData[1:n], resultLabel[1:n]
    testIn,  testLabel  = inputData[n:len(pastData)-12], resultLabel[n:len(pastData)-12] 


    #モデルの構造を定義
    model = Sequential()
    model.add(Dense(512, input_shape=(6,)))
    model.add(Activation('relu'))
    model.add(Dropout(0.1))

    model.add(Dense(512))
    model.add(Activation('relu'))
    model.add(Dropout(0.1))

    model.add(Dense(label_no))
    model.add(Activation('softmax'))

    #モデルを構築
    model.compile(
        loss='categorical_crossentropy',
        optimizer="rmsprop",
        metrics=['accuracy'])

    #データで訓練開始
    model.fit(
        trainIn, trainLabel,
        batch_size=100,
        nb_epoch=20,
        validation_split=0.1,
        callbacks=[EarlyStopping(monitor='val_loss', patience=2)],
        verbose=1)

    #モデルの評価を開始
    score = model.evaluate(testIn, testLabel)
    #レースの予想を開始
    predictInData = inputData[len(pastData)-12:len(pastData)]
    predictions = model.predict(predictInData)
    
    return score,predictions

if __name__ == '__main__':
    
    #2015年のレース結果をデータベースから読み出す
    sql = SQL()
    sql.pastData('2015')
    pastData2015 = execute_SQL_pandas(sql.SQL)

    #2016年のレース結果をデータベースから読み出す
    sql.pastData('2016')
    pastData2016 = execute_SQL_pandas(sql.SQL)
    
    #2015年と2016年のレース結果を結合する
    pastData = pastData2015.append(pastData2016, ignore_index=True)
    
    #予想するレースのデータをデータベースから読み出す
    sql.predictData('2017-01-14')
    predictData = execute_SQL_pandas(sql.SQL)
    #予想する
    score,predictions = predict(pastData,predictData)
    

    

学習データを増やしても正解率は改善しない

2015~2016年の2年分のレース結果を学習データに使用した場合の結果。


Train on 3427 samples, validate on 381 samples
Epoch 1/20
3427/3427 [==============================] - 1s - loss: 1.3895 - acc: 0.4835 - val_loss: 1.3966 - val_acc: 0.4646
Epoch 2/20
3427/3427 [==============================] - 1s - loss: 1.3169 - acc: 0.5001 - val_loss: 1.3206 - val_acc: 0.4987
Epoch 3/20
3427/3427 [==============================] - 1s - loss: 1.3072 - acc: 0.5042 - val_loss: 1.2881 - val_acc: 0.5459
Epoch 4/20
3427/3427 [==============================] - 1s - loss: 1.2989 - acc: 0.5066 - val_loss: 1.3045 - val_acc: 0.5013
Epoch 5/20
3427/3427 [==============================] - 1s - loss: 1.2977 - acc: 0.5127 - val_loss: 1.2742 - val_acc: 0.5381
Epoch 6/20
3427/3427 [==============================] - 1s - loss: 1.2947 - acc: 0.5083 - val_loss: 1.2805 - val_acc: 0.5249
Epoch 7/20
3427/3427 [==============================] - 1s - loss: 1.2891 - acc: 0.5153 - val_loss: 1.2683 - val_acc: 0.5512
Epoch 8/20
3427/3427 [==============================] - 1s - loss: 1.2861 - acc: 0.5185 - val_loss: 1.2708 - val_acc: 0.5276
Epoch 9/20
3427/3427 [==============================] - 1s - loss: 1.2853 - acc: 0.5147 - val_loss: 1.2687 - val_acc: 0.5302
Epoch 10/20
3427/3427 [==============================] - 1s - loss: 1.2810 - acc: 0.5142 - val_loss: 1.2799 - val_acc: 0.5249
1856/1891 [============================>.] - ETA: 0saccuracy= 0.499206768921
    



2016年後半のみを学習データとして与えて予測を実施。


if __name__ == '__main__':
    
    #過去のレース結果をデータベースから読み出す
    sql = SQL()
    
    sql.pastData('2016')
    pastData2016 = execute_SQL_pandas(sql.SQL)
            
    #予想するレースのデータをデータベースから読み出す
    sql.predictData('2017-01-14')
    predictData = execute_SQL_pandas(sql.SQL)
    #予想する
    score,predictions = predict(pastData2016[1476:],predictData)
    
    print('accuracy=', score[1])


    

2016年後半のみを学習データとして与えて予測を実施した結果。


Train on 900 samples, validate on 100 samples
Epoch 1/20
900/900 [==============================] - 0s - loss: 1.5447 - acc: 0.4044 - val_loss: 1.3123 - val_acc: 0.6100
Epoch 2/20
900/900 [==============================] - 0s - loss: 1.4403 - acc: 0.4578 - val_loss: 1.2292 - val_acc: 0.6200
Epoch 3/20
900/900 [==============================] - 0s - loss: 1.3868 - acc: 0.4778 - val_loss: 1.1930 - val_acc: 0.6200
Epoch 4/20
900/900 [==============================] - 0s - loss: 1.3804 - acc: 0.4722 - val_loss: 1.1864 - val_acc: 0.6000
Epoch 5/20
900/900 [==============================] - 0s - loss: 1.3791 - acc: 0.4700 - val_loss: 1.2399 - val_acc: 0.5700
Epoch 6/20
900/900 [==============================] - 0s - loss: 1.3706 - acc: 0.4722 - val_loss: 1.2084 - val_acc: 0.6000
Epoch 7/20
900/900 [==============================] - 0s - loss: 1.3515 - acc: 0.4756 - val_loss: 1.2319 - val_acc: 0.5600
480/487 [============================>.] - ETA: 0saccuracy= 0.498973306138
    

今回はレーサーの勝率のみで予測しているので、与える入力データとレース結果との因果関係により必要なデータ量にも影響を与える可能性があるので引き続き検証を続ける。