とあるIT企業データサイエンティストの競馬予測チャレンジ 特徴量エンジニアリング編

機械学習

本記事ではモデリングに使えるデータセットを作っていきます!

 

競馬予測チャレンジ目次!

 


  1. データ取得編1(過去のレースデータ取得)
  2. データ取得編2(スピード指数取得)
  3. 特徴量エンジニアリング編         ⇦本記事はココ
  4. モデリング、評価編
  5. 実践編


 

競馬の予測モデルを作成するためのデータセットを作ってい行きます。データ取得編でスクレイピングしてcsvファイルにしたものを結合していき、使える形にしていきます!  

使用するデータの確認

これまで、netkeiba.com競馬新聞&スピード指数(無料)から競馬レースに関するデータを取得しました。さらに使えそうなデータを取捨選択します。内訳としては次のようになります。

  • 馬名
  • 馬場種類(ダート or 芝)
  • 右曲がり or 左曲がり
  • 天気
  • 走行距離
  • 枠番
  • 馬番
  • 斤量
  • 騎手
  • 馬主
  • 賞金
  • 性別
  • 年齢
  • 馬体重
  • 馬体重変化量
  • スピード指数

ここから様々な特徴量を生成します。

 

どんな特徴量が作れそうか?

今回検討した特徴量は、

  • 過去レースの着順(1回前、2回前、3回前、5回前)
  • 過去スピード指数(1回前、2回前、3回前、5回前)
  • 前回レースからの日数
  • 前回レースの走行距離
  • これまでの獲得賞金合計
  • 連帯率(過去に2位以上になった割合)
  • 平均スピード(これまでの総走行距離÷全レースの走行タイム合計)
これらをがんばってPythonで作成しますが、今回Pythonコードは省略します。
もしご興味がある方がいらっしゃれば雑コードを公開します。( ̄ー ̄)ニヤリ
とりあえず、データクレンジングはやっていきます。

やっぱりやらないといけないデータクレンジング

来ましたね。面倒くさいやつ。

これをやらないとモデリングができないんです。

 

今回スクレイピングでデータを取得していますので、スクレイピングミスによる異常値を疑いましょう。

スクレイピングは使えると便利ですが、あくまで機械的にしか情報を取ることができません。

全てに対応することもできるかもしれませんが、数が多く非常に手間です。

混ざってしまったおかしたデータはPythonで取り除きましょう。

具体的には、

  • データの結合チェック
  • 欠損処理
  • 異常値除去(例として着順には数値だけでなく”中”と”取”とか含まれる)
    →そもそもテキストデータから異常値を見つけるのが大変
  • 馬名の訂正

などなどです。

今回はテキストデータの異常値を見つける方法を共有したいと思います。

 

value_counts()を使う

value_counts()はDataFrameの一つのカラムを指定し、そのカラムに含まれるユニークな値とその個数をカウントしてくれる機能です。

自分はよくこの機能を異常値発見に使います。

例えば、今回のデータに含まれる着順を見てみます。

df['着順'].value_counts(dropna=False)

ちなみに、”dropna=False”を指定すると、NaNになっているデータ数もカウントしてくれます。

結果は、、、

1     10201
3     10195
2     10191
#### 省略 #### 中 629 取 251 除 220 2(降) 4 3(降) 2 4(降) 1 5(降) 1 失 1

着順なので数値だけかと思いきや、後半の方に文字列が混じっていることがわかります。

 

ただしvalue_counts()の欠点は、指定したカラムのユニーク数が1000を超えるなど多い場合、異常値を探すことが困難となります。

そこで次のテクニックとして、文字数に着目します。

 

文字数をカウントし、極端に長いデータを見つける

この手法を使うことで、通常では考えにくい長さのデータを発見することができます。

今回の例だと、スクレイピングミスで発生する馬名の異常値です。

文字数をカウントするのに便利な関数は自分の知る限りないので、少し工夫してやります。

下のコードは馬名を1文字レベルでリストに分割し、そのリスト数つまり文字数をカウントしています。

df['馬名カウント'] = df['馬名'].map(lambda x:len(list(str(x))))
df.sort_values(by='馬名カウント',ascending=False)

さて、データを並び替えて表示してみると…

馬名                                          name_num
<font size="-2">(外)</font>ショウナンダニエル   35
<font size="-2">(外)</font>マテンロウゴースト   35
<font size="-2">(外)</font>エイシンエルヴィン   35
<font size="-2">(外)</font>フランクエトワール   35
<font size="-2">(外)</font>バーボンハイボール   35
<font size="-2">(外)</font>ロシアンサモワール   35

このように馬名の前にサイトに記載されているコードの一部と思われる英数字が紛れ込んでいることがわかります。

異常値を見つけることができたらあとは該当するデータを除去するいった処理を行います。

今回は共通した長さの余計な英数字を取り除くだけなので次のように1行で修正できました。

df['馬名']=df['馬名'].map(lambda x:str(x)[26:] if 'font' in x else x)

これは、英数字の”font”という文字が入っていたら26文字目までを削除しています。

 

最終的なデータセット

データセットを作る際に、気を付けたいのはリーケージです。

スピード指数などはそのまま使うことはできません。

2015年~2019年までのデータで特徴量を生成して反映させます。

 

カラム名 説明
weather 天気
field_cond 馬場の状態
kisyu 騎手名
wakuban 枠番
umaban 馬番
kinryo 斤量
surface 芝 or ダート
distance レース距離
turn 右回り、左回りか
sex 性別
age 年齢
race_num 〇日目のレース
race_place レース場所
weight 馬体重
weight_c 馬体重の変化量
last_days 最後のレースからの日数
target 3着以内かどうか
speed 総走行距離/総タイム
5prev_result 5回前の着順
3prev_result 3回前の着順
2prev_result 2回前の着順
prev_result 1回前の着順
p_speed_index 1回前のスピード指数
2p_speed_index 2回前のスピード指数
3p_speed_index 3回前のスピード指数
5p_speed_index 5回前のスピード指数
prev_speed 前回レースの平均速度
prev_dist 前回レースの走行距離
prize_sum これまでの賞金総額
rentai_rate 連帯率(2位以上の割合)

 

ついにデータセット完成や!

次はモデリング、評価をやっていきます!

コメント

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