Python
機械学習
scikit-learn
人工知能
ビッグデータ

機械学習の開発内容について(Example)

More than 1 year has passed since last update.

はじめに

前回ブログに書いた内容の実際の開発内容(※)を書きます。

機械学習を始めるのに重要なこと!!

・明確に勉強する目的を持つこと!

勉強してみようくらいの感覚では続きません。

・本当にやるなら自分で勉強すること

人に聞いても断片的になるので出来たつもりになってしまう。
また、その道の技術者に聞いても、ものすごく難しいことから入り何を言ってるのかすら理解出きないことが多いです(笑)自分だけかもですが。。。
ある公式を新しい公式で説明されても・・・って感じでした!

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

では、本題へ!

機械学習のはじめの一歩(マーケティング)

※※※ 機械学習の開発に至ったきっかけは最後にかきました ※※※

競馬予想の機械学習を始めるのに当たり先ずは対象となる情報集めをしました。
自分は競馬が全然わからず、興味もなかったので全然わかりませんでしたが、いろいろな人が実際に試している情報がネット上にあったので参考にしました。

http://stockedge.hatenablog.com/entry/2016/01/03/103428
http://www.mm-lab.jp/analysis/expect_the_arima_kinen_in_multiple_regression_analysis/

競馬のデータ収集(データ収集)

Facebookでいろいろな人に聞いてみたら、天気や馬の性別、馬の年齢、過去のレース情報が必要と聞きましたので、そちらを集めることに。

幸いデータを集めている人を発見したので、データをもらってきた。
皆さんも使えるようにプログラムと一緒にgitにあげておきます。

https://github.com/tsunaki00/horse_racing

情報のクレンジング,分析・分類

ある程度、情報の分類をしたいと考えましたが、自分が競馬素人のため断念。。
なので、レース情報と馬のパラメータ情報をプログラム内でマスタ化し数値化しました。

予測モデル作成と実験

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

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

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

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

パッケージのインストール

  $ pip install numpy
  $ pip install sklearn

予測プログラム

#coding:utf-8
import csv

from sklearn.externals import joblib
from sklearn.ensemble import RandomForestClassifier

class Predict:
  def __init__ (self) :
    self.model = None
    self.horse_data = []  
    self.train_data = []  
    self.train_target = [] 
    # テスト対象
    self.test_row_no = -1 

    self.master = {
      1 : {
        "福島": 0, "小倉": 1, "京都": 2, "函館": 3,
        "中山": 4, "札幌": 5, "東京": 6,
        "阪神": 7, "中京": 8, "新潟": 9 
      },
      4 :  { "芝" : 0, "ダート" : 1, "障害" : 2 },
      5 :  { "右" : 0, "左" : 1, "芝" : 2, "直線" : 3, "右2周" : 4 },
      7 :  { "不良" : 0,  "重" : 1, "稍重" : 2, "良" : 3 },
      14 : {"牡" : 0, "牝" : 1, "せん" : 2},
      29 : {"A" : 0, "B" : 1, "C" : 2, "D" : 3, "E" : 4, "nan" : -1 }
    }

  def train(self):
    hurdle_race_count = 0
    header = []
    label = []
    with open("data/jra_race_result.csv", "r") as f:
      reader = csv.reader(f)
      # 障害は除くデータで予測データを作成
      for idx, row in enumerate(reader):
        if idx == 0:
          for i, col in enumerate(row):
            header = row
          continue
        elif row[4] == '障害' :
          hurdle_race_count += 1
          continue
        horse = []
        parameter = []
        # マスタデータで数値化
        for i, col in enumerate(row):
          if i in {3, 13, 16, 18, 19, 26, 27, 28}:
            horse.append(col)
            continue
          elif i == 0 : 
            if self.test_row_no == -1 and col == '2016-09-17' :
              self.test_row_no = (idx - hurdle_race_count)
            parameter.append(col.replace('-',''))
          elif i == 10 : 
            label.append(header[i])
            horse.append(col)
            self.train_target.append(col)
          elif self.master.has_key(i) :
            if i == 1 :
              horse.append(col)
            label.append(header[i])
            parameter.append(self.master[i][col])
          else :
            if i in (2, 12) :
              horse.append(col)
            label.append(header[i])
            if col == ''  or col == ' - ': 
              col = -1
            parameter.append(float(col))
        self.horse_data.append(horse)
        self.train_data.append(parameter)

    # 学習モデルを作成(アルゴリズムはRandomForest)
    # パラメータの例n_estimators=xx, max_features="auto", n_jobs=-1
    self.model = RandomForestClassifier()
    # fitで学習 (9/17までを学習)
    self.model.fit(self.train_data[0 : self.test_row_no - 1], self.train_target[0 : self.test_row_no - 1])
    # modelをシリアライズする場合
    # joblib.dump(model, 'model.pkl') 
    # 素性の重要度(RandomForestの分岐での重要度)
    for i, xi in enumerate(self.model.feature_importances_): 
      print '{0}\t{1:.1f}%'.format(label[i], xi * 100)

  def predict(self):
    for i, val in enumerate(self.train_data[self.test_row_no:]):
      # predictで予測
      predict = self.model.predict([val])[0]
      if int(predict) == 1 :
        result = "☓"
        if int(predict) == int(self.horse_data[i][3]) :
          result = "○"
        print '{0} {1}R {2} {3} {4} 実際の着順 : {5}着 {6}'.format(self.horse_data[i][0],
                                                             self.horse_data[i][1],
                                                             self.horse_data[i][2],
                                                             self.horse_data[i][4],
                                                             self.horse_data[i][5],
                                                             self.horse_data[i][3], result )

if __name__ == "__main__":
  predict = Predict()
  predict.train()
  predict.predict()

結果

全然当たらないですね(笑)
※ もちろん現在開発中のSIVAはデータ元の情報もパラメータなど全く違います。

中山 01R サラ系3歳未勝利 14 ディアプピーラ 実際の着順 : 16着 ☓
中山 02R サラ系3歳未勝利 1 ケイアイリブラ 実際の着順 : 1着 ○
中山 05R サラ系3歳未勝利 16 ミエノワンダー 実際の着順 : 1着 ○
中山 05R サラ系3歳未勝利 13 ベルミュール 実際の着順 : 12着 ☓
中山 06R サラ系4歳上500万円以下 14 シンボリスウィフト 実際の着順 : 12着 ☓
中山 07R サラ系4歳上500万円以下 6 シンボリゾンネ 実際の着順 : 12着 ☓
中山 08R サラ系4歳上1000万円以下 13 アサクサマリンバ 実際の着順 : 11着 ☓
中山 09R 初日の出ステークス 5 ハンマープライス 実際の着順 : 9着 ☓
中山 10R ジュニアカップ 14 レッドヴィーヴォ 実際の着順 : 9着 ☓
中山 10R ジュニアカップ 11 レッドジャイヴ 実際の着順 : 10着 ☓
中山 11R 日刊スポーツ賞中山金杯(GIII) 9 ジャスタウェイ 実際の着順 : 3着 ☓
中山 11R 日刊スポーツ賞中山金杯(GIII) 16 イケドラゴン 実際の着順 : 15着 ☓
中山 12R サラ系4歳上1000万円以下 2 オメガブルーハワイ 実際の着順 : 3着 ☓
京都 01R サラ系3歳未勝利 8 ロレーヌクロス 実際の着順 : 3着 ☓
京都 01R サラ系3歳未勝利 4 デンコウショウイン 実際の着順 : 15着 ☓
京都 04R サラ系4歳上500万円以下 1 ミッキークリスエス 実際の着順 : 8着 ☓
京都 05R サラ系3歳未勝利 13 タニノタキシード 実際の着順 : 8着 ☓
京都 06R サラ系3歳新馬 11 メイショウオニグマ 実際の着順 : 8着 ☓
京都 07R サラ系4歳上500万円以下 5 ウエスタンムサシ 実際の着順 : 8着 ☓
京都 07R サラ系4歳上500万円以下 14 ソーニ 実際の着順 : 16着 ☓
京都 09R 福寿草特別 12 アドマイヤドバイ 実際の着順 : 2着 ☓
京都 10R 新春ステークス 2 タイキパーシヴァル 実際の着順 : 2着 ☓
京都 11R スポーツニッポン賞京都金杯(GIII) 11 サウンドオブハート 実際の着順 : 4着 ☓
京都 12R サラ系4歳上1000万円以下 2 スズカジョンブル 実際の着順 : 4着 ☓
中山 02R サラ系3歳未勝利 9 ベルモントジョーイ 実際の着順 : 7着 ☓
中山 03R サラ系3歳新馬 8 バッティングパワー 実際の着順 : 7着 ☓
中山 05R サラ系3歳未勝利 8 オーゴンチャチャ 実際の着順 : 9着 ☓
中山 05R サラ系3歳未勝利 9 イーグルモア 実際の着順 : 10着 ☓
中山 06R サラ系3歳新馬 9 マコロン 実際の着順 : 8着 ☓
中山 07R サラ系4歳上500万円以下 7 トーセンサイレンス 実際の着順 : 13着 ☓
中山 07R サラ系4歳上500万円以下 14 コスモディクタット 実際の着順 : 14着 ☓
中山 08R サラ系4歳上1000万円以下 4 ダノンシュナップス 実際の着順 : 14着 ☓
中山 09R 寒竹賞 12 ヒカルペガサス 実際の着順 : 11着 ☓
中山 09R 寒竹賞 4 ミリオンフレッシュ 実際の着順 : 12着 ☓
中山 10R 初富士ステークス 6 ステラロッサ 実際の着順 : 1着 ○
中山 10R 初富士ステークス 2 フルアクセル 実際の着順 : 2着 ☓
中山 10R 初富士ステークス 3 マイネエポナ 実際の着順 : 11着 ☓
中山 11R ジャニュアリーステークス 5 エベレストオー 実際の着順 : 13着 ☓
中山 12R サラ系4歳上1000万円以下 7 シンボリカージナル 実際の着順 : 13着 ☓
京都 02R サラ系3歳未勝利 6 バンブーバッジョ 実際の着順 : 14着 ☓
京都 03R サラ系3歳未勝利 3 ロードクロサイト 実際の着順 : 13着 ☓
京都 05R サラ系3歳新馬 7 ブライトアイディア 実際の着順 : 6着 ☓
京都 05R サラ系3歳新馬 3 アンシャックルド 実際の着順 : 7着 ☓
京都 06R サラ系3歳500万円以下 4 マコトタンホイザー 実際の着順 : 12着 ☓
京都 07R サラ系4歳上500万円以下 9 デイジーバローズ 実際の着順 : 14着 ☓
京都 08R サラ系4歳上1000万円以下 14 ナンゴクユニバース 実際の着順 : 14着 ☓
京都 09R 初夢ステークス 2 タカオノボル 実際の着順 : 1着 ○
京都 09R 初夢ステークス 7 アルバトン 実際の着順 : 11着 ☓
京都 09R 初夢ステークス 5 ミッキーバラード 実際の着順 : 12着 ☓
京都 10R 万葉ステークス 5 フォゲッタブル 実際の着順 : 6着 ☓
京都 10R 万葉ステークス 4 セイカプレスト 実際の着順 : 9着 ☓
京都 11R 日刊スポーツ賞シンザン記念(GIII) 16 アットウィル 実際の着順 : 6着 ☓

最後に

今日はここまでにしておきます。
パラメータのチューニング方法やデータの正規化方法なども今後アップしていきます。

(おまけ)SIVA開発のきっかけ

このプロジェクトのきっかけとなったのは、10月の半ばに行った情報処理試験で友達から「試験に落ちたかもー!」って連絡がきたのがきっかけとなります。

そこで前々から学習しようと思っていた、機械学習の来年の試験問題を予測して見ようと思いました。

プログラムに使ったライブラリは情報の多いscikit-learnを使用しましました。
[やったこと]
H.13年度の問題からH.28年度までの問題をカテゴリ化し、来年度の出る問題カテゴリを予測してみた。

14642235_1785738458343919_3303819700484393142_n.jpg

初めて触れたときの結果は、プログラムの難易度は低いと感じましたがアルゴリズムの選択に迷いました。(いまもなにが正しいのかわかってませんが(笑))
参考になる情報を見つけたのでシェアします。
※ scoreを出せるのもあるので今度、手順を書きます。

14721760_1785764201674678_6869920007789574956_n.jpg

ただし国家試験の予測ではすぐに結果の検証ができない!!!

情報処理試験の問題を予測をしてすぐに検証したいが、来年の春までは試験がないので、結果がわからない・・・・
そんな課題があったので、すぐに結果の出るもにしようと思いSIVAに至りました。

以上、また書きます!
SIVAは随時実況していきますので、いいね!フォローお願いします。
[facebook]
https://www.facebook.com/AIkeiba/
[Twitter]
https://twitter.com/Siva_keiba