強打とコンタクトはトレードオフの関係か?

強打をするために強いスイングをするとその代償として空振りが増えるというような印象がある。例えばこの記事では2018年の丸佳浩の三振の増加は長打増加の必要なコストとして扱っている。

丸佳浩が長距離砲に。巨人移籍後も本塁打量産が期待できるスラッガー化の裏付け

強振すると三振が増え長打が増える、というのはなんとなくイメージしやすい。ただそれは実際数字にするとどの程度なのだろうか。

検証

MLB15-20年を対象に連続する年で300打席以上立った選手についてBarrel/BBE(バレル/打球)と各指標の年度間の差を算出して相関分析を行う。例えばBarrel/BBEが5%→7%なら+2%、K%が20%→18%なら-2%、といった具合だ。データはBaseball Savantから入手できるStatcastのデータを使用した。

K%

K%差 Barrel

K%(三振/打席)差とBarrel/BBE差の相関係数は0.21と相関は弱かった。傾きをそのまま信じた場合K%が1%上昇するとBarrel/BBEは0.16%上昇するという結果になった。

Swing%

画像2

Swing%(スイング/投球)差とBarrel/BBEの相関係数は-0.03でありほとんど相関はなかった。強打を心がけた結果Swingが増えるという傾向はあまりないのだろうか。

Contact%

画像3

Contact%(空振り/スイング)差とBarrel/BBE差の相関係数は-0.23であり弱い負の相関であった。傾きをそのまま信じた場合、Contact%が1%低下するとBarrel/BBEは0.2%上昇する。

まとめ

選手別で見るとContact系の指標が低下した年には弱い相関ではあるがBarrel/BBEがわずかに上昇する傾向にはあるようだ。この結果からするとContactと強打はトレードオフの関係にあるというのはある程度はあてはまるのかもしれない。ただ選手個人の成長やAgingによる影響(若い選手はISOのような長打指標とK%がどちらも良化する一方でベテランはどちらも悪化する)は補正できていないしこの数字をそのまま信じられるものでもないようなところはある。次回以降もしやることがあれば課題になる部分である。

以下、今回書いたRのコード。

#tidyverseを使用
library(tidyverse)
# dfには2015-2020のstatcastのデータが入っている
# 列が全部含まれていると止まるので必要な列に絞る
df <- df%>%
 select(events,type,des,description,woba_denom,game_type,
        batter,barrel,game_year)
save(df, file="sc_data_for_barrel_plate.Rdata")
#レギュラーシーズンに限定する
df <- df %>%
 filter(game_type =="R")
#バント除く
df <- df %>% filter(! grepl("bunt", des))
#データの下処理
strikeouts <- c("strikeout", "strikeout_double_play")
df <- df %>% mutate(
 K_FL = ifelse(events %in% strikeouts, 1, 0),
 BB_FL = ifelse(events == "walk", 1, 0),
 pitch_denom = case_when(
   description == "swinging_strike" ~ "1",
   description == "swinging_strike_blocked" ~ "1",
   description == "called_strike" ~ "1",
   description == "foul_tip" ~ "1",
   description == "bunt_foul_tip" ~ "0",
   description == "foul" ~ "1",
   description == "foul_bunt" ~ "0",
   description == "ball" ~ "1",
   description == "blocked_ball" ~ "1",
   description == "pitchout" ~ "0",
   description == "hit_by_pitch" ~ "1",
   description == "hit_into_play" ~ "1",
   description == "hit_into_play_score" ~ "1",
   description == "hit_into_play_no_out" ~ "1",
   description == "missed_bunt" ~ "0"),
 pitch_denom = as.double(pitch_denom),
 swing = case_when( 
   description == "swinging_strike" ~ "1",
   description == "swinging_strike_blocked" ~ "1",
   description == "called_strike" ~ "0",
   description == "foul_tip" ~ "1",
   description == "bunt_foul_tip" ~ "0",
   description == "foul" ~ "1",
   description == "foul_bunt" ~ "0",
   description == "ball" ~ "0",
   description == "blocked_ball" ~ "0",
   description == "pitchout" ~ "0",
   description == "hit_by_pitch" ~ "0",
   description == "hit_into_play" ~ "1",
   description == "hit_into_play_score" ~ "1",
   description == "hit_into_play_no_out" ~ "1",
   description == "missed_bunt" ~ "0"),
 swing = as.double(swing),
 contact = case_when( 
   description == "swinging_strike" ~ "0",
   description == "swinging_strike_blocked" ~ "0",
   description == "called_strike" ~ "0",
   description == "foul_tip" ~ "0",
   description == "bunt_foul_tip" ~ "0",
   description == "foul" ~ "1",
   description == "foul_bunt" ~ "0",
   description == "ball" ~ "0",
   description == "blocked_ball" ~ "0",
   description == "pitchout" ~ "0",
   description == "hit_by_pitch" ~ "0",
   description == "hit_into_play" ~ "1",
   description == "hit_into_play_score" ~ "1",
   description == "hit_into_play_no_out" ~ "1",
   description == "missed_bunt" ~ "0"),
 contact = as.double(contact),
 swst = case_when( 
   description == "swinging_strike" ~ "1",
   description == "swinging_strike_blocked" ~ "1",
   description == "called_strike" ~ "0",
   description == "foul_tip" ~ "1",
   description == "bunt_foul_tip" ~ "0",
   description == "foul" ~ "0",
   description == "foul_bunt" ~ "0",
   description == "ball" ~ "0",
   description == "blocked_ball" ~ "0",
   description == "pitchout" ~ "0",
   description == "hit_by_pitch" ~ "0",
   description == "hit_into_play" ~ "0",
   description == "hit_into_play_score" ~ "0",
   description == "hit_into_play_no_out" ~ "0",
   description == "missed_bunt" ~ "0"),
 swst = as.double(swst))
 
#Plate系指標
bat_plate <- df  %>%
 group_by(game_year,batter)%>%
 dplyr::summarise(pitch_denom = sum(pitch_denom, na.rm = TRUE),
                  swing = sum(swing, na.rm = TRUE),
                  contact = sum(contact, na.rm = TRUE),
                  swst = sum(swst, na.rm = TRUE),
                  swingpct = swing /pitch_denom*100,
                  contactpct = contact / swing*100,
                  swstpct = swst / pitch_denom*100)%>%
 select(game_year,batter,
        swingpct,
        contactpct,
        swstpct)

#Barrel/BBEを計算
bat_barrel <- df%>%
 filter(woba_denom == 1 ,type== "X")%>%
 group_by(game_year,batter)%>%
 dplyr::summarise(wOBAcon_denom = sum(woba_denom, na.rm = TRUE),
                  barrel_CT = sum(barrel, na.rm = TRUE),
                  barrel_BBE = barrel_CT / wOBAcon_denom * 100)
#打席系を計算
bat_PA <- df%>%
 filter(woba_denom == 1)%>%
 group_by(game_year,batter)%>%
 dplyr::summarise(wOBA_denom = sum(woba_denom, na.rm = TRUE),
                  K = sum(K_FL, na.rm = TRUE),
                  Kpct = K / wOBA_denom * 100,
                  BB = sum(BB_FL, na.rm = TRUE),
                  BBpct = BB / wOBA_denom * 100)
                  
#300打席以上に限定する
bat_PA <- bat_PA %>%
 filter(wOBA_denom >= 300)
#データを結合していく
bat_PA <- bat_barrel %>%select(game_year,batter,Kpct,BBpct)
data <- left_join(bat_PA, bat_plate) %>%
 select(game_year,batter,Kpct,BBpct,
        swingpct,contactpct,swstpct)
data <- left_join(data, bat_barrel) %>%
 select(game_year,batter,Kpct,BBpct,
        swingpct,contactpct,swstpct,
        barrel_BBE)
        
#年度間比較のためのdfを作る
data_2 <- data
data2 <- names(data_2)[ which( names(data_2)=="game_year" ) ] <- "next_year"
data2 <- names(data_2)[ which( names(data_2)=="Kpct" ) ] <- "next_Kpct"
data2 <- names(data_2)[ which( names(data_2)=="BBpct" ) ] <- "next_BBpct"
data2 <- names(data_2)[ which( names(data_2)=="swingpct" ) ] <- "next_swingpct"
data2 <- names(data_2)[ which( names(data_2)=="contactpct" ) ] <- "next_contactpct"
data2 <- names(data_2)[ which( names(data_2)=="swstpct" ) ] <- "next_swstpct"
data2 <- names(data_2)[ which( names(data_2)=="barrel_BBE" ) ] <- "next_barrel_BBE"
data <- data %>%
 mutate(next_year = game_year + 1)
data_3 <- left_join(data, data_2) %>%
 select(next_year,batter,
        Kpct,BBpct,swingpct,contactpct,swstpct,barrel_BBE,
        next_Kpct,next_BBpct,next_swingpct,next_contactpct,next_swstpct,next_barrel_BBE)
data_3 <- subset(data_3, !(is.na(data_3$next_swingpct)))
data_3 <- data_3 %>%
 mutate(Kpct_dif = Kpct - next_Kpct,
        BBpct_dif = BBpct - next_BBpct,
        swingpct_dif = swingpct - next_swingpct,
        contactpct_dif = contactpct - next_contactpct,
        swstpct_dif = swstpct - next_swstpct,
        barrel_BBE_dif = barrel_BBE - next_barrel_BBE)

#相関係数の計算
correl <- data.frame(Kpct_dif = cor(data_3$Kpct_dif,data_3$barrel_BBE_dif),
                    BBpct_dif = cor(data_3$BBpct_dif,data_3$barrel_BBE_dif),
                    swingpct_dif = cor(data_3$swingpct_dif,data_3$barrel_BBE_dif),
                    contactpct_dif = cor(data_3$contactpct_dif,data_3$barrel_BBE_dif),
                    swstpct_dif = cor(data_3$swstpct_dif,data_3$barrel_BBE_dif) )
correl[,1:5] <- round(correl[,1:5], 2)

#表を作る能力がないのでcsvで保存してExcelで作成した。
write_csv(data_3,"Barrel_contact.csv")

この記事が気に入ったらサポートをしてみませんか?