【スクレイピング】学習データ(netkeibaから取得したレースデータ)を加工

競馬AI

本記事の目的

目的
  • 機械学習で使用できるように、取得したレースデータを加工する

作業概要

本サイトでは、下記の手順で「netkeiba.com」からレースデータを取得します。

ねずみくん
ねずみくん

このページでは、「③取得したデータを加工」を解説するよ

本ページでは、「②レースデータを取得」で取得したレースデータを使用します。

まだご覧になっていない方は、ぜひ読んでみてください!

③取得したデータを編集

ソースコード

""" メソッド:取得データを編集 """
def edit_data(race_result):
    
    # 「タイム」が欠損値である行を削除する ----------------- (※1)
    race_result = race_result.dropna(subset=['タイム'])
                
    # 「性齢」と「馬体重(増減)」を分割する ----------------- (※2)
    sex = []
    age = []
    weight = []
    weight_change = []
    error_row = []
    for cnt in range(0, len(race_result), 1):
        try:
            # 値を抽出
            value = race_result.at[race_result.index[cnt], '性齢']
            sex_value = value[0]
            age_value = value[1]
            weight_list = race_result.at[race_result.index[cnt], '馬体重(増減)'].split('(')
            weight_value = int(weight_list[0])
            weight_change_value = int(weight_list[1][:-1])
            
            # リストに追加
            sex.append(sex_value)
            age.append(age_value)
            weight.append(weight_value)
            weight_change.append(weight_change_value)

        except Exception:
            error_row.append(cnt)
            
    # 例外エラーが発生した行を削除
    if len(error_row) > 0:
        race_result.drop(error_row, axis=0, inplace=True)
                
    # 列を追加
    race_result['sex'] = sex
    race_result['age'] = age  
    race_result['weight'] = weight
    race_result['weight_change'] = weight_change
    
    # 「タイム」の値を秒数に変換
    race_time = race_result['タイム']
    time_sec = []
    for value in race_time:
        minutes = int(value.split(':')[0])
        sec = float(value.split(':')[1])
        td = datetime.timedelta(minutes=minutes, seconds=sec)
        time_sec.append(td.total_seconds())
    race_result['time'] = time_sec
    
    # レースIDを追加
    race_result['race_ID'] = race_result['date'] + race_result['area_ID']\
                            + race_result['race_month'] + race_result['race_day']\
                            + race_result['race_num']
                            
    # 文字型の値を数値化
    race_result = race_result.replace({'未勝利':0, '1勝クラス':1, '2勝クラス':2,
                                       '3勝クラス':3, 'オープン':4,
                                       '牝':0, '牡':1, 'セ':2})
    
    # 不要な列を削除する
    drop_list = ['馬名', '性齢', '騎手', 'タイム', '着差', 'コーナー通過順', '厩舎', '馬体重(増減)']
    race_result.drop(drop_list, axis=1, inplace=True)
        
    # 「race_result」のインデックスを0始まりの連番に振りなおす
    race_result.reset_index(drop=True, inplace=True)
    
    # 列名を英語に変換
    race_result = race_result.rename(columns={'着順':'rank', '枠':'frame',
                                              '馬番':'horse_num', '斤量':'weight2',
                                              '人気':'population', '単勝オッズ':'win_odds',
                                              '後3F':'3_frame_after'})

    return race_result

メソッドの引数と戻り値

カテゴリ 変数 説明
引数 race_result DataFrame レースデータ
戻り値 race_result DataFrame レースデータ(編集後)

解説

「タイム」が欠損値である行を削除する(※1)

入手したデータの中には、欠場した競走馬情報も含まれているため、欠損値が紛れ込んでいます。

そのようなデータは「タイム」が欠損値となっているので、本処理ではそのデータを削除しています。

# 「タイム」が欠損値である行を削除する ----------------- (※1)
race_result = race_result.dropna(subset=['タイム'])

「性齢」と「馬体重(増減)」を分割する(※2)

「性齢」と「馬体重(増減)」には、それぞれ複数の情報が含まれています。

◆性齢
 →性別と年齢の2つの情報が含まれている
  ※記載例:牝3

◆馬体重(増減)
 →性別と年齢の2つの情報が含まれている
  ※記載例:448(-4)

本処理ではこれらの情報を分割して取得し、新たな列を追加しています。

また、本処理では意図しないデータによってエラーが発生する可能性があります。

そこで、

構文

try:
正常処理

except Exception:
異常処理

という構文を使用することで、エラーが発生した際のレコード件数を「error_row」に格納し、後でまとめて削除しています。

    #「性齢」と「馬体重(増減)」を分割する ----------------- (※2)
    sex = []
    age = []
    weight = []
    weight_change = []
    error_row = []
    for cnt in range(0, len(race_result), 1):
        try:
            #値を抽出
            value = race_data.at[race_data.index[cnt], '性齢']
            sex_value = value[0]
            age_value = value[1]
            weight_list = race_data.at[race_data.index[cnt], '馬体重(増減)'].split('(')
            weight_value = int(weight_list[0])
            weight_change_value = int(weight_list[1][:-1])
            
            #リストに追加
            sex.append(sex_value)
            age.append(age_value)
            weight.append(weight_value)
            weight_change.append(weight_change_value)

        except Exception:
            error_row.append(cnt)

    #例外エラーが発生した行を削除
    if len(error_row) > 0:
        race_data.drop(error_row, axis=0, inplace=True)

文字列型の値を数値化(※3)

入手したデータを機械学習で使用する際、数値以外が使えないケースがあります。

なので本処理では、

メソッド

replace()

を使用して、値を数値化しています。

    # 文字型の値を数値化 ----------------- (※3)
    race_result = race_result.replace({'未勝利':0, '1勝クラス':1, '2勝クラス':2,
                                       '3勝クラス':3, 'オープン':4,
                                       '牝':0, '牡':1, 'セ':2})

不要な列を削除(※4)

データフレーム型変数から列を削除する際に、

メソッド

drop()

を使用しています。

特に第三引数の「inplace=True」を指定しないと、元のDataFrame型変数に削除結果が更新されないので、注意が必要です。

「drop()」の引数
  • 第一引数:削除対象のラベル名
     ※列ラベルのリストを指定することで、一気に列を削除することができます。
           
  • 第二引数:削除する方向
    • axis=0:行を削除
    • axis=1:列を削除 
          
  • 第三引数:変更有無
    • inplace=True:元のDataFrameが変更される
    • inplace=False:元のDataFrameが変更されない
    # 不要な列を削除する ----------------- (※4)
    drop_list = ['馬名', '性齢', '騎手', 'タイム', '着差', 'コーナー通過順', '厩舎', '馬体重(増減)']
    race_result.drop(drop_list, axis=1, inplace=True)

コメント

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