LoginSignup
2
5

セイバーメトリクスの基礎をRで学ぶ

Posted at

野球のデータを分析してみたいと思いながらはや数年、プロ野球データフリークのサイトからコツコツとダウンロードしてきたデータをちょっとずついじりながら楽しんでいこうと思っています。

今回参考になったのはこの本です。

71LOzMOZQkL.SL1500.jpg

今回はプロ野球データフリークのサイトにある2009年から2023年までのNPB12球団のチームデータをダウンロードしたデータを使い分析します。

過去データを頑張ってまとめたエクセルファイルをgithubにアップロードしてありますので、こちらからダウンロードして使ってみてください。

データの読み込み
library(openxlsx)
datT<-read.xlsx("C:/Users/ユーザー名/Downloads/team_data.xlsx",sheet="Sheet1")
colnames(datT)

データの項目はこんな感じです。

> colnames(datT)
 [1] "年度"     "順位"     "リーグ"   "チーム"   "試合"     "勝利"     "敗北"     "引分"     "打率"     "得点"    
[11] "打数"     "安打"     "二塁打"   "三塁打"   "本塁打"   "盗塁"     "犠打"     "四球"     "死球"     "三振"    
[21] "併殺打"   "出塁率"   "長打率"   "OPS"      "NOI"      "IsoD"     "IsoP"     "得点平均" "安打平均" "投球回"  
[31] "防御率"   "セーブ"   "ホールド" "完投"     "完封勝"   "被安打"   "被本塁打" "与四球"   "与死球"   "奪三振"  
[41] "失点"     "自責点"   "WHIP"     "DIPS"     "失点平均" "被安平均"

実際にプロ野球のデータを使って各指標を見ていきます。
ちょっと指標が少ないので追加します。

スタッツを追加する
library(tidyverse)

datT2<-datT %>% 
  mutate(単打=安打-二塁打-三塁打-本塁打) %>% 
  mutate(犠飛=round((安打+四球+死球)/出塁率)-(打数+四球+死球)) %>%
  mutate(wOBA=(0.9*単打+1.3*二塁打+1.6*三塁打+2.0*本塁打+0.7*(四球+死球))/(打数+四球+死球+犠飛)) %>%
  mutate(ピタゴラス勝率=得点^2/(得点^2+失点^2))%>% 

まずはピタゴラス勝率です。
ピタゴラス勝率とは、野球版ピタゴラスの定理ともいわれているもので、

ピタゴラス勝率=得点^{2}÷(得点^{2}+失点^{2})

で定義されてます。得点と失点のデータで勝率を予測できてしまうというものです。
なんとなくピタゴラスの定理の数式に似てますね。
実際にピタゴラス勝率と勝率の関係を見てみます。

ピタゴラス勝率と勝率
#グラフに回帰式や決定係数等を入れるためのパッケージ
install.packages("ggpmisc")
library(ggpmisc)

#ピタゴラス勝率と勝率
ggplot(data=datT2,mapping=aes(x=ピタゴラス勝率,y=勝利/(試合-引分)))+
  geom_point(size=2,shape=21)+labs(x="ピタゴラス勝率",y="勝率")+
  geom_smooth(method = "lm", formula = y ~ x)+
  stat_poly_eq(formula = y ~ x,aes(label = paste(stat(eq.label),
                                                 stat(rr.label),
                                                 sep = "*\", \"*")),
               label.x = "right",
               label.y = "bottom",
               parse = TRUE)+
  theme_bw()

image.png

大体8割くらいは説明できているという結果になりました。

次は各打撃指標と得点との相関を見ていきます。

まずは打率との関係です。

打率=安打/打数
打率と平均得点
ggplot(data=datT2,mapping=aes(x=打率,y=得点平均))+
  geom_point(size=2,shape=21)+labs(x="打率",y="平均得点")+
  geom_smooth(method = "lm", formula = y ~ x)+
  stat_poly_eq(formula = y ~ x,aes(label = paste(stat(eq.label),
                                                 stat(rr.label),
                                                 sep = "*\", \"*")),
               label.x = "right",
               label.y = "bottom",
               parse = TRUE)+
  theme_bw()

image.png

出塁率との関係です。

出塁率=(安打+四球+死球)/(打数+四球+死球+犠飛)
出塁率と平均得点
ggplot(data=datT2,mapping=aes(x=出塁率,y=得点平均))+
  geom_point(size=2,shape=21)+labs(x="出塁率",y="平均得点")+
  geom_smooth(method = "lm", formula = y ~ x)+
  stat_poly_eq(formula = y ~ x,aes(label = paste(stat(eq.label),
                                                 stat(rr.label),
                                                 sep = "*\", \"*")),
               label.x = "right",
               label.y = "bottom",
               parse = TRUE)+
  theme_bw()

image.png

長打率との関係です。

長打率=塁打/打数

塁打とは単打を1、二塁打を2、三塁打を3、本塁打を4として数えた安打数です。

長打率と平均得点

ggplot(data=datT2,mapping=aes(x=長打率,y=得点平均))+
  geom_point(size=2,shape=21)+labs(x="長打率",y="平均得点")+
  geom_smooth(method = "lm", formula = y ~ x)+
  stat_poly_eq(formula = y ~ x,aes(label = paste(stat(eq.label),
                                                 stat(rr.label),
                                                 sep = "*\", \"*")),
               label.x = "right",
               label.y = "bottom",
               parse = TRUE)+
  theme_bw()

image.png

OPS(On-base plus slugging)との関係です。

OPS=出塁率+長打率
OPSと平均得点
ggplot(data=datT2,mapping=aes(x=OPS,y=得点平均))+
  geom_point(size=2,shape=21)+labs(x="OPS",y="平均得点")+
  geom_smooth(method = "lm", formula = y ~ x)+
  stat_poly_eq(formula = y ~ x,aes(label = paste(stat(eq.label),
                                                 stat(rr.label),
                                                 sep = "*\", \"*")),
               label.x = "right",
               label.y = "bottom",
               parse = TRUE)+
  theme_bw()

image.png

最後に加重出塁率(wOBA:Weighted On-Base Average)との関係も見てみます。

wOBA=(0.9*単打+1.3*二塁打+1.6*三塁打+2.0*本塁打+0.7*(四球+死球))/(打数+四球+死球+犠飛)

加重出塁率は各出塁に得点価値に基づいた加重を加えた指標で、
「打者が打撃あたりでどれだけチームの得点増に貢献する打撃をしているか」
を表します。

加重出塁率(wOBA)と平均得点
ggplot(data=datT2,mapping=aes(x=wOBA,y=得点平均))+
  geom_point(size=2,shape=21)+labs(x="wOBA",y="平均得点")+
  geom_smooth(method = "lm", formula = y ~ x)+
  stat_poly_eq(formula = y ~ x,aes(label = paste(stat(eq.label),
                                                 stat(rr.label),
                                                 sep = "*\", \"*")),
               label.x = "right",
               label.y = "bottom",
               parse = TRUE)+
  theme_bw()

image.png

こうしてみると打率だけでは十分に打撃評価ができないのがわかりますね。
また、加重出塁率の方がOPSよりもより詳細な分析指標にはなっているはずですが、得点との相関でみると同じくらいの精度になっているので、いかにOPSがシンプルかつ有効な指標であるかがわかります。

昨年度の各球団のwOBAを見てみます。

wOBA2023
library(dplyr)
wOBA2023 <- datT2 %>%
  filter(年度=="2023") %>% 
  select(チーム,wOBA)%>%
  arrange(-wOBA) 
> wOBA2023
          チーム      wOBA
1           巨人 0.3135741
2           楽天 0.3062023
3   ソフトバンク 0.3054725
4     オリックス 0.3046036
5           阪神 0.3042225
6       ヤクルト 0.3034910
7           横浜 0.3008999
8         ロッテ 0.2994156
9           広島 0.2964967
10      日本ハム 0.2886672
11          西武 0.2863681
12          中日 0.2752864

選手(球団)の力もあるとは思いますが、なんとなく巨人やソフトバンクなど本拠地がホームランが入りやすい球団で高く、日ハムや中日など本拠地が広い球場の球団は低い傾向があるように見えますね。
球場補正したらどうなるかやってみたいです。

2
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
5