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

機械学習

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

 

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

 


  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

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

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

今回の例では運よく、余計な英数字が共通した長さの文字だったので、簡単に取り除くだけで修正できました。

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をコピーしました