上記期間のtrain_data.csv, test_data.csvにおいて、totalPitchingCount=1となるデータのバッティングカウント(B,S)に誤りがございました。
totalPitchingCount=1においてはB=0, S=0が正となります。
該当データをダウンロードされている方は、誠に恐れ入りますが、totalPitchingCount=1のB,SについてB=0, S=0と修正いただくか、再ダウンロード対応いただけますと幸いです。
お手数おかけいたしますが、何卒よろしくお願いいたします。
テクノロジーの進展により、近代野球におけるデータ活用はチーム編成や戦術を決めるうえで欠かせないものとなりました。
例えば、NPB(日本プロ野球機構)では、ヤクルトスワローズを率いていた野村克也監督が1990年代にID(Important Data)野球を提唱し、新しい取り組みを次々と実践していきました。
一例として、先発投手として当時成績の厳しかった江夏をリリーフ投手として抜擢、選手の特性に応じたチーム編成を行いました。またチームミーティングについては、従来の根性論に近い形式ではなく、投球分析に基づいた戦略を監督から選手に伝える場とするなど、運営方法までも大きく変革しました。
その結果、ヤクルトスワローズは1992、1993年と2年連続での優勝を手にしました。現在では、横浜DeNAベイスターズがデータ分析の専門部隊を結成するなど、データ活用はNPBの文化として強く根付いています。
MLBにおいても、1990年代後半のビリー・ビーンGMによるセイバーメトリクスという手法により、彼の率いるオークランド・アスレチックスは強豪チームの仲間入りを遂げました。
その活躍を描いた書籍「マネーボール」は大ヒットし、映画化までされています。
本コンペでは、一球ごとの投球データ(球速・球種等)と試合状況・対戦者情報より、ストライク・アウト・ホームランといった投球結果を予測するモデル開発にチャレンジいただきます。
「打った」「点が入った」といった視点で試合を見るだけではなく、選手交代・配球など、意思決定の裏側にあるデータを知ることで、普段とは違った角度からも野球をお楽しみいただければ幸いです。
今回のコンペでは、訓練データとして、球種、投球の速度、打球の距離や方角といった情報が与えられています。
これらのデータは、投球が行われるまでは未確定の情報となるため、テストデータからは除外されています。
本コンペを通じて、テストデータに含まれていない情報についても活用したモデル開発に親しんでいただけますと幸いです。
また、ストライクやファールに比べて2塁打やホームランといった打球は非常に数が少なくなります。このような不均衡データを用いていることも、本コンペの特徴です。
セイバーメトリクス入門 脱常識で野球を科学する
セイバーメトリクスの落とし穴~マネー・ボールを超える野球論~ (光文社新書)
Pythonで動かして学ぶ! Kaggleデータ分析入門 (AI & TECHNOLOGY)
Kaggleで勝つデータ分析の技術
データをダウンロードするにはログインまたはユーザー登録して下さい
上記期間のtrain_data.csv, test_data.csvにおいて、totalPitchingCount=1となるデータのバッティングカウント(B,S)に誤りがございました。
totalPitchingCount=1においてはB=0, S=0が正となります。
該当データをダウンロードされている方は、誠に恐れ入りますが、totalPitchingCount=1のB,SについてB=0, S=0と修正いただくか、再ダウンロード対応いただけますと幸いです。
お手数おかけいたしますが、何卒よろしくお願いいたします。
コンペに使用するデータは3つに分けられます。
訓練データ、テストデータには、それぞれ20,400件、33,808件のデータ含まれます。
データには、各投球時の試合状況とその結果が含まれています。
訓練データでは投球結果に関して、球種、投球の速度、打球の距離や方角といった情報が与えられていますが、投球が行われるまでは未確定の情報となるため、テストデータからは除外されています。
column name | example | description | exist on test data? |
---|---|---|---|
totalPitchingCount | 1 | 各打席の投球が何球目か | yes |
B | 0 | ボールカウント | yes |
S | 1 | ストライクカウント | yes |
O | 0 | アウトカウント | yes |
b1 | False | 1塁にランナーがいるか | yes |
b2 | True | 2塁にランナーがいるか | yes |
b3 | True | 3塁にランナーがいるか | yes |
pitcher | - | ピッチャー名(NaNを含む) | yes |
pitcherHand | L | 右投げか左投げか | yes |
batter | - | バッター名(NaNを含む) | yes |
batterHand | R | 右打ちか左打ちか | yes |
gameID | 20202173 | 試合ID | yes |
inning | 1回表 | イニング | yes |
pitchType | ストレート | 球種 | no |
speed | 149km/h | 投球速度 | no |
ballPositionLabel | 内角低め | 投球位置 | no |
ballX | 17 | 投球のX座標(1-21) | no |
ballY | J | 投球のY座標(A-K) | no |
dir | S | 打球方向(A-Z) | no |
dist | 38.3 | 打球距離 | no |
battingType | B | 打球種類(B:バント, G:ゴロ, P:ポップフライ, F:フライ, L:ライナー) | no |
isOuts | True | 投球結果がアウトか | no |
y | 1 | 投球結果(0:ボール, 1:ストライク, 2:ファウル, 3:アウト, 4:シングルヒット, 5:二塁打, 6:三塁打, 7:ホームラン) |
batter、pitcherは、元データが一部欠損していたことにより、一部NaNとなっています。
column name | example | description |
---|---|---|
startTime | 18:00 | 試合開始時間 |
bottomTeam | DeNA | 後攻チーム名 |
topTeam | 広島 | 先攻チーム名 |
place | 横浜 | 試合会場 |
startDayTime | 2020-06-19 18:00:00 | 試合開始日時 |
gameID | 20202173 | 試合ID |
テストデータセットの投球時の状況に関するデータにもとづき、投球結果の予測をしてください。
yの値は、0,1,2,3,4,5,6,7のいずれかになるように設定してください。
yの値 | 投球結果 |
---|---|
0 | ボール |
1 | ストライク |
2 | ファウル |
3 | アウト |
4 | シングルヒット |
5 | 二塁打 |
6 | 三塁打 |
7 | ホームラン |
回答用のsubmission.csvを用意する(エントリーとヘッダー行を含む) 。
提出されたファイルに余分な行や列(idとy以外)が含まれていた場合はエラーとなります。
提出ファイルは以下の列のみを必ず含んでください:
id,y
0,4
1,1
2,1
3,7
4,0
本コンペでは、開催期間終了後 賞金対象者のコードを公開し、ユーザーの皆様にチーティング有無をレビューしていただき順位確定させる、オープンレビュー方式のコンペティションを行います。
コード公開後1週間:
レビュアー(ユーザー)より、チーティングの疑いに関するコメントがある場合は、ご回答をお願いいたします。
※チーティングとは無関係のコメント(ノウハウに関する質疑 等)についてもご回答いただけると幸いですが、順位確定の判断材料とは致しません。
レビュアーからの質疑と、回答状況をふまえて、最終的に運営側で順位確定を判断します。
開始日 2021/4/9 0:00 JST
終了日 2021/6/20 24:00 JST
エントリー締め切り なし
※コンペ期間中であっても、不正が疑われる場合は、運営より確認のためメール連絡させていただくことがございます。一週間以内にご回答いただけない場合も、不正と判断させていただきます。
原則外部データ/学習済みモデルの使用は禁止としておりますが、正解データの入手につながらない場合は、下記承認プロセスにより使用できることといたします。
注)ただし、コンペ終了まで7日をきってからの申請は禁止とします
公平性の担保、チーティング等の不正防止のため、予告なくルールの追加・変更を行う場合がございます。
ご不便をおかけすることもあるかと思いますが、サービス向上のためご了承ください。
はい。
最も精度の高い学習モデルを作成した優勝者には、賞金10万円を贈呈します。
順位確定までのプロセスについては、ルール「Open Review Competition」を参照ください。
可能です。チームページから作成いただけます。
こちらから作成いただけます。
コンペティション参加にはアカウント登録が必要となりますのでご注意ください。
申請を行うことによって利用可能です。
ルール「外部データ/学習済みモデルの使用申請について」を参照ください。
Seed を固定することが推奨です。
ただし、Seed を固定しなくても提出用コードとしては認めています。
このチュートリアルでは、野球の試合における投球データに対して
を行います。
#環境確認
import pandas as pd
import numpy as np
import sklearn
!python3 --version
print(pd.__version__)
print(np.__version__)
print(sklearn.__version__)
import matplotlib
print(matplotlib.__version__)
Python 3.8.6
1.1.1
1.18.5
0.23.2
3.3.3
まずはデータを読み込んで見ましょう。csvデータの読み込みは複数のやり方がありえますが、pandas
のread_csv
関数はその中でも機能が豊富で、扱いやすいためこれを使います。
これを使うと、csvデータを読み込み、pandas.DataFrame
にして返してくれます。
#データの読み込みと前処理
import pandas as pd
train_data = pd.read_csv("train_data.csv", index_col='id')
print(train_data.shape)
(20400, 23)
また、DataFrame
には.head()
というメソッドが定義されており、これを呼び出すとDataFrame
の先頭の数行を確認できます。
train_data.head()
totalPitchingCount | B | S | O | b1 | b2 | b3 | pitcher | pitcherHand | batter | ... | pitchType | speed | ballPositionLabel | ballX | ballY | dir | dist | battingType | isOuts | y | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
id | |||||||||||||||||||||
0 | 1 | 0 | 0 | 0 | False | False | False | 今永 昇太 | L | ピレラ | ... | ストレート | 149km/h | 内角低め | 17 | J | NaN | NaN | NaN | NaN | 0 |
1 | 2 | 1 | 0 | 0 | False | False | False | 今永 昇太 | L | ピレラ | ... | ストレート | 149km/h | 内角低め | 14 | I | NaN | NaN | NaN | NaN | 1 |
2 | 3 | 1 | 1 | 0 | False | False | False | 今永 昇太 | L | ピレラ | ... | チェンジアップ | 137km/h | 外角高め | 8 | D | NaN | NaN | NaN | NaN | 0 |
3 | 4 | 2 | 1 | 0 | False | False | False | 今永 昇太 | L | ピレラ | ... | スライダー | 138km/h | 内角中心 | 21 | G | NaN | NaN | NaN | NaN | 2 |
4 | 5 | 2 | 2 | 0 | False | False | False | 今永 昇太 | L | ピレラ | ... | チェンジアップ | 136km/h | 外角中心 | 7 | F | S | 38.3 | G | False | 4 |
5 rows × 23 columns
訓練データに説明変数y
の分布がどのようになっているか確認してみます。
train_data['y'].value_counts()
0 7544
1 5611
2 3562
3 2509
4 797
5 223
7 142
6 12
Name: y, dtype: int64
ボール、ストライク、ファイル、アウトが多く、バッターが出塁することはなかなか難しいようです。
続いて、下記のコードを使用して使用するデータ全体の概観を確認します。
各項目について欠損値以外('non-null')の値がどの程度含まれているか把握できます。また、データの形式についてもここで判別可能です。
train_data.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 20400 entries, 0 to 20399
Data columns (total 23 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 totalPitchingCount 20400 non-null int64
1 B 20400 non-null int64
2 S 20400 non-null int64
3 O 20400 non-null int64
4 b1 20400 non-null bool
5 b2 20400 non-null bool
6 b3 20400 non-null bool
7 pitcher 20400 non-null object
8 pitcherHand 20355 non-null object
9 batter 20400 non-null object
10 batterHand 20355 non-null object
11 gameID 20400 non-null int64
12 inning 20400 non-null object
13 pitchType 20400 non-null object
14 speed 20400 non-null object
15 ballPositionLabel 20400 non-null object
16 ballX 20400 non-null int64
17 ballY 20400 non-null object
18 dir 3642 non-null object
19 dist 5166 non-null float64
20 battingType 3642 non-null object
21 isOuts 5166 non-null object
22 y 20400 non-null int64
dtypes: bool(3), float64(1), int64(7), object(12)
memory usage: 3.3+ MB
データの形式を見ると、バッティングの結果に関するカラムに欠損値が多いようです。またこれらのデータは被説明変数y
とともにテストデータでは与えられない変数となっています。
モデルに投入する目的変数(y)、説明変数(X)を作成します。今回は学習データとテストデータの両方で与えられるカラムを用いてモデルを作成します。
X = train_data[['B', 'S', 'O', 'b1', 'b2', 'b3']]
y = train_data['y']
いよいよ予測モデルの作成に入ります。model.fit('説明変数','目的変数')
と記述することでモデルの学習が可能となります。目的変数を説明変数の組み合わせで説明可能な回帰モデルを作成できます。
#scikit-learnライブラリをimport
import sklearn
from sklearn.ensemble import RandomForestClassifier
#線形回帰モデルのインスタンス化
model = RandomForestClassifier()
#予測モデルの作成
model.fit(X, y)
RandomForestClassifier()
list(reversed(sorted(list(zip(model.feature_importances_, X.columns)))))
[(0.3209557774604652, 'S'),
(0.2948133327526405, 'B'),
(0.14942731837880008, 'O'),
(0.08071108251796956, 'b1'),
(0.0771053739782763, 'b2'),
(0.07698711491184829, 'b3')]
RandomForestではfeature_importances_
で特徴量の重要度を取得することができます。
どのベースにランナーがいるかという情報はあまり重要ではないようです。
また、コンペの評価指標となるf1
スコアを確認してみましょう。
今回は、sklearn.metrics
に含まれるf1_score
メソッドを使用します。
1に近いほど予測精度が高いことを表します。
モデルを元にした予測値は、model.predict('説明変数')
で表します。
# F1スコアの出力
from sklearn.metrics import f1_score
y_true = y
y_pred = model.predict(X)
print(f1_score(y_true, y_pred, average='macro'))
0.15409650198369168
今回作成したモデルのF1スコアは15.4%程度でした。利用した説明変数の組み合わせの総数が高々400程度であることが原因と思われます。
最後に、作成したモデルを使用してテストデータでの投球の結果を予測します。
path_test = "test_data.csv"
test_data = pd.read_csv(path_test, index_col='id')
test_data.head()
totalPitchingCount | B | S | O | b1 | b2 | b3 | pitcher | pitcherHand | batter | batterHand | gameID | inning | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
id | |||||||||||||
0 | 2 | 1 | 0 | 0 | False | False | False | 遠藤 淳志 | R | 乙坂 智 | L | 20202564 | 2回表 |
1 | 1 | 0 | 0 | 0 | False | False | False | バンデンハーク | R | 西川 遥輝 | L | 20202106 | 3回裏 |
2 | 7 | 3 | 2 | 2 | True | False | False | スアレス | R | 堂林 翔太 | R | 20203305 | 9回裏 |
3 | 1 | 0 | 0 | 2 | True | False | False | クック | R | 井領 雅貴 | L | 20202650 | 3回裏 |
4 | 2 | 0 | 0 | 2 | False | False | False | 則本 昂大 | R | 安達 了一 | R | 20202339 | 2回表 |
test_X = test_data[['B', 'S', 'O', 'b1', 'b2', 'b3']]
先ほど使用したmodel.predict('説明変数')
の説明変数
にテストデータの値を代入することで、テストデータの予測値を算出することができます。
下記のようにして、提出用のsubmission.csv
を出力することが可能です。
#テスト結果の出力
test_predicted = model.predict(test_X)
submit_df = pd.DataFrame({'y': test_predicted})
submit_df.index.name = 'id'
submit_df.to_csv('submission.csv')
コンペティションへの参加に際しては、ProbSpace利用規約(以下、「利用規約」といいます。)に加え、本ProbSpace参加規約(以下「本規約」といいます。)に同意いただく必要があります。利用規約にて定義された用語は、本規約においても同様の意味で用いられるものとします。
第1条(適用)
第2条(定義)
本規約において次の各用語の定義は、それぞれ以下に定めるとおりとします。
第3条(権利の帰属)
第4条(入賞者の義務)
第5条(禁止事項)
第6条(本コンペの変更、中断、終了等)
第7条(損害賠償)
第8条(本規約の変更)
当社は、必要と判断した場合には、参加者に対して事前に通知する(本コンペにかかる当社ウェブサイト上での告知その他当社が適当と認める方法を含みます。)ことにより、いつでも本規約を変更することができるものとします。なお、変更内容の通知後、参加者が当社の定める期間内に本コンペへの参加を取り消す手続をとらなかった場合には、当該参加者は変更後の規約に同意したものとみなされます。当社は、本規約の変更により参加者に生じたすべての損害について一切の責任を負いません。
第9条(その他)
本契約の準拠法は日本法とし、本契約に起因し又は関連する一切の紛争については、当社の本店所在地を管轄する裁判所を第一審の専属的合意管轄裁判所とします。
(制定)2020年6月22日