From 75a14cdffb9ce950d3599c76c7c698971732ffea Mon Sep 17 00:00:00 2001 From: mrcaseb Date: Fri, 10 Jul 2020 20:27:41 +0200 Subject: [PATCH] Push nflfastR v2.1.1 --- .Rbuildignore | 1 - .github/workflows/pkgdown.yaml | 49 -------------- .travis.yml | 3 + DESCRIPTION | 22 +++---- NAMESPACE | 2 + NEWS.md | 30 +++++++++ R/helper_add_nflscrapr_mutations.R | 5 +- R/helper_additional_functions.R | 80 ++++++++++++++++++----- R/helper_scrape_nfl.R | 9 +++ man/clean_pbp.Rd | 2 + nflfastR_2.1.0.pdf => nflfastR_2.1.1.pdf | Bin 117691 -> 117802 bytes vignettes/examples.Rmd | 2 +- 12 files changed, 124 insertions(+), 81 deletions(-) delete mode 100644 .github/workflows/pkgdown.yaml rename nflfastR_2.1.0.pdf => nflfastR_2.1.1.pdf (92%) diff --git a/.Rbuildignore b/.Rbuildignore index db63adff..f1a3b1a0 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -16,5 +16,4 @@ ^man/figures/card\.png$ ^man/figures/header_github\.png$ ^man/figures/header_twitter\.png$ -^man/figures/logo\.png$ ^man/figures/nflfastR_logo_fillsize\.png$ diff --git a/.github/workflows/pkgdown.yaml b/.github/workflows/pkgdown.yaml deleted file mode 100644 index e3b6c908..00000000 --- a/.github/workflows/pkgdown.yaml +++ /dev/null @@ -1,49 +0,0 @@ -on: - push: - branches: master - -name: pkgdown - -jobs: - pkgdown: - runs-on: macOS-latest - env: - GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} - steps: - - uses: actions/checkout@v2 - - - uses: r-lib/actions/setup-r@master - - - uses: r-lib/actions/setup-pandoc@master - - - name: Query dependencies - run: | - install.packages('remotes') - saveRDS(remotes::dev_package_deps(dependencies = TRUE), ".github/depends.Rds", version = 2) - writeLines(sprintf("R-%i.%i", getRversion()$major, getRversion()$minor), ".github/R-version") - shell: Rscript {0} - - - name: Cache R packages - uses: actions/cache@v1 - with: - path: ${{ env.R_LIBS_USER }} - key: ${{ runner.os }}-${{ hashFiles('.github/R-version') }}-1-${{ hashFiles('.github/depends.Rds') }} - restore-keys: ${{ runner.os }}-${{ hashFiles('.github/R-version') }}-1- - - - name: Install dependencies - run: | - install.packages("remotes") - install.packages("tidyverse") - install.packages("ggrepel") - install.packages("ggimage") - install.packages("tictoc") - remotes::install_deps(dependencies = TRUE) - remotes::install_dev("pkgdown") - shell: Rscript {0} - - - name: Install package - run: R CMD INSTALL . - - - name: Deploy package - run: pkgdown::deploy_to_branch(new_process = FALSE) - shell: Rscript {0} diff --git a/.travis.yml b/.travis.yml index 11bda832..655d3491 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,7 @@ # R for travis: see documentation at https://docs.travis-ci.com/user/languages/r +os: + - linux + - osx language: r r: diff --git a/DESCRIPTION b/DESCRIPTION index 43970307..a2849710 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Type: Package Package: nflfastR Title: Functions to Efficiently Scrape NFL Play by Play Data -Version: 2.1.0 +Version: 2.1.1 Authors@R: c(person(given = "Sebastian", family = "Carl", @@ -26,8 +26,7 @@ Authors@R: family = "Ventura", role = "ctb", email = "samventura22@gmail.com")) -Description: nflfastR is a set of functions to efficiently - scrape NFL play-by-play data. +Description: A set of functions to efficiently scrape NFL play-by-play data. License: MIT + file LICENSE URL: https://mrcaseb.github.io/nflfastR/, https://github.com/mrcaseb/nflfastR BugReports: https://github.com/mrcaseb/nflfastR/issues @@ -42,23 +41,22 @@ Imports: lubridate, magrittr, mgcv, - progressr, - purrr, + progressr (>= 0.6.0), + purrr (>= 0.3.0), stats, rlang, - stringr, - tibble, - tidyr, - tidyselect, + stringr (>= 1.3.0), + tibble (>= 3.0), + tidyr (>= 1.0.0), + tidyselect (>= 1.0.0), xgboost (>= 1.1) Suggests: DBI, furrr, future, rmarkdown, - RSQLite, - knitr + RSQLite Encoding: UTF-8 LazyData: true RoxygenNote: 7.1.1 -VignetteBuilder: knitr + diff --git a/NAMESPACE b/NAMESPACE index 945740ad..6a04b46b 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -9,10 +9,12 @@ export(fast_scraper_schedules) export(update_db) import(dplyr) importFrom(dplyr,bind_cols) +importFrom(dplyr,case_when) importFrom(dplyr,filter) importFrom(dplyr,first) importFrom(dplyr,group_by) importFrom(dplyr,if_else) +importFrom(dplyr,left_join) importFrom(dplyr,mutate) importFrom(dplyr,rename) importFrom(dplyr,select) diff --git a/NEWS.md b/NEWS.md index f0c2374e..50ba08dd 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,33 @@ +# nflfastR 2.1.1 + +### Functions + +* `clean_pbp()` now standardizes player IDs across the old (1999-2010) and new +(2011+) data sources. Player IDs once again uniquely identify players, and each +unique player has one unique ID (as they did before the NFL data source change): + * For players whose careers finished before 2011, their IDs remain the same + * For players who played in both eras or only in the new era, their ID is + the new ID + * For example, Akili Smith (ID: 00-0015082) and Alex Smith + (ID: 32013030-2d30-3032-3334-3336b638d37d) are both abbreviated as "A.Smith" + but can be distinguished by their IDs, with Akili showing what the old + format ID looks like, and Smith the new one + * Standardization is realized by using an [ID map](https://github.com/guga31bb/nflfastR-data/blob/master/roster-data/legacy_id_map.csv) + available in the data repo created with [this script](https://github.com/guga31bb/nflfastR-data/blob/master/roster-data/legacy_id_map.R) + +* `clean_pbp()` now removes all variables it is about to create to make sure +nothing unexpected can happen + +### Miscellaneous + +* Added minimum version requirements to some package dependencies because +installation broke for some users with outdated packages + +* Made a minor bug fix to catch more out-of-order plays and fixed a bug where some +plays were being incorrectly dropped in older seasons + +* Standardized team names (e.g. `SD` --> `LAC`) in some columns we had missed + # nflfastR 2.1.0 ### Models diff --git a/R/helper_add_nflscrapr_mutations.R b/R/helper_add_nflscrapr_mutations.R index fb8aee1e..9053e892 100644 --- a/R/helper_add_nflscrapr_mutations.R +++ b/R/helper_add_nflscrapr_mutations.R @@ -18,12 +18,13 @@ add_nflscrapr_mutations <- function(pbp) { dplyr::mutate(index = 1 : dplyr::n()) %>% # remove duplicate plays. can't do this with play_id because duplicate plays # sometimes have different play_ids - dplyr::group_by(.data$game_id, .data$quarter, .data$time, .data$play_description) %>% + dplyr::group_by(.data$game_id, .data$quarter, .data$time, .data$play_description, .data$down) %>% dplyr::slice(1) %>% dplyr::ungroup() %>% dplyr::mutate( # Modify the time column for the quarter end: - time = dplyr::if_else(.data$quarter_end == 1, "00:00", .data$time), + time = dplyr::if_else(.data$quarter_end == 1 | + (.data$play_description == "END GAME" & is.na(.data$time)), "00:00", .data$time), time = dplyr::if_else(.data$play_description == 'GAME', "15:00", .data$time), # Create a column with the time in seconds remaining for the quarter: quarter_seconds_remaining = lubridate::period_to_seconds(lubridate::ms(.data$time)) diff --git a/R/helper_additional_functions.R b/R/helper_additional_functions.R index 192b5cdc..0917ea7c 100644 --- a/R/helper_additional_functions.R +++ b/R/helper_additional_functions.R @@ -13,6 +13,8 @@ #' the play description; e.g. 24-M.Lynch instead of M.Lynch. #' The function also standardizes team abbreviations so that, for example, #' the Chargers are always represented by 'LAC' regardless of which year it was. +#' The function also standardizes player IDs for players appearing in both the +#' older era (1999-2010) and the new era (2011+). #' @return The input Data Frame of the paramter 'pbp' with the following columns #' added: #' \describe{ @@ -37,8 +39,17 @@ #' @importFrom stringr str_detect str_extract str_replace_all #' @importFrom glue glue #' @importFrom rlang .data +#' @importFrom tidyselect one_of clean_pbp <- function(pbp) { message('Cleaning up play-by-play. If you run this with a lot of seasons this could take a few minutes.') + + # Load id map to standardize player ids for players that were active before 2011 + # and in or after 2011 meaning they appear with old gsis_ids and new ids + legacy_id_map <- readRDS(url("https://github.com/guga31bb/nflfastR-data/blob/master/roster-data/legacy_id_map.rds?raw=true")) + + # drop existing values of clean_pbp + pbp <- pbp %>% dplyr::select(-tidyselect::one_of(drop.cols)) + r <- pbp %>% dplyr::mutate( #get rid of extraneous spaces that mess with player name finding @@ -91,7 +102,8 @@ clean_pbp <- function(pbp) { passer == "R.Griffin" ~ "R.Griffin III", passer == "Randel El" ~ "A.Randle El", passer == "Randle El" ~ "A.Randle El", - passer == "Van Pelt" ~ "A.Van Pelt", + season <= 2003 & passer == "Van Pelt" ~ "A.Van Pelt", + season > 2003 & passer == "Van Pelt" ~ "B.Van Pelt", passer == "Dom.Davis" ~ "D.Davis", TRUE ~ .data$passer ), @@ -107,7 +119,8 @@ clean_pbp <- function(pbp) { rusher == "R.Griffin" ~ "R.Griffin III", rusher == "Randel El" ~ "A.Randle El", rusher == "Randle El" ~ "A.Randle El", - rusher == "Van Pelt" ~ "A.Van Pelt", + season <= 2003 & rusher == "Van Pelt" ~ "A.Van Pelt", + season > 2003 & rusher == "Van Pelt" ~ "B.Van Pelt", rusher == "Dom.Davis" ~ "D.Davis", TRUE ~ rusher ), @@ -122,7 +135,7 @@ clean_pbp <- function(pbp) { c("extra_point","field_goal","kickoff","punt"), 1, 0), # easy filter: play is 1 if a "normal" play (including penalties), or 0 otherwise # with thanks to Lee Sharpe for the code - play=dplyr::if_else(!is.na(.data$epa) & !is.na(.data$posteam) & + play = dplyr::if_else(!is.na(.data$epa) & !is.na(.data$posteam) & .data$desc != "*** play under review ***" & substr(.data$desc,1,8) != "Timeout " & .data$play_type %in% c("no_play","pass","run"),1,0) @@ -133,7 +146,8 @@ clean_pbp <- function(pbp) { "side_of_field", "forced_fumble_player_1_team", "forced_fumble_player_2_team", "solo_tackle_1_team", "solo_tackle_2_team", "assist_tackle_1_team", "assist_tackle_2_team", "assist_tackle_3_team", "assist_tackle_4_team", - "fumbled_1_team", "fumbled_2_team", "fumble_recovery_1_team", "fumble_recovery_2_team" + "fumbled_1_team", "fumbled_2_team", "fumble_recovery_1_team", "fumble_recovery_2_team", + "yrdln", "end_yard_line", "drive_start_yard_line", "drive_end_yard_line" ), team_name_fn) %>% #Seb's stuff for fixing player ids @@ -162,6 +176,9 @@ clean_pbp <- function(pbp) { name = dplyr::if_else(!is.na(.data$passer), .data$passer, .data$rusher), id = dplyr::if_else(!is.na(.data$passer_id), .data$passer_id, .data$rusher_id) ) %>% + dplyr::mutate_at( + dplyr::vars(.data$passer_id, .data$rusher_id, .data$receiver_id, .data$id, ends_with("player_id")), + update_ids, legacy_id_map) %>% dplyr::arrange(.data$index) %>% dplyr::select(-"index") @@ -181,6 +198,13 @@ receiver_finder <- "(?<=((to)|(for))\\s[:digit:]{0,2}\\-{0,1})" # weird play finder abnormal_play <- "(Lateral)|(lateral)|(pitches to)|(Direct snap to)|(New quarterback for)|(Aborted)|(backwards pass)|(Pass back to)|(Flea-flicker)" +# These columns are being generated by clean_pbp and the function tries to drop +# them in case it is being used on a pbp dataset where the columns already exist +drop.cols <- c( + "success", "passer", "rusher", "receiver", "pass", "rush", "special", + "first_down", "play", "passer_id", "rusher_id", "receiver_id", "name", "id" +) + # custom mode function from https://stackoverflow.com/questions/2547402/is-there-a-built-in-function-for-finding-the-mode/8189441 custom_mode <- function(x, na.rm = TRUE) { if(na.rm){x <- x[!is.na(x)]} @@ -188,22 +212,42 @@ custom_mode <- function(x, na.rm = TRUE) { return(ux[which.max(tabulate(match(x, ux)))]) } -#just a function to help with standardizing team abbreviations used in clean_pbp() +# fixes team names on columns with yard line +# example: 'SD 49' --> 'LAC 49' +# thanks to awgymer for the contribution: +# https://github.com/mrcaseb/nflfastR/issues/29#issuecomment-654592195 team_name_fn <- function(var) { - dplyr::case_when( - var %in% "JAC" ~ "JAX", - var %in% "STL" ~ "LA", - var %in% "SL" ~ "LA", - var %in% "ARZ" ~ "ARI", - var %in% "BLT" ~ "BAL", - var %in% "CLV" ~ "CLE", - var %in% "HST" ~ "HOU", - var %in% "SD" ~ "LAC", - var %in% "OAK" ~ "LV", - TRUE ~ var + stringr::str_replace_all( + var, + c( + "JAC" = "JAX", + "STL" = "LA", + "SL" = "LA", + "ARZ" = "ARI", + "BLT" = "BAL", + "CLV" = "CLE", + "HST" = "HOU", + "SD" = "LAC", + "OAK" = "LV" + ) ) } +#' @importFrom tibble tibble +#' @importFrom rlang .data +#' @importFrom dplyr left_join mutate case_when +update_ids <- function(var, id_map) { + join <- tibble::tibble(id = var) %>% + dplyr::left_join(id_map, by = c("id" = "gsis_id")) %>% + dplyr::mutate( + out_id = dplyr::case_when( + is.na(.data$new_id) ~ .data$id, + TRUE ~ .data$new_id + ) + ) + return(join$out_id) +} + #' Compute QB epa #' #' @param d is a Data frame of play-by-play data scraped using \code{\link{fast_scraper}}. @@ -213,8 +257,12 @@ team_name_fn <- function(var) { #' @export #' @import dplyr #' @importFrom rlang .data +#' @importFrom tidyselect one_of add_qb_epa <- function(d) { + # drop existing values of clean_pbp + d <- d %>% dplyr::select(-tidyselect::one_of("qb_epa")) + fumbles_df <- d %>% dplyr::filter(.data$complete_pass == 1 & .data$fumble_lost == 1 & !is.na(.data$epa) & !is.na(.data$down)) %>% dplyr::mutate( diff --git a/R/helper_scrape_nfl.R b/R/helper_scrape_nfl.R index 9e57ac8a..5facbff1 100644 --- a/R/helper_scrape_nfl.R +++ b/R/helper_scrape_nfl.R @@ -229,6 +229,15 @@ get_pbp_nfl <- function(id, dir = NULL) { ) %>% dplyr::mutate_all(dplyr::na_if, "") + # nfl didn't fill in first downs on this game + if (id == '2018_01_ATL_PHI') { + combined <- combined %>% + dplyr::mutate( + first_down_pass = dplyr::if_else(.data$pass_attempt == 1 & .data$first_down == 1, 1, .data$first_down_pass), + first_down_rush = dplyr::if_else(.data$rush_attempt == 1 & .data$first_down == 1, 1, .data$first_down_rush) + ) + } + }, error = function(e) { message("The following error has occured:") diff --git a/man/clean_pbp.Rd b/man/clean_pbp.Rd index 5b7ac565..b082c5a7 100644 --- a/man/clean_pbp.Rd +++ b/man/clean_pbp.Rd @@ -41,4 +41,6 @@ but updated to work with the RS data, which has a different player format in the play description; e.g. 24-M.Lynch instead of M.Lynch. The function also standardizes team abbreviations so that, for example, the Chargers are always represented by 'LAC' regardless of which year it was. +The function also standardizes player IDs for players appearing in both the +older era (1999-2010) and the new era (2011+). } diff --git a/nflfastR_2.1.0.pdf b/nflfastR_2.1.1.pdf similarity index 92% rename from nflfastR_2.1.0.pdf rename to nflfastR_2.1.1.pdf index dbf5bb3347681993c68de1c651a16fe800686563..ff748403c3e7dd045120ea091df4bf21c2848fa5 100644 GIT binary patch delta 9020 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 MG5{c@ERFns0P-z6Gynhq delta 8890 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 Chd@mL diff --git a/vignettes/examples.Rmd b/vignettes/examples.Rmd index 3866bf74..460ff2a3 100644 --- a/vignettes/examples.Rmd +++ b/vignettes/examples.Rmd @@ -200,7 +200,7 @@ nflfastR::calculate_win_probability(data) %>% Not surprisingly, `vegas_wp` increases with the amount a team was coming into the game favored by. Weirdly, the model thinks home teams are more likely to win even when the spread is 0. I'm not sure how much to believe the model on that one, but leaving `home` in the model did make the model better at out of sample predictions, so who knows. -# Example 8: Using the build-in database function +# Example 8: Using the built-in database function If you're comfortable using `dplyr` functions to manipulate and tidy data, you're ready to use a database. Why should you use a database?