この記事ではスクレイピングして取得した競馬データを、機械学習に使える形に整えるやり方を説明します。
データを取得することに比べて、このデータの前処理はかなり大変です。
データサイエンティストの人でも「前処理はかなり苦しい」という記事を見たことがあります。
前処理によって学習結果、つまりモデル全体の性能が大きく変わってきてしまうからです。
データの形もバラバラなことが多く、エラーが出まくって僕も大変でした笑
この記事をよんで、「前処理ってこんな感じなんだ」とイメージしてもらえると嬉しいです。
取得したデータを確認
競馬データをnetkeibaという競馬情報サイトからスクレイピングする方法は別記事に書きました。
今回は、そのデータの1部を使って前処理を説明したいと思います。
その記事のなかでお見せした、1レース分のデータがこちらです。
着順 | 枠_x | 馬番 | 馬名 | 性齢 | 斤量 | 騎手 | タイム | 着差 | 人気 | 単勝オッズ | 後3F | 厩舎 | 馬体重(増減) | 枠_y | 印 | 馬名 オッズ | 騎手斤量 | 前走 | 2走 | 3走 | 4走 | 5走 | 距離 | フィールド | 馬場 | レースID | |
0 | 1 | 8 | 9 | ラインストライカー | 牡3 | 56.0 | 大畑雅章 | 1:37.6 | 2 | 5.3 | 40.5 | 愛知安部幸夫 | 485(-5) | 8 | コパノリッキー ラインストライカー サンキャッチャー (シンボリクリスエス) 愛知・安部幸夫 中1週 485kg(-5) 5.3 (2人気) | 牡3黒鹿 大畑雅 56.0 | 2022.05.27 名古屋 2 3歳8組 ダ1500 1:37.0 不 11頭 1番 2人 大畑雅章 56.0 6-8-2 (39.4) 490(0) ラクレット(0.4) | 2022.05.19 名古屋 4 3歳8組 ダ1500 1:39.2 良 11頭 3番 2人 大畑雅章 56.0 7-6-7 (39.7) 490(-3) サリヴァン(0.8) | 2022.05.05 名古屋 5 3歳7組 ダ1500 1:38.1 良 12頭 9番 2人 大畑雅章 56.0 8-8-6 (39.5) 493(+1) サヴァンナナイツ(1.1) | 2022.04.25 名古屋 2 3歳7組 ダ1500 1:39.5 重 10頭 10番 6人 大畑雅章 56.0 5-4-3 (41.4) 492(-7) アカクマドリ(0.9) | 2022.04.13 名古屋 5 3歳8組 ダ1500 1:41.1 良 12頭 3番 6人 丹羽克輝 56.0 7-4-3 (42.2) 499(+7) ルブアルハリ(1.3) | 1500 | ダ | 重 | 202248060701 | ||
1 | 2 | 1 | 1 | フォートウィリアム | 牡3 | 56.0 | 岡部誠 | 1:37.7 | クビ | 1 | 1.2 | 40.7 | 愛知安部幸夫 | 515(-2) | 1 | モーリス フォートウィリアム シーリーコート (Distorted Humor) 愛知・安部幸夫 連闘 515kg(-2) 1.2 (1人気) | 牡3栗 岡部誠 56.0 | 2022.05.30 名古屋 1 3歳12組 ダ1500 1:37.4 良 9頭 4番 1人 岡部誠 56.0 6-4-2 (39.6) 517(+7) フライシュッツ(-0.9) | 2022.05.01 阪神 10 3歳未勝利 芝2400(外) 2:33.0 稍 12頭 12番 12人 酒井学 56.0 11-11-12-12 (38.0) 510(-10) スズノマーベリック(3.4) | 2022.04.16 阪神 14 3歳未勝利 ダ2000 2:13.2 稍 16頭 11番 13人 角田大河 53.0 13-13-14-14 (40.6) 520(-8) オブジェダート(4.0) | 2022.01.09 中京 12 3歳未勝利 ダ1900 2:05.9 良 15頭 8番 10人 西村淳也 56.0 14-13-8-12 (41.3) 528(-2) サンライズジャスト(4.0) | 2021.12.26 阪神 7 2歳新馬 ダ1800 2:00.3 良 16頭 16番 10人 西村淳也 55.0 12-12-12-10 (40.9) 530(0) オステリア(2.5) | 1500 | ダ | 重 | 202248060701 | |
2 | 3 | 2 | 2 | ウマイウマスギル | 牡3 | 55.0 | ☆細川智史 | 1:39.5 | 9 | 3 | 10.4 | 41.4 | 愛知坂口義幸 | 418(-3) | 2 | オウケンブルースリ ウマイウマスギル キューバンマンボ (スズカマンボ) 愛知・坂口義幸 中1週 418kg(-3) 10.4 (3人気) | 牡3鹿 細川智 55.0 | 2022.05.27 名古屋 3 3歳7組 ダ1500 1:37.4 不 11頭 5番 3人 細川智史 55.0 10-8-7 (39.7) 421(+1) メイショウクモジ(0.7) | 2022.05.19 名古屋 2 3歳8組 ダ1500 1:38.4 良 11頭 6番 5人 細川智史 55.0 4-4-3 (39.0) 420(-19) サリヴァン(0.0) | 2022.05.05 名古屋 4 3歳8組 ダ1500 1:39.1 良 10頭 7番 2人 細川智史 55.0 7-7-6 (39.7) 439(+9) チーママ(1.1) | 2022.04.25 名古屋 2 3歳9組 ダ1500 1:39.3 重 12頭 5番 10人 細川智史 55.0 9-9-5 (39.8) 430(-2) レクシー(0.0) | 2022.04.13 名古屋 11 3歳9組 ダ1500 1:42.8 良 12頭 2番 9人 柿原翔 56.0 11-11-11 (41.8) 432(+2) プロボノ(5.5) | 1500 | ダ | 重 | 202248060701 | |
3 | 4 | 4 | 4 | ゼアル | 牝3 | 52.0 | 宮下瞳 | 1:39.5 | ハナ | 4 | 16.8 | 42.1 | 愛知藤ヶ崎一 | 421(+2) | 4 | アドマイヤムーン ゼアル グリーンアイズII (Green Desert) 愛知・藤ヶ崎一 中1週 421kg(+2) 16.8 (4人気) | 牝3芦 宮下瞳 52.0 | 2022.05.27 名古屋 4 3歳7組 ダ1500 1:37.6 不 11頭 7番 7人 宮下瞳 52.0 7-7-6 (40.2) 419(-3) メイショウクモジ(0.9) | 2022.05.19 名古屋 3 3歳8組 ダ1500 1:38.7 良 11頭 11番 4人 宮下瞳 52.0 6-3-4 (39.5) 422(0) サリヴァン(0.3) | 2022.05.05 名古屋 4 3歳7組 ダ1500 1:38.0 良 12頭 12番 7人 宮下瞳 52.0 6-6-4 (39.6) 422(-2) サヴァンナナイツ(1.0) | 2022.04.22 名古屋 9 3歳6組 ダ1500 1:41.1 重 12頭 11番 5人 宮下瞳 52.0 2-2-4 (44.0) 424(+2) メッチャサス(2.1) | 2022.04.12 名古屋 7 3歳6組 ダ1500 1:42.3 良 12頭 11番 3人 宮下瞳 52.0 2-2-6 (43.3) 422(+6) ロバリアスピード(2.9) | 1500 | ダ | 重 | 202248060701 | |
4 | 5 | 7 | 7 | ワイジーコマチ | 牝3 | 54.0 | 加藤聡一 | 1:39.9 | 2 | 6 | 104.5 | 41.5 | 愛知榎屋充 | 449(+7) | 7 | エスケンデレヤ ワイジーコマチ パリスブルー (ゼンノロブロイ) 愛知・榎屋充 中2週 449kg(+7) 104.5 (6人気) | 牝3栗 加藤聡 54.0 | 2022.05.19 名古屋 8 3歳7組 ダ1500 1:40.0 良 11頭 6番 9人 加藤聡一 54.0 9-9-9 (40.9) 442(-4) ディラック(1.3) | 2022.05.05 名古屋 8 3歳6組 ダ1500 1:40.0 良 12頭 2番 8人 加藤聡一 54.0 11-11-9 (40.2) 446(+1) アイファーラニオー(2.5) | 2022.04.22 名古屋 6 3歳5組 ダ1500 1:40.3 重 12頭 11番 8人 丸山真一 54.0 7-7-9 (41.9) 445(-2) プロボノ(1.9) | 2022.04.11 名古屋 6 3歳5組 ダ1500 1:40.7 良 12頭 12番 12人 木之前葵 52.0 7-6-4 (42.3) 447(+6) ビッグベッター(2.2) | 2022.02.02 名古屋 9 3歳4組 ダ1400 1:37.3 良 11頭 5番 9人 木之前葵 52.0 8-8-10 (42.7) 441(-3) マボンヌ(3.7) | 1500 | ダ | 重 | 202248060701 | |
5 | 6 | 5 | 5 | エイシンルーキー | 牡3 | 56.0 | 柿原翔 | 1:40.9 | 5 | 5 | 21.3 | 43.1 | 愛知藤ヶ崎一 | 484(+2) | 5 | ザファクター エイシンルーキー エイシンフレア (エイシンデピュティ) 愛知・藤ヶ崎一 中1週 484kg(+2) 21.3 (5人気) | 牡3鹿 柿原翔 56.0 | 2022.05.27 名古屋 6 3歳7組 ダ1500 1:38.3 不 11頭 11番 6人 柿原翔 56.0 1-1-1 (42.3) 482(-2) メイショウクモジ(1.6) | 2022.05.19 名古屋 3 3歳7組 ダ1500 1:39.0 良 11頭 7番 5人 柿原翔 56.0 1-1-1 (42.5) 484(+1) ディラック(0.3) | 2022.05.05 名古屋 3 3歳7組 ダ1500 1:38.0 良 12頭 7番 5人 柿原翔 56.0 2-2-2 (40.7) 483(+4) サヴァンナナイツ(1.0) | 2022.04.22 名古屋 4 3歳6組 ダ1500 1:40.3 重 12頭 12番 7人 柿原翔 56.0 3-3-3 (43.2) 479(-1) メッチャサス(1.3) | 2022.04.12 名古屋 6 3歳6組 ダ1500 1:41.4 良 12頭 3番 6人 村上弘樹 56.0 5-7-8 (41.8) 480(+12) ロバリアスピード(2.0) | 1500 | ダ | 重 | 202248060701 | |
6 | 7 | 6 | 6 | エイシンウクラン | 牝3 | 54.0 | 加藤利征 | 1:41.9 | 5 | 9 | 169.5 | 43.3 | 愛知錦見勇夫 | 356(+3) | 6 | エイシンアポロン エイシンウクラン エイシンシルダリア (キングカメハメハ) 愛知・錦見勇夫 中1週 356kg(+3) 169.5 (9人気) | 牝3栗 加藤利 54.0 | 2022.05.26 名古屋 10 3歳6組 ダ1500 1:44.3 良 10頭 1番 9人 大畑雅章 54.0 9-10-10 (43.4) 353(+1) ザビッグマン(7.6) | 2022.05.17 名古屋 12 3歳6組 ダ1500 1:41.8 良 12頭 11番 12人 加藤利征 54.0 11-11-11 (42.6) 352(+2) サトミン(4.6) | 2022.05.05 名古屋 11 3歳5組 ダ1500 1:41.6 良 12頭 5番 11人 浅野皓大 53.0 10-11-11 (42.8) 350(0) ブルーインサニティ(5.3) | 2022.04.22 名古屋 10 3歳5組 ダ1500 1:42.1 重 12頭 12番 10人 浅野皓大 52.0 11-10-10 (42.8) 350(-2) プロボノ(3.7) | 2022.04.11 名古屋 12 3歳5組 ダ1500 1:44.9 良 12頭 1番 11人 大畑雅章 54.0 11-12-12 (43.9) 352(+4) ビッグベッター(6.4) | 1500 | ダ | 重 | 202248060701 | |
7 | 8 | 8 | 8 | アップモンスター | 牝3 | 54.0 | 友森翔太 | 1:42.8 | 4 | 8 | 129.8 | 45.3 | 愛知井手上慎 | 450(+4) | 8 | バトルプラン アップモンスター スピネッタ (シンボリクリスエス) 愛知・井手上慎 中1週 450kg(+4) 129.8 (8人気) | 牝3栗 友森翔 54.0 | 2022.05.27 名古屋 10 3歳7組 ダ1500 1:42.1 不 11頭 9番 8人 加藤聡一 54.0 3-4-9 (45.1) 446(-3) メイショウクモジ(5.4) | 2022.05.17 名古屋 10 3歳6組 ダ1500 1:41.3 良 12頭 3番 9人 友森翔太 54.0 10-10-8 (42.5) 449(+4) サトミン(4.1) | 2022.05.05 名古屋 10 3歳6組 ダ1500 1:40.6 良 12頭 8番 10人 戸部尚実 54.0 6-5-7 (42.6) 445(-5) アイファーラニオー(3.1) | 2022.04.22 名古屋 11 3歳5組 ダ1500 1:43.6 重 12頭 8番 6人 友森翔太 54.0 3-3-8 (45.6) 450(0) プロボノ(5.2) | 2022.04.11 名古屋 10 3歳5組 ダ1500 1:44.1 良 12頭 8番 10人 友森翔太 54.0 5-4-9 (46.1) 450(-9) ビッグベッター(5.6) | 1500 | ダ | 重 | 202248060701 | |
8 | 9 | 3 | 3 | レディウィット | 牝3 | 53.0 | ☆浅野皓大 | 1:43.0 | 1 | 7 | 120.2 | 43.6 | 愛知今津勝之 | 398(0) | 3 | ダノンレジェンド レディウィット プレイガール (Caerleon) 愛知・今津勝之 中1週 398kg(0) 120.2 (7人気) | 牝3鹿 浅野皓 53.0 | 2022.05.26 名古屋 8 3歳6組 ダ1500 1:40.6 良 10頭 10番 10人 浅野皓大 53.0 9-9-9 (40.4) 398(+3) ザビッグマン(3.9) | 2022.05.17 名古屋 11 3歳6組 ダ1500 1:41.6 良 12頭 7番 11人 浅野皓大 53.0 8-9-10 (43.0) 395(+1) サトミン(4.4) | 2022.03.09 名古屋 9 ありがとう ダ1400 1:37.0 良 10頭 2番 9人 浅野皓大 52.0 9-9-10 (40.8) 394(+3) リヤンフォルス(4.3) | 2022.03.02 名古屋 10 風雅16歳 ダ1400 1:37.8 稍 11頭 4番 10人 浅野皓大 52.0 7-7-9 (43.1) 391(-7) ヴァルゴ(2.4) | 2022.02.02 名古屋 10 3歳4組 ダ1400 1:37.3 良 11頭 9番 10人 浅野皓大 52.0 11-11-11 (42.0) 398(+8) マボンヌ(3.7) | 1500 | ダ | 重 | 202248060701 |
本当に見づらい笑
いい見せ方があるなら教えて欲しいです…
わかりやすいようにデータのカラム(列)をわけるとこんな感じですね。
当日データ | 過去データ | |
予想に使える | 馬番 枠_x 枠_y 馬名 性齢 斤量 騎手 人気 単勝オッズ 厩舎 馬体重(増減) 騎手斤量 馬名オッズ 距離 フィールド 馬場 | 前走 2走 3走 4走 5走 |
予想に使えない | 着順 タイム 着差 後3F |
その他データ → 印 レースID
データを確認したうえで、今回する前処理は次の5つですね。
- いらないカラムを消す
- 特殊記号を消す
- 1つのカラムに入っているデータを複数カラムに分ける
- 文字列データを数値データにする
- タイムを秒表記にする
順に説明します。
①いらないカラムを消す
さきほど確認していただいたように、いらないカラムがあることがわかります。
「枠_x(枠_y)」のようにデータフレームの結合で生じた重複カラムはもちろん、データがダブっているものも結構あります。
今回、いらないカラムは次の9つです。
- 枠_x
- 枠_y
- 馬名
- 厩舎
- 騎手斤量
- 馬名 オッズ
- 着差
- 後3F
- 印
馬名と厩舎は、データ分析なら必要だと思いますが「地方競馬の機械学習」のためには不要と判断しました。
いらないカラムを消すときは次のようなコードを書きます。
#いらないカラムを消す
df = df.drop(['枠_x', '枠_y', '馬名', '厩舎', '騎手斤量', '馬名 オッズ', '着差', '後3F', '印'], axis=1)
「axis=1」というのは「タテ方向」ってことです。
axis=0だとヨコ方向になるのでエラーが出るでしょう。
.drop([‘カラム名’], axis=1)で「’カラム名’の列を消す」って覚えておいてください。
②特殊記号を消す
はじめに表示したデータのなかで特殊記号が使われているものがありました。
騎手が「☆浅野皓大」と名前の前に「☆」がついています。
これは女性騎手や見習い騎手のために用意された減量制度のマークだそうです。
引用元:JRA – 馬やレースに付く記号
減量制度は勝利数などによって変化してしまうので、同じ騎手でも複数の名前を持ってしまう可能性があります。
そこで特殊記号を消しておきましょう。
#特殊記号を消す
df['騎手'] = df['騎手'].str.replace('▲', '')
df['騎手'] = df['騎手'].str.replace('△', '')
df['騎手'] = df['騎手'].str.replace('☆', '')
df['騎手'] = df['騎手'].str.replace('★', '')
df['騎手'] = df['騎手'].str.replace('◇', '')
特殊記号は5種類あるので1つずつ指定してreplace関数で消しました。
③1つのカラムに入っているデータを複数カラムに分ける
「性齢」「馬体重(増減)」「前走から5走まで」のデータのように1つのカラムに複数データが入っている場合があります。
それぞれデータをわけて「性」と「齢」のように新しいカラムをつくりたいですよね。
そんなときはextractが便利です。
df['性齢']
-->
0 牡3
1 牡3
2 牡3
3 牝3
4 牝3
5 牡3
6 牝3
7 牝3
8 牝3
Name: 性齢, dtype: object
#1つのカラムに入っているデータを複数カラムに分ける
df_sex = df['性齢'].str.extract('([牝牡セ])(\d+)', expand=True)
df_sex
-->
0 1
0 牡 3
1 牡 3
2 牡 3
3 牝 3
4 牝 3
5 牡 3
6 牝 3
7 牝 3
8 牝 3
正規表現を使うので、慣れるのに時間がかかりますがとても便利です。
extractを使えばこんな感じで新しいカラムを作ることができます。
#1つのカラムに入っているデータを複数カラムに分ける
df_sex = df['性齢'].str.extract('([牝牡セ])(\d+)', expand=True)
df['性'] = df_sex.loc[:, 0]
df['齢'] = df_sex.loc[:, 1]
df_weight = df['馬体重(増減)'].str.extract('(\d{3}).([+-0]\d*)', expand=True)
df['馬体重'] = df_weight.loc[:, 0]
df['体重増減'] = df_weight.loc[:, 1].str.replace('+', '', regex=True)
#「性齢」「馬体重(増減)」はいらないので消す
df = df.drop(['性齢', '馬体重(増減)'], axis=1)
#「前走」から必要なデータにわける
df_split = df['前走'].str.extract('(\d{4}.\d{2}.\d{2})\s(\w+)\s(\d*).*([ダ|芝])(\d+).*(\d:\d{2}.\d)\s(\w)\s(\d*)頭\s(\d*)番\s(\d*)人\s(\w+)\s(\d{2}[.]\d).+(\d{2}[.]\d).\s(\d{3}).([+-0]\d*).+\((-?\d*.\d{1})', expand=True)
最後のdf_splitとか暗号ですよね笑
僕はまだ正規表現に慣れていないのでめちゃめちゃ時間がかかりました。
でもこんな感じでデータがとれると気持ちいいですよ。
df_split
-->
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
0 2022.05.27 名古屋 2 ダ 1500 1:37.0 不 11 1 2 大畑雅章 56.0 39.4 490 0 0.4
1 2022.05.30 名古屋 1 ダ 1500 1:37.4 良 9 4 1 岡部誠 56.0 39.6 517 +7 -0.9
2 2022.05.27 名古屋 3 ダ 1500 1:37.4 不 11 5 3 細川智史 55.0 39.7 421 +1 0.7
3 2022.05.27 名古屋 4 ダ 1500 1:37.6 不 11 7 7 宮下瞳 52.0 40.2 419 -3 0.9
4 2022.05.19 名古屋 8 ダ 1500 1:40.0 良 11 6 9 加藤聡一 54.0 40.9 442 -4 1.3
5 2022.05.27 名古屋 6 ダ 1500 1:38.3 不 11 11 6 柿原翔 56.0 42.3 482 -2 1.6
6 2022.05.26 名古屋 10 ダ 1500 1:44.3 良 10 1 9 大畑雅章 54.0 43.4 353 +1 7.6
7 2022.05.27 名古屋 10 ダ 1500 1:42.1 不 11 9 8 加藤聡一 54.0 45.1 446 -3 5.4
8 2022.05.26 名古屋 8 ダ 1500 1:40.6 良 10 10 10 浅野皓大 53.0 40.4 398 +3 3.9
あとはカラム名をつけてあげるだけですからね。
#カラム名を指定
df_split.columns = ['日付', '場所', '着順', 'フィールド', '距離', 'タイム', '馬場', '出走馬数', '馬番', '人気', '騎手', '斤量', '後3F', '馬体重', '体重増減', '着差']
df_split
-->
日付 場所 着順 フィールド 距離 タイム 馬場 出走馬数 馬番 人気 騎手 斤量 後3F 馬体重 体重増減 着差
0 2022.05.27 名古屋 2 ダ 1500 1:37.0 不 11 1 2 大畑雅章 56.0 39.4 490 0 0.4
1 2022.05.30 名古屋 1 ダ 1500 1:37.4 良 9 4 1 岡部誠 56.0 39.6 517 +7 -0.9
2 2022.05.27 名古屋 3 ダ 1500 1:37.4 不 11 5 3 細川智史 55.0 39.7 421 +1 0.7
3 2022.05.27 名古屋 4 ダ 1500 1:37.6 不 11 7 7 宮下瞳 52.0 40.2 419 -3 0.9
4 2022.05.19 名古屋 8 ダ 1500 1:40.0 良 11 6 9 加藤聡一 54.0 40.9 442 -4 1.3
5 2022.05.27 名古屋 6 ダ 1500 1:38.3 不 11 11 6 柿原翔 56.0 42.3 482 -2 1.6
6 2022.05.26 名古屋 10 ダ 1500 1:44.3 良 10 1 9 大畑雅章 54.0 43.4 353 +1 7.6
7 2022.05.27 名古屋 10 ダ 1500 1:42.1 不 11 9 8 加藤聡一 54.0 45.1 446 -3 5.4
8 2022.05.26 名古屋 8 ダ 1500 1:40.6 良 10 10 10 浅野皓大 53.0 40.4 398 +3 3.9
④文字列データを数値データにする
さきほどのdf_splitを見ると
- 場所
- フィールド
- 馬場
- 騎手
のデータは文字列になっていました。
文字列のままでは機械学習できません。数値データに変換する必要があります。
map関数を使いましょう。
#文字列データを数値データにする
nagoya_mapping = {'名古屋': 1}
df_split['場所'] = df_split['場所'].map(nagoya_mapping)
field_mapping = {'芝': 1, 'ダ': 2, '障': 3}
df_split['フィールド'] = df_split['フィールド'].map(field_mapping)
condition_mapping = {'良': 1, '稍': 2, '重': 3, '不': 4}
df_split['馬場'] = df_split['馬場'].map(condition_mapping)
このように辞書型で文字列をどんな数字に置き換えるか指定してあげれば、map関数で一発です。
nagoya_mappingで名古屋だけを指定したのは、「名古屋なら1、それ以外の場所なら0」とするためです。
あらかじめ文字列の種類が決まっているものは自分で辞書をつくれば大丈夫です。
ですが、騎手はそうはいきません。
名古屋競馬に出場する騎手は決まっているそうですが、それでも移籍してきたり新人が入ったりすることもあるでしょう。
なので、今回はデータセットの騎手のユニークな値を出し、それを辞書型に変換することにしました。
#騎手のユニーク値から辞書をつくる
jockey_mapping = dict(zip(df_split['騎手'].unique().tolist(), range(1, len(df_split['騎手'].unique().tolist()) + 1)))
#文字列から数値に変換する
df_split['騎手'] = df_split['騎手'].map(jockey_mapping)
dict(zip(リスト1, リスト2))することで「リスト1,2をつかって辞書をつくる」となります。
結果を見てみましょう。
#変換後
df_split
-->
日付 場所 着順 フィールド 距離 タイム 馬場 出走馬数 馬番 人気 騎手 斤量 後3F 馬体重 体重増減 着差
0 2022.05.27 1 2 2 1500 1:37.0 4 11 1 2 1 56.0 39.4 490 0 0.4
1 2022.05.30 1 1 2 1500 1:37.4 1 9 4 1 2 56.0 39.6 517 +7 -0.9
2 2022.05.27 1 3 2 1500 1:37.4 4 11 5 3 3 55.0 39.7 421 +1 0.7
3 2022.05.27 1 4 2 1500 1:37.6 4 11 7 7 4 52.0 40.2 419 -3 0.9
4 2022.05.19 1 8 2 1500 1:40.0 1 11 6 9 5 54.0 40.9 442 -4 1.3
5 2022.05.27 1 6 2 1500 1:38.3 4 11 11 6 6 56.0 42.3 482 -2 1.6
6 2022.05.26 1 10 2 1500 1:44.3 1 10 1 9 1 54.0 43.4 353 +1 7.6
7 2022.05.27 1 10 2 1500 1:42.1 4 11 9 8 5 54.0 45.1 446 -3 5.4
8 2022.05.26 1 8 2 1500 1:40.6 1 10 10 10 7 53.0 40.4 398 +3 3.9
4つのカラムでちゃんと数値化できていますね。
「性」のカラムでも同じようにmap関数を使えばいけます。
⑤タイムを秒表記にする
つづいて、タイムを秒表記にしていきます。「1:37.0」を「97.0」にするってことです。
いろいろ調べたらこんな形になりました。
#タイムを秒表記にする
base_time = pd.to_datetime('00:00.0', format='%M:%S.%f')
df_split['タイム'] = pd.to_datetime(df_split['タイム'], format='%M:%S.%f') - base_time
df_split['タイム'] = df_split['タイム'].dt.total_seconds()
df_split['タイム']
-->
0 97.0
1 97.4
2 97.4
3 97.6
4 100.0
5 98.3
6 104.3
7 102.1
8 100.6
なぜ「base_time」との差を計算する必要があるのか僕にはちゃんとわかっていません(わかる人がいいたらぜひ教えてください)
ですが、これで秒表記にできました。
まとめ
この記事ではnetkeibaからスクレイピングした競馬データを機械学習に使えるよう前処理する方法について書きました。
まずはデータセットの中身を確認し、以下の作業を行いました。
- いらないカラムを消す
- 特殊記号を消す
- 1つのカラムに入っているデータを複数カラムに分ける
- 文字列データを数値データにする
- タイムを秒表記にする
データセットの中身によっては、より多くの作業が必要になるかもしれません。
データとデータをかけ合わせたりして新たなデータをつくることもします。
機械学習において、カラムのようにデータの特徴となる部分のことを特徴量と言います。
この特徴量を決める作業が機械学習のできを左右すると言っても過言ではありません。
特徴量エンジニアという仕事があるくらいです。
僕も特徴量についてもっと勉強して、よりいい学習ができるようにレベルアップしていきたいですね。
それでは、また。
コメント