はじめに
2022年プロ野球が開幕して早3ヶ月。
シーズン日程も折り返しましたが、
みなさま、贔屓球団の調子はいかがでしょうか?
新体制に希望を抱いて迎えた我が贔屓球団は
セ・リーグ最下位です!!!(2022/7/4現在)
そんな貧打に喘ぐ中日ドラゴンズの
「ホームラン数予測」をやってみました。
プロ野球ファン歴は19年ですが、機械学習経験は4ヶ月の初心者ですので、
どうか温かい目でご覧いただけると幸いでございます。
また、気になる点がありましたら、
ご指摘いただけると明日への励みになりますので、
ぜひコメントお待ちしております!
- 【データ】
- 【ゴール】 「2021年のプロ野球選手データを使って、中日ドラゴンズの選手のホームラン数を予測する」
- 【タスク】 ・中日ドラゴンズ以外の11球団のデータを使って機械学習
・出場試合数やヒット数などの変数から「ホームラン数」の傾向を学習させる
・学習したモデルを用い、中日ドラゴンズ選手データから「ホームラン数」を予測
- 【環境】 ・macOS
・Python 3.9.7
・JupyterLab
ライブラリ
最初にまとめて記載する派なので、
こちらに必要ライブラリのインポートをまとめます。
import urllib #HTMLにアクセス&取得
from bs4 import BeautifulSoup #HTMLからデータ抽出
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression as LR
from sklearn.metrics import mean_squared_error as MSE
import matplotlib.pyplot as plt
Webスクレイピング
※Webスクレイピングには著作権侵害等の恐れがあるため、
規約などを確認して使用するようにしましょう。
参照記事:Webスクレイピングの注意事項一覧
url = 'https://baseball-data.com/21/stats/hitter-all/hr-1.html'
html = urllib.request.urlopen(url)
soup = BeautifulSoup(html, 'html.parser')
table = soup.find_all('table')[0] # HTMLから表部分を全て取得
rows = table.find_all('tr') # 表から行データを取得
# データ格納
head_data = []
player_data = []
for i, row in enumerate(rows):
if i == 0: # 1行目
for headerValue in row.find_all('th'):
head_data.append(headerValue.get_text())
elif (i > 0) and (i + 1 < len(rows)): # 2行目〜最終行未満
player_row = []
for playerValue in row.find_all('td'):
player_row.append(playerValue.get_text())
player_data.append(player_row)
# データフレーム型に変換
df = pd.DataFrame(data = player_data, columns = head_data)
# CSV出力
df.to_csv('playerdata.csv', header=True, index=False)
データ分析
今回は、目的変数「本塁打」
との相関係数が0.7以上の
「打席数」「打数」「安打」「打点」「四球」「三振」
を予測に使う説明変数としました。
# CSV読み込み
df = pd.read_csv('playerdata.csv')
# 中日以外の11球団データを抽出
df11 = df[df['チーム'] != '中日']
# 中日のデータを抽出
df_d = df[df['チーム'] == '中日']
# 本塁打との相関係数
df_homerun = pd.DataFrame(df11.corr()['本塁打'])
# 可視化(相関高い長打率)
plt.scatter(x = df11['長打率'], y = df11['本塁打'])
plt.show()
# 可視化(相関低い盗塁)
plt.scatter(x = df11['盗塁'], y = df11['本塁打'])
plt.show()
# 相関係数が0.7以上の項目を抽出
x_columns = df_homerun[df_homerun['本塁打'] >= 0.7].index.tolist()
# 目的変数を除外
x_columns.remove('本塁打')
# 説明変数と目的変数を定義
X = df11[x_columns]
y = df11['本塁打']
モデル学習・評価
今回はシンプルに線形回帰モデル
で学習していきます。
# データ分割
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state = 1)
# モデルの学習
lr = LR()
lr.fit(X_train, y_train)
# 予測値の算出
y_pred_test = lr.predict(X_test)
y_pred_test
# MSEの算出
mse_test = MSE(y_test, y_pred_test)
mse_test
予測
さあ、いよいよ予測です!
# 中日データ(説明変数)
x_d = df_d[x_columns]
# 予測本塁打数の算出
y_pred_d = lr.predict(x_d)
# 予測本塁打列の追加
df_d['予測本塁打'] = np.round(y_pred_d).astype(np.int32)
# 予測値と実測値との比較
print(df_d[['選手名', '本塁打', '予測本塁打']])
選手名 | 本塁打 | 予測本塁打 |
---|---|---|
ビシエド | 17 | 17 |
木下拓哉 | 11 | 11 |
福田永将 | 8 | 7 |
高橋周平 | 5 | 8 |
阿部寿樹 | 5 | 3 |
堂上直倫 | 5 | 6 |
福留孝介 | 4 | 6 |
京田陽太 | 3 | 1 |
渡辺勝 | 2 | 2 |
A.マルティネス | 2 | 2 |
以下略 |
数本の誤差はありますが、概ね正確に予測できました。
それにしてもチーム本塁打数少な、、、(パァン)
おまけ
今回のコード全文を記しておきます。
# ライブラリ
import urllib #HTMLにアクセス&取得
from bs4 import BeautifulSoup #HTMLからデータ抽出
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression as LR
from sklearn.metrics import mean_squared_error as MSE
import matplotlib.pyplot as plt
# スクレイピング
url = 'https://baseball-data.com/21/stats/hitter-all/hr-1.html'
html = urllib.request.urlopen(url)
soup = BeautifulSoup(html, 'html.parser')
table = soup.find_all('table')[0] # HTMLから表部分を全て取得
rows = table.find_all('tr') # 表から行データを取得
# データ格納
head_data = []
player_data = []
for i, row in enumerate(rows):
if i == 0: # 1行目
for headerValue in row.find_all('th'):
head_data.append(headerValue.get_text())
elif (i > 0) and (i + 1 < len(rows)): # 2行目〜最終行未満
player_row = []
for playerValue in row.find_all('td'):
player_row.append(playerValue.get_text())
player_data.append(player_row)
# データフレーム型に変換
df = pd.DataFrame(data = player_data, columns = head_data)
# CSV出力
df.to_csv('playerdata.csv', header=True, index=False)
# CSV読み込み
df = pd.read_csv('playerdata.csv')
# 中日以外の11球団データを抽出
df11 = df[df['チーム'] != '中日']
# 中日のデータを抽出
df_d = df[df['チーム'] == '中日']
# 本塁打との相関係数
df_homerun = pd.DataFrame(df11.corr()['本塁打'])
# 可視化(相関高い長打率)
plt.scatter(x = df11['長打率'], y = df11['本塁打'])
plt.show()
# 可視化(相関低い盗塁)
plt.scatter(x = df11['盗塁'], y = df11['本塁打'])
plt.show()
# 相関係数が0.7以上の項目を抽出
x_columns = df_homerun[df_homerun['本塁打'] >= 0.7].index.tolist()
# 目的変数を除外
x_columns.remove('本塁打')
# 説明変数と目的変数を定義
X = df11[x_columns]
y = df11['本塁打']
# モデルの作成・評価
# データ分割
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state = 1)
# モデルの学習
lr = LR()
lr.fit(X_train, y_train)
# 予測値の算出
y_pred_test = lr.predict(X_test)
y_pred_test
# MSEの算出
mse_test = MSE(y_test, y_pred_test)
mse_test
# 予測
# 中日データ(説明変数)
x_d = df_d[x_columns]
# 予測本塁打数の算出
y_pred_d = lr.predict(x_d)
# 予測本塁打列の追加
df_d['予測本塁打'] = np.round(y_pred_d).astype(np.int32)
# 予測値と実測値との比較
print(df_d[['選手名', '本塁打', '予測本塁打']])