1年分のStatcastデータの取得
さて、前回はStatcastデータについて、特定の選手について解析してみました。
まずは、書籍にあるようにコレア選手の打球方向を調べ、その後2022年シーズンの大谷選手の打球方向について調べることができました!
続いてシーズン全てのインプレーのデータを収集して解析をして行こうと思います。
前回は、baseballrパッケージのscrape_statcast_savan関数を用いることで指定選手、指定期間のデータを収集することができましたね。
しかし、baseballr関数は最大40000行のデータした取得できないようです。
しかし1年間の投球データは概算で約70万球になります。(164試合×約150球×30球団)
そこでstatcastrパッケージを利用して、データベースを構築して、そこからcsvデータをエクスポートする方法を取ります。
データベースの構築について
Statcastを解析すると膨大なデータとなります。このビッグデータ問題の解決策は、そのデータをリレーショナルデータベース管理システムに格納しておき、Rからそこに接続して分析に必要なデータのみを都度抽出するようにしておくことです。
個人的にはこの概念を理解するのにかなり時間がかかりました。。。その手順もよくわからなかったのですが、試行錯誤してなんとか理解できるようになりました。
手順としては、①RDBMSをインストールする(ここではMySQL)、②MySQL内にデータベースを作成する、③RからMySQLへ接続する、④RからMySQL内のデータベースに入力をする、⑤RからSQL(これはデータベースを操作する言語)を実行するとなります。
※データベースのインストールや操作については、11章のパークファクターの計算の章に詳細ありますので、こちらはまた後ほどアップしたいなぁ、、、と思っています。
MySQLを利用してデータベースを構築します。
library(statcastr)
library(RMySQL)
conn <- dbConnect(MySQL(), dbname = "abdwr",
user = "root", password = "password")
dbSendQuery(conn, "CREATE DATABASE statcast;")
それに1年分のStatcastを入れて行きます。
※ここで注意なのですが、この先のコマンドが本書とものと、リポジトリ内のものhttps://github.com/ghmagazine/r_analyzing_baseballが若干違います。
db <- src_mysql(dbname = "statcast",
user = "root", password = "password")
sc <- etl("statcastr", db, dir = "statcastr")
sc %>%
etl_init() %>%
etl_extract(year = 2017, month = 3:10) %>%
etl_transform(year = 2017, month = 3:10)
files <- dir("statcastr/load/", pattern = ".csv", full.names = T)
statcast <- files %>% map(read_csv) %>% do.call("rbind", .)
copy_to(db, statcast)
結果としては、、、HTTP 504 Gateway Timeout となってしまいます。
この原因はサーバー側のレスポンスに時間がかかっているようです。。
ちなみに、scrape_statcast_savant関数でデータ量が多かったりすると(例えば数カ月分のデータをしてい)、同じエラーになります。
そこで、別の戦略を発動することとしました。一つ一つCSVをダウンロードしてそして結合するという方法をとりました。
①まず、Statcast Savantのサイトにアクセスします。
上部の帯にある Searchをクリック
②そうすると、検索項目が出てきますので、Player TypeをBatterに、Game Dateをシーズン前半の3月から6月に指定。Group byをTeamにします。(ちなみに期間を1シーズンにするとエラーとなってしまいます。)
③検索すると下部にチーム30球団が羅列されます。一番右端のGraphsをクリックして、Download as CSVをクリック
④そして、全球団分をダウンロードします。これをシーズン後半分も繰り返します。
これらのcsvファイルを統合します。方法は下記のリンクでみつけました!
まず、フォルダを作成し、ディレクトリを指定
setwd("~/r_analyze/r_analyzing_baseball-main/statcast2022")
そして、下記のコマンドを実行します。
csv_list <- list.files(pattern = "*.csv")
data_sc_2022 <- do.call(rbind, lapply(csv_list, function(x) read.csv(x, header=TRUE, stringsAsFactors = FALSE)))
これで、data_sc_2022という2022年シーズンの全投球が格納されたデータフレームができました!!
ここから、打球を抽出します。インプレーの打球はtypeがXと示されます。
data_sc_2022_bip<- data_sc_2022%>%
filter(type == "X")
打球方向の傾向と内野守備
ここでは、打球方向の傾向について調べます。左バッターを対象として、ゴロの打球方向の傾向と、それに対する守備シフトの関係を見てみます。
2022年Statcastのインプレーデータを総括して、打席数と左打者なら1のビットを立てます。
left_handed_batters <- data_sc_2022_bip%>%
group_by(batter, player_name)%>%
summarize(N = n(), Stand = mean(stand == "L"))
一覧としては打者IDが小さい順に表示されているようです。
batter player_name N Stand 1 405395 Pujols, Albert 258 0 2 408234 Cabrera, Miguel 301 0 3 425877 Molina, Yadier 223 0 4 429664 Canó, Robinson 75 1 5 435559 Suzuki, Kurt 113 0 6 443558 Cruz, Nelson 332 0 7 444482 Peralta, David 331 1 8 444489 Piña, Manny 14 0 9 444876 Escobar, Alcides 92 0 10 446334 Longoria, Evan 186 0
この全打者のデータから300打席以上(レギュラー級の選手)の左打者を抽出します。
left_handed_batters<- left_handed_batters%>%
filter(N > 300, Stand == 1)%>%
inner_join(sc_bips)
MLBでは打球角度が10度以下の打球がゴロに分類されます。そのため、filter関数を使って打球角度が10度以下のものを抽出します。
そのデータから、P_opp :打球角度が引っ張りの割合と、Shift:シフトを引いていた割合を算出します。
left_handed_batters%>%
filter(launch_angle < 10)%>%
summarize(N = n(),
P_opp = 100 * mean(hc_x > 125.42, na.rm=TRUE),
Shift = 100* mean(if_fielding_alignment == "Infield shift",na.rm = TRUE))->shift_data
散布図を描きます。
ggplot(shift_data, aes(P_opp, Shift))+
geom_point()+
xlab("Percentage of Grounders Pulled")+
ylab("Percentage of Infield Shifts")
このグラフから、引っ張りゴロ割合が70%を超えてくる打者には守備シフトが引かれることが多かったようです。
引っ張り割合が75%ぐらいなら守備シフトが引かれる確率は50%ほどのようですね。
ちなみに、引っ張り割合の上位3人は、ベリンジャー87.5% 、リゾ85.6%、シュワーバー84.7%でした。
打球角度と打球速度
続いて、Statcastの打球角度と打球速度に注目した解析を行っていきましょう。
2022年全データから打球速度(mps)と打球角度の散布図を出してみます。
data_sc_2022_bip%>%
ggplot(aes(x = launch_speed, y= launch_angle))+
geom_point(alpha = 0.05)
この黒の集団の中心を推察すると打球角度10〜20度、打球速度80〜90マイルほどであろうかと思います。
ここで、さらにそれぞれの打球がヒットになる確率がどうであるかの情報をも負荷します。
打球の分類についてガイドラインを作成します。
10度以下はゴロ、10〜25度はラインドライブ、25度以上はフライとします。
guidelines <- tibble(
launch_angle = c(10, 25, 50),
launch_speed = 40,
label = c("Ground balls", "Line drives", "Flyballs"))
ev_plot <- data_sc_2022_bip %>%
sample_n(nrow(.) / 2) %>%
ggplot(aes(x = as.numeric(launch_speed), y = as.numeric(launch_angle),
color = as.numeric(estimated_ba_using_speedangle))) +
geom_hline(data = guidelines, aes(yintercept = launch_angle),
color = "black", linetype = 2) +
geom_text(data = guidelines,
aes(label = label, y = launch_angle - 4),
color = "black", hjust = "left") +
geom_point(alpha = 0.05) +
scale_color_gradient("BA", low = crcblue, high = "white") +
scale_x_continuous("Exit velocity (mph)",
limits = c(40, 120)) +
scale_y_continuous("Launch angle (degrees)",
breaks = seq(-75, 75, 25))
はい、これで先程出した白黒の打球速度×打球角度の図のうち、薄い色がヒットで濃い色が凡打というデータとなりました!
そうすると、まず、打球角度25度・打球速度70マイルほどから 打球角度10度・打球速度110マイルぐらいにヒット確率が高くなるラインがあります。
また、打球角度25度・打球速度105マイル付近にもヒット確率が高くなるポイントがあります。
そこで、続いて、wOBAすなわち得点価値を荷重した打撃指標でみてみます。
そうすると、打球角度25度・打球速度105マイル付近にもヒット確率が高くなります。
これより、その周辺がホームランを含む長打が多いということとなります。
このゾーンを「バレルゾーン」とも呼び、この打球を増やすための打者の流行が「フライボール革命」と呼ばれたりするようです!
打球角度は能力なのか??
打球角度について個々で特徴的なものなのかどうか調べてみます。
300打席以上のレギュラー選手において、打球角度の平均とばらつきについて算出します。
regulars2022 <- data_sc_2022_bip%>%
group_by(batter, player_name)%>%
summarize(N = n(),
avg_la = mean(launch_angle, na.rm = TRUE),
var_la = var(launch_angle, na.rm= TRUE))%>%
filter(N>300)
打球角度の平均について上位から順に出力してみます。
regulars2022%>%
arrange(desc(avg_la))
batter player_name N avg_la var_la <int> <chr> <int> <dbl> <dbl> 1 571448 Arenado, Nolan 489 21.7 845. 2 596059 Odor, Rougned 321 21.4 985. 3 623993 Santander, Anthony 457 21.3 935. 4 608070 Ramírez, José 528 20.7 912. 5 527038 Flores, Wilmer 429 20.7 710. 6 571970 Muncy, Max 329 20.6 757. 7 500871 Escobar, Eduardo 372 20.6 607. 8 641355 Bellinger, Cody 360 20.3 813. 9 543760 Semien, Marcus 547 19.9 748. 10 553993 Suárez, Eugenio 352 19.9 601.
そうすると、アレナド選手が打球角度21.7度で一番高いということがわかりました。
アレナド選手は 打率.293、ホームラン30本、出塁率.358、長打率.533、OPS.891でした。
逆に打球角度が低い順で見てみると
regulars2022%>%
arrange(avg_la)
batter player_name N avg_la var_la <int> <chr> <int> <dbl> <dbl> 1 621563 Wendle, Joey 301 2.50 930. 2 677950 Thomas, Alek 312 2.62 836. 3 518934 LeMahieu, DJ 399 3.04 827. 4 543333 Hosmer, Eric 317 3.06 885. 5 592885 Yelich, Christian 416 3.23 731. 6 606132 Tapia, Raimel 334 3.55 835. 7 643396 Kiner-Falefa, Isiah 419 3.95 771. 8 671739 Harris II, Michael 308 4.17 792. 9 665489 Guerrero, Vladimir 526 4.25 876. 10 670032 Lopez, Nicky 384 4.25 888.
最も打球角度平均が低い打者はマーリンズのウェンドル選手でした
打率は.259、ホームラン3本、出塁率.297、長打率.360、OPS.658という成績です。
続いて、全打球に関する情報を扱ってみたいと思います。打球角度があるデータをすべてレギュラー選手データに結合します。
sc_regulars <- data_sc_2022_bip%>%
filter(!is.na(launch_angle)) %>%
inner_join(regulars2022, by = "batter")
これを描いてみます。
la_plot<- ggplot(sc_regulars,
aes(x = launch_angle, group =batter))+
geom_density(size = 0.1, color = "darkgray")+
scale_x_continuous("Launch Angle (degree)")
そして、打球角度平均が最も低い選手と打球角度のばらつきがもっとも小さい選手をハイライトさせます。
highlightとして、2名を抽出し、後ほど使用するラベルの表示位置情報を作成します。
highlight <- regulars2022%>%
filter(avg_la<2.55 | var_la < 520)%>%
mutate(x_coord = ifelse(avg_la < 2.55, -45, 50),
y_coord = ifelse(avg_la < 2.55, 0.01, 0.02))
highlight_regularsとして情報を追加
highlight_regulars <- sc_regulars%>%
filter(!is.na(launch_angle))%>%
inner_join(highlight, by = "batter")
図を描きます。
la_plot+
geom_text_repel(data = highlight,
aes(x = x_coord, label = player_name,
y = y_coord), color = crcblue)+
geom_density(data = highlight_regulars, color=crcblue)
はい、そうすると打球角度のデータができましたね。
ウェンドル選手は10度と-20度ぐらいに山があるように見えます。
ジャッジ選手は、10度と30度ぐらいに山があります。
おまけ 打球速度ランキング
打球角度だけでなく打球速度も気になりますね。2022年最も高速な打球速度を放った選手は誰だったのでしょうか。
ここからは本書には書いてないですが、自分が気になったので調べてみました。
data_sc_2022_bip%>%
arrange(desc(launch_speed))->la2022
la2022%>%
select(pitch_type, game_date,release_speed,player_name,launch_speed)
球種 | 試合 | 球速 | 選手 | 打球速度 | |
1 | SL | 2022-08-24 | 90.9 | Cruz, Oneil | 122.4 |
2 | SL | 2022-06-11 | 81.4 | Stanton, Giancarlo | 119.8 |
3 | SI | 2022-05-03 | 87.3 | Stanton, Giancarlo | 119.8 |
4 | FF | 2022-04-10 | 95.1 | Ohtani, Shohei | 119.1 |
5 | FF | 2022-05-21 | 97.9 | Stanton, Giancarlo | 119.1 |
そうすると8月24日のオニール選手打球だったみたいです。