ffverse / ffscrapr

R API Client for Fantasy Football League Platforms
https://ffscrapr.ffverse.com
Other
76 stars 21 forks source link

ff_starters.espn_conn() Player Projected Score Incorrect Sometimes #397

Closed logan-888 closed 1 year ago

logan-888 commented 1 year ago

Describe the bug In ff_starters(), for espn leagues the projected player score is the same as the actual player score about 23% of the time due to the assumption "assume stats list col returns actual as first list and projected as second" written in the .espn_week_starter function in espn_starters.R

Funnily enough, you predicted this being an issue when it was first implemented https://github.com/ffverse/ffscrapr/issues/323#issuecomment-902679640

Reprex

league_conn <- espn_connect(season = 2022, league_id = 98743043)

starters <- ff_starters(league_conn, weeks = 1:13) 

# This will include times where the player happens to land exactly on their projection, but this occured only 7 times 
starters %>%
  mutate(bugged = ifelse(player_score == projected_score, 1, 0)) %>%
  filter(projected_score != 0) %>%
  count(bugged)

# A tibble: 2 × 2
#  bugged     n
#   <dbl> <int>
#1      0  1538
#2      1   459

starters %>%
filter(player_name == "Micheal Pittman Jr.", week == 1)

# A tibble: 1 × 12
#  week franchise_id franchise_name franchise_score lineup_slot player_score projected_score player_id player_name         pos   team  #eligible_lineup_slots
#  <int>        <int> <chr>                    <dbl> <chr>              <dbl>           <dbl>     <int> <chr>               <chr> <chr> <list>               
#1     1            4 Big  Bald God             125. WR                  27.1            27.1   4035687 Michael Pittman Jr. WR    IND   <list [7]>  

Expected behavior The projected score to be correct, such as below

starters %>%
filter(player_name == "Micheal Pittman Jr.", week == 1)

# A tibble: 1 × 12
#   week franchise_id franchise_name franchise_score lineup_slot player_score projected_score player_id player_name         pos   team  #eligible_lineup_slots
#  <int>        <int> <chr>                    <dbl> <chr>              <dbl>           <dbl>     <int> <chr>               <chr> <chr> <list>               
#1     1            4 Big  Bald God             125. WR                  27.1            14.9   4035687 Michael Pittman Jr. WR    IND   <list [7]> 

Session information

── System Info ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
• R version 4.2.3 (2023-03-15 ucrt)   • Running under: Windows 10 x64 (build 22621)
── ffverse Packages ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
• ffscrapr (1.4.8)  • ffsimulator (1.2.3)  • ffpros (0.1.5)  
── ffverse Options ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
• ffpros.include_metadata: FALSE
• ffpros.sport           : nfl
• ffpros.user_agent      : ffpros/0.1.5 R client package https://github.com/ffverse/ffpros
── ffverse Dependencies ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
• askpass    (1.1)     • httr       (1.4.4)  • Rglpk      (0.6-4)   
• assertthat (0.2.1)   • jsonlite   (1.8.4)  • rlang      (1.0.6)   
• backports  (1.4.1)   • lifecycle  (1.0.3)  • slam       (0.1-50)  
• cachem     (1.0.6)   • magrittr   (2.0.3)  • stringi    (1.7.8)   
• checkmate  (2.1.0)   • memoise    (2.0.1)  • stringr    (1.5.0)   
• cli        (3.6.0)   • mime       (0.12)   • sys        (3.4)     
• cpp11      (0.4.2)   • nflreadr   (1.3.2)  • tibble     (3.1.8)   
• curl       (4.3.2)   • openssl    (2.0.3)  • tidyr      (1.3.0)   
• data.table (1.14.2)  • pillar     (1.8.1)  • tidyselect (1.2.0)   
• dplyr      (1.1.0)   • pkgconfig  (2.0.3)  • tidytable  (0.10.0)  
• fansi      (1.0.3)   • purrr      (1.0.1)  • utf8       (1.2.2)   
• fastmap    (1.1.0)   • R6         (2.5.1)  • vctrs      (0.5.2)   
• generics   (0.1.3)   • rappdirs   (0.3.3)  • withr      (2.5.0)   
• glue       (1.6.2)   • ratelimitr (0.4.1)    
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

Screenshots

Current code that causes the issue: current_error

Additional context

My current solution to the issue:

dplyr::mutate(
      projected_score = ifelse(purrr::map_dbl(.data$player,
                                              ~.x %>%
                                                purrr::pluck("stats",
                                                             2,
                                                             "statSourceId",
                                                             .default = NA_real_)) == 1, #statSourceId of 1 corresponds to projections, 0 corresponds to real stats
                               purrr::map_dbl(.data$player,
                                              ~.x %>%
                                                purrr::pluck("stats",
                                                             2,
                                                             "appliedTotal",
                                                             .default = NA_real_) %>%
                                                round(1)),
                               purrr::map_dbl(.data$player,
                                              ~.x %>%
                                                purrr::pluck("stats",
                                                             1,
                                                             "appliedTotal",
                                                             .default = NA_real_) %>%
                                                round(1))),
      player = NULL)
tanho63 commented 1 year ago

Nice find - and thank you for the reprex + proposed fix! Looks good, my only modifications are to extract the statSourceId first and then pass the index into the retrieval function.

... %>%
    tidyr::hoist("player",
                 "eligible_lineup_slots" = "eligibleSlots",
                 "player_name" = "fullName",
                 "pos" = "defaultPositionId",
                 "team" = "proTeamId",
                 "stats" = "stats"
    ) %>%
    dplyr::mutate(
      which_source_is_projection = purrr::map(
        .data$stats,
        # projections are statSourceId == 1
        # per <https://github.com/ffverse/ffscrapr/issues/397>
        ~ which(purrr::map(.x, "statSourceId") == 1)
      ),
      projected_score = purrr::map2_dbl(
        .data$stats,
        .data$which_source_is_projection,
        ~ {if(length(.y)==0) return(NA_real_) else purrr::pluck(.x, .y, "appliedTotal", .default = NA_real_)}),
      player = NULL,
      stats = NULL,
      which_source_is_projection = NULL
    )
tanho63 commented 1 year ago

If you reinstall from github, this should now be resolved - feel free to reopen/open a new issue otherwise!