【Rstudio】baseball savantのトラッキングデータを一括で取得

本noteは、MLBが公開しているトラッキングデータを、Rstudioで取得しようというnoteです。

特定の投手(打者)のデータを取得する方法はネットに溢れていますが、1年分の全データをまとめて取得する方法はあまり見かけません。あっても力技のみ。

というわけで、一括で取得する方法をお話しします。


いきなり模範解答

library(tidyverse)
library(baseballr)

statcast <- function(season){
  dates <- seq.Date(as.Date(paste0(season, '-03-01')),
                    as.Date(paste0(season, '-12-01')), by = 'week')
  
  date_grid <- tibble(start_date = dates, 
                      end_date = dates + 6)
  
  map_df(.x = seq_along(date_grid$start_date), 
           ~{message(paste0('\nScraping week of ', date_grid$start_date[.x], '...\n'))
             
             scrape_statcast_savant(start_date = date_grid$start_date[.x],
                                    end_date = date_grid$end_date[.x])
           }
  )
}
sc2022 <- statcast(2022)

sc2016_2022 <- map_df(c(2016:2022), statcast)

ざっくり手順を説明すると、
①seq.Date関数で6日ごとの日付を発生させる
②tibble関数でカレンダーを作成する
③カレンダーを繰り返し関数(map_df)に入れてスクレイピング

以上


詳しい説明。

まず、ベースとなる関数はbaseballrパッケージに収録されている"scrape_statcast_savant"という関数。取得したいデータの期間をstart_dateとend_dateで指定する。

scrape_statcast_savant(start_date = 開始日付, end_date = 終了日付)


1年分欲しい場合、この引数にひたすら日付を書き込んで最後に結合するという作戦もあるが、その力技は労力が半端ない。

目標は

start_date = 2022/03/01, end_date = 2022/03/07
start_date = 2022/03/08, end_date = 2022/03/14
start_date = 2022/03/15, end_date = 2022/03/21

という感じのコードを発生させることである。


ここから詳しい手順。

初めに、3/1から7日置き(1週間置き)の日付を発生させる

dates <- seq.Date(as.Date(paste0(season, '-03-01')),
                    as.Date(paste0(season, '-12-01')), by = 'week')

 datesには2022/3/1, 2022/3/8, 2022/3/15・・・と並ぶ


そしてその日付をカレンダー状に並べる。
開始日付列(start_date)に先ほど発生させた日付を、
終了日付列(end_date)にdates+6した日付を並べる。

date_grid <- tibble(start_date = dates, 
                      end_date = dates + 6)


date_gridのイメージ

 開始日付     終了日付
 2022/3/01  2022/3/07
 2022/3/08  2022/3/14
 2022/3/15  2022/3/21
 2022/3/22  2022/3/28


最後に、map_df関数という繰り返し関数を使って、カレンダーの開始日付と終了日付を行ごとに組み込むようなコードを書く。大元のmap関数はリストに格納されるが、map_df関数はデータフレームとして結合してくれるので、そのままcsvファイルに保存できて便利。

 map_df(.x = seq_along(date_grid$start_date), 
           ~{message(paste0('\nScraping week of ', date_grid$start_date[.x], '...\n'))
             
             scrape_statcast_savant(start_date = date_grid$start_date[.x],
                                    end_date = date_grid$end_date[.x])
           }
  )

まず、seq_alongで.xに行番号を格納する。

"message~"は遊び心で加えただけなので消去可能。
"何日の週のデータを取ってます"というメッセージが表示されるようにしてる。進捗が見えるから案外良い。

start_date = date_grid$start_date[.x]は
「date_gridのstart_date列.x行目のデータを代入」

end_date = date_grid$end_date[.x]は
「date_gridのstart_date列.x行目のデータを代入」

という意味。

カレンダー(date_grid)が

行      開始日付    終了日付
  1  2022/3/01  2022/3/07
  2  2022/3/08  2022/3/14
  3  2022/3/15  2022/3/21
  4  2022/3/22  2022/3/28

なので、

1行目:scrape~(start_date = 2022/03/01, end_date = 2022/03/07)
2行目:scrape~(start_date = 2022/03/08, end_date = 2022/03/14)
3行目:scrape~(start_date = 2022/03/15, end_date = 2022/03/21)

という感じで自動で入る。

あとは、全行分のデータを取得してデータフレームに格納されるまで気長に待つ。

終了。


おまけ

※1週間単位でスクレイピングするとサーバーに負荷がかかって、たまにエラーを吐く。なので3日刻みのバージョンも作った。

statcast <- function(season){
  dates <- seq.Date(as.Date(paste0(season, '-03-01')),
                    as.Date(paste0(season, '-12-01')), by = '4 days')
  
  date_grid <- tibble(start_date = dates, 
                      end_date = dates + 3)
  
  map_df(.x = seq_along(date_grid$start_date), 
           ~{message(paste0('\nScraping week of ', date_grid$start_date[.x], '...\n'))
             
             scrape_statcast_savant(start_date = date_grid$start_date[.x],
                                    end_date = date_grid$end_date[.x])
           }
  )

datesとdate_gridをいじっただけで、枠組みは同じ。それでもエラーを吐くようだったら、2日刻み、1日刻みにする。

2023/04/01追記
データ型(character. numericなど)のズレが原因で、結合にできない事案が確認された。

いいなと思ったら応援しよう!