Help us understand the problem. What is going on with this article?

機械学習で競馬予想(その4)

More than 3 years have passed since last update.

はじめに

特にFujitsu Advent Calendar 2016にちなんだ内容でなく、自分の趣味(継続中の開発の続き)を書きます。
※ 当記事は会社を代表するものではなく、個人の意見です。
(本業は新規事業立ち上げなどで開発職ではありません)

継続中の開発

[開発しているSIVAについて]
[facebook]
https://www.facebook.com/AIkeiba/
[Twitter]
https://twitter.com/Siva_keiba
随時実況していきますので、いいね!フォローお願いします。

今回のやること

前回の続き。
ディープラーニング(深層学習)による予測についてのサンプルコードを書きます。

始めるにあたり必要なスキルはこちらを参考してください。

今回のライブラリ

TensorFlow:https://www.tensorflow.org/
前回のデータを使います。
インストール方法は以下の記事などを参考にしてもらえばと思います。

Pythonの環境構築からTensorFlowインストール

予測モデル作成と実験(前と同じです)

以下のプログラムを準備してモデルの作成

用意したデータは以下のCSV(JRA-VANより)

ラベル名 説明
開催日 yyyy-mm-dd
競馬場
レース番号
レース名
コース ダート
周回 ダートか芝の場合、右回りなら「右」、左回りなら「左」
距離 [m]
馬場状態 良(りょう)
賞金 [万円]
頭数
着順
枠番
馬番
馬名
性別
年齢
騎手
タイム [s]
着差 前着の馬との差のこと,クビ,
通過順
上り3F ラスト600mのタイム[s]
斥量 [kg]
馬体重 [kg]
増減 前レースからの馬体重変化[kg]
人気 oddsの降順の番号
オッズ
ブリンカー ブリンカー(目隠し)ありの場合、「B」
調教師
調教コメント
調教評価

※ブリンカー、調教師、調教コメント以外をパラメータにしてます。

予測プログラム(trainNN.py)

データと合わせてGitにあげときました。

# -*- coding: utf-8 -*-
import csv
import random
import numpy as np
import pandas as pd
import tensorflow as tf
from sklearn.cross_validation import train_test_split
from sklearn.feature_extraction import DictVectorizer
from sklearn import preprocessing

class TrainNN:

  def __init__(self) : 
    # Parameters
    self.learning_rate = 0.01     # 学習率 高いとcostの収束が早まる
    self.training_epochs = 50     # 学習全体をこのエポック数で区切り、区切りごとにcostを表示する

    self.batch_choice = 500
    self.batch_size = 0           # 学習1回ごと( sess.run()ごと )に訓練データをいくつ利用するか
    self.display_step = 1         # 1なら毎エポックごとにcostを表示
    self.train_size = 500         # 全データの中でいくつ訓練データに回すか
    self.step_size =  500         # 何ステップ学習するか

    # Network Parameters
    self.n_hidden_1 = 64      # 隠れ層1のユニットの数
    self.n_hidden_2 = 64      # 隠れ層2のユニットの数

    self.n_input = 27          # 与える変数の数
    self.n_classes = 0        # 分類するクラスの数

  def load_csv(self):
    file_name = "data/jra_race_resultNN.csv"
    df = pd.read_csv(file_name)
    ## 文字列の数値化
    labelEncoder = preprocessing.LabelEncoder()
    df['area_name'] = labelEncoder.fit_transform(df['area_name'])
    df['race_name'] = labelEncoder.fit_transform(df['race_name'])
    df['track'] = labelEncoder.fit_transform(df['track'])
    df['run_direction'] = labelEncoder.fit_transform(df['run_direction'])
    df['track_condition'] = labelEncoder.fit_transform(df['track_condition'])
    df['horse_name'] = labelEncoder.fit_transform(df['horse_name'])
    df['horse_sex'] = labelEncoder.fit_transform(df['horse_sex'])
    df['jockey_name'] = labelEncoder.fit_transform(df['jockey_name'])
    df['margin'] = labelEncoder.fit_transform(df['margin'])
    df['is_blinkers'] = labelEncoder.fit_transform(df['is_blinkers'])
    df['trainer_name'] = labelEncoder.fit_transform(df['trainer_name'])
    df['comments_by_trainer'] = labelEncoder.fit_transform(df['comments_by_trainer'])
    df['evaluation_by_trainer'] = labelEncoder.fit_transform(df['evaluation_by_trainer'])
    df['dhorse_weight'] = labelEncoder.fit_transform(df['dhorse_weight'])
    x_np = np.array(df[['area_name', 'race_number', 'race_name', 'track', 'run_direction',
                       'distance', 'track_condition', 'purse', 'heads_count', 
                       'post_position', 'horse_number', 'horse_name', 'horse_sex', 'horse_age', 
                       'jockey_name', 'time', 'margin', 'time3F', 
                       'load_weight', 'horse_weight', 'dhorse_weight', 'odds_order', 
                       'odds', 'is_blinkers', 'trainer_name', 'comments_by_trainer', 
                        'evaluation_by_trainer'
    ]].fillna(0))
    # 結果
    d = df[['finish_order']].to_dict('record')

    self.vectorizer = DictVectorizer(sparse=False)
    y_np = self.vectorizer.fit_transform(d)
    self.n_classes = len(self.vectorizer.get_feature_names())

    # データを訓練データとテストデータに分ける
    [self.x_train, self.x_test] = np.vsplit(x_np, [self.train_size]) 
    [self.y_train, self.y_test] = np.vsplit(y_np, [self.train_size])
    self.batch_size = self.train_size

  # Create model
  def multilayer_perceptron(self, x, weights, biases):
    # Hidden layer with RELU activation
    layer_1 = tf.add(tf.matmul(x, weights['h1']), biases['b1'])
    layer_1 = tf.nn.relu(layer_1)
    # Hidden layer with RELU activation
    layer_2 = tf.add(tf.matmul(layer_1, weights['h2']), biases['b2'])
    layer_2 = tf.nn.relu(layer_2)
    # Output layer with linear activation
    out_layer = tf.matmul(layer_2, weights['out']) + biases['out']
    return out_layer

  def train(self) :
    # tf Graph input
    x = tf.placeholder("float", [None, self.n_input])
    y = tf.placeholder("float", [None, self.n_classes])

    # Store layers weight & bias
    weights = {
      'h1': tf.Variable(tf.random_normal([self.n_input, self.n_hidden_1]), name="h1"),
      'h2': tf.Variable(tf.random_normal([self.n_hidden_1, self.n_hidden_2]), name="h2"),
      'out': tf.Variable(tf.random_normal([self.n_hidden_2, self.n_classes]), name="wout")
    }
    # バイアスの設定
    biases = {
      'b1': tf.Variable(tf.random_normal([self.n_hidden_1]), name="b1"),
      'b2': tf.Variable(tf.random_normal([self.n_hidden_2]), name="b2"),
      'out': tf.Variable(tf.random_normal([self.n_classes]), name="bout")
    }

    # Construct model
    pred = self.multilayer_perceptron(x, weights, biases)

    # Define loss and optimizer
    cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(pred, y))

    correct_prediction = tf.equal(tf.argmax(pred, 1), tf.argmax(y, 1))
    accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))

    # Logistic Regression  AdamOptimizer GradientDescentOptimizer
    optimizer = tf.train.AdamOptimizer(learning_rate=self.learning_rate).minimize(cost)

    # Initializing the variables
    init = tf.initialize_all_variables()
    saver = tf.train.Saver()
    # Launch the graph

    with tf.Session() as sess:
      tf.scalar_summary("cost", cost)
      tf.scalar_summary("accuracy", accuracy)
      merged = tf.merge_all_summaries()
      writer = tf.train.SummaryWriter("logs/tensorflow_log", sess.graph_def)    

      sess.run(init)
      # Training cycle
      for epoch in range(self.training_epochs):
        avg_cost = 0.
        # Loop over step_size
        for i in range(self.step_size):
          # 訓練データから batch_size で指定した数をランダムに取得
          ind = np.random.choice(self.batch_size, self.batch_choice)
          x_train_batch = self.x_train[ind]
          y_train_batch = self.y_train[ind]
          # Run optimization op (backprop) and loss op (to get loss value)
          _, c = sess.run([optimizer, cost], feed_dict={x: x_train_batch, y: y_train_batch})
          avg_cost += c / self.step_size

        # Display logs per epoch step
        if epoch % self.display_step == 0:
          print "Epoch:", '%04d' % (epoch+1), "cost=", "{:.9f}".format(avg_cost)
          # Compute average loss
          summary_str, acc = sess.run([merged, accuracy], feed_dict={x: x_train_batch, y: y_train_batch})
          writer.add_summary(summary_str, epoch)
          print "Accuracy:", acc
          ## modelの保存
          # name_model_file = 'model_epoch_' + str(epoch+1) + '.ckpt'
          # save_path = saver.save(sess, 'model/tensorflow/' + name_model_file)

      # Test model
      correct_prediction = tf.equal(tf.argmax(pred, 1), tf.argmax(y, 1))
      # Calculate accuracy
      accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
      print "Accuracy:", accuracy.eval(session=sess, feed_dict={x: self.x_test, y: self.y_test})

if __name__ == "__main__":
  trainNN = TrainNN()
  trainNN.load_csv()
  trainNN.train()

※ pythonおよびデTensorFlowについては勉強中ですのでプログラムに誤りがあるかもです。

結果

$ python trainNN.py 
Epoch: 0001 cost= 28999.539070313
Accuracy: 0.183333
Epoch: 0002 cost= 10636.817809570
Accuracy: 0.146667
Epoch: 0003 cost= 8187.893877930
Accuracy: 0.216667
Epoch: 0004 cost= 6673.761091797
Accuracy: 0.183333
Epoch: 0005 cost= 5364.944535645
Accuracy: 0.196667
Epoch: 0006 cost= 4300.876705078
Accuracy: 0.176667
Epoch: 0007 cost= 3560.373814697
Accuracy: 0.27
Epoch: 0008 cost= 2843.689293701
Accuracy: 0.203333
Epoch: 0009 cost= 1605.616168819
Accuracy: 0.1
Epoch: 0010 cost= 21.059406254
Accuracy: 0.0666667
Epoch: 0011 cost= 9.320877672
Accuracy: 0.0566667
Epoch: 0012 cost= 5.621849694
Accuracy: 0.0866667
Epoch: 0013 cost= 4.749191205
Accuracy: 0.07
Epoch: 0014 cost= 4.069611630
Accuracy: 0.0733333
Epoch: 0015 cost= 3.946254434
Accuracy: 0.0566667
Epoch: 0016 cost= 3.253856863
Accuracy: 0.0433333
Epoch: 0017 cost= 3.309734127
Accuracy: 0.07
Epoch: 0018 cost= 2.978426178
Accuracy: 0.0566667
Epoch: 0019 cost= 2.970437231
Accuracy: 0.0533333
Epoch: 0020 cost= 2.999267270
Accuracy: 0.0566667
Epoch: 0021 cost= 3.828851234
Accuracy: 0.0766667
Epoch: 0022 cost= 2.859027134
Accuracy: 0.0666667
Epoch: 0023 cost= 2.799751988
Accuracy: 0.08
Epoch: 0024 cost= 2.799972694
Accuracy: 0.06
Epoch: 0025 cost= 2.799448245
Accuracy: 0.0633333
Epoch: 0026 cost= 2.799542419
Accuracy: 0.06
Epoch: 0027 cost= 2.798464981
Accuracy: 0.0933333
Epoch: 0028 cost= 2.799431955
Accuracy: 0.07
Epoch: 0029 cost= 2.798901843
Accuracy: 0.05
Epoch: 0030 cost= 2.797275106
Accuracy: 0.0366667
Epoch: 0031 cost= 2.799933175
Accuracy: 0.0566667
Epoch: 0032 cost= 2.799303545
Accuracy: 0.07
Epoch: 0033 cost= 2.799922926
Accuracy: 0.0533333
Epoch: 0034 cost= 2.799450584
Accuracy: 0.0833333
Epoch: 0035 cost= 2.800814153
Accuracy: 0.08
Epoch: 0036 cost= 2.799030569
Accuracy: 0.0733333
Epoch: 0037 cost= 2.799764482
Accuracy: 0.0566667
Epoch: 0038 cost= 2.799920460
Accuracy: 0.0833333
Epoch: 0039 cost= 2.799320694
Accuracy: 0.09
Epoch: 0040 cost= 2.800959777
Accuracy: 0.0766667
Epoch: 0041 cost= 2.799612596
Accuracy: 0.09
Epoch: 0042 cost= 2.800021134
Accuracy: 0.0666667
Epoch: 0043 cost= 2.799918224
Accuracy: 0.0666667
Epoch: 0044 cost= 2.799846961
Accuracy: 0.06
Epoch: 0045 cost= 2.799782973
Accuracy: 0.06
Epoch: 0046 cost= 2.798343555
Accuracy: 0.0633333
Epoch: 0047 cost= 2.800401002
Accuracy: 0.0633333
Epoch: 0048 cost= 2.799323093
Accuracy: 0.06
Epoch: 0049 cost= 2.799231728
Accuracy: 0.0733333
Epoch: 0050 cost= 2.800211056
Accuracy: 0.0633333
Accuracy: 0.0697074

$ tensorboard --logdir=logs/

tensorboard

Screen Shot 0028-12-17 at 23.12.08.png

Screen Shot 0028-12-17 at 23.13.23.png

0.6%。。。全くあたりませんね(笑)
※ もちろんですがSIVAで開発しているアルゴリズムは全く違います。
もう少し勉強してまた書きます!

さいごに(ご参考)

SIVAについては的中率は約40%で回収率は安定して100%前後です。

CzMZW9OUkAAab_1.jpg

[開発しているSIVAについて]
[facebook]
https://www.facebook.com/AIkeiba/
[Twitter]
https://twitter.com/Siva_keiba
随時実況していきますので、いいね!フォローお願いします。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした