Author: Tan Ho
Date: 2023-02-11

# ESPN: Basics

#### Tan Ho

#### 2023-02-11

In this vignette, I’ll walk through how to get started with a basic dynasty value analysis on ESPN, pulling in roster data.

We’ll start by loading the packages:

      library(ffscrapr)
      library(dplyr)
      library(tidyr)

In ESPN, you can find the league ID by looking in the URL - it’s the number immediately after ?leagueId in this example URL: https://fantasy.espn.com/football/team?leagueId=899513&seasonId=2020

Let’s set up a connection to this league:

    sucioboys <- espn_connect(season = 2020, league_id = 899513)

    sucioboys
    #> <ESPN connection 2020_899513>
    #> List of 4
    #>  $ platform : chr "ESPN"
    #>  $ season   : chr "2020"
    #>  $ league_id: chr "899513"
    #>  $ cookies  : NULL
    #>  - attr(*, "class")= chr "espn_conn"

I’ve done this with the `espn_connect()` function, although you can also do this from the `ff_connect()` call - they are equivalent. Most if not all of the remaining functions after this point are prefixed with “ff_”.

Cool! Let’s have a quick look at what this league is like.

    sucioboys_summary <- ff_league(sucioboys)
    #> Using request.R from "ffscrapr"

    str(sucioboys_summary)
    #> tibble [1 × 16] (S3: tbl_df/tbl/data.frame)
    #>  $ league_id      : chr "899513"
    #>  $ league_name    : chr "Sucio Boys"
    #>  $ season         : int 2020
    #>  $ league_type    : chr "keeper"
    #>  $ franchise_count: int 10
    #>  $ qb_type        : chr "2QB/SF"
    #>  $ idp            : logi FALSE
    #>  $ scoring_flags  : chr "0.5_ppr"
    #>  $ best_ball      : logi FALSE
    #>  $ salary_cap     : logi FALSE
    #>  $ player_copies  : num 1
    #>  $ years_active   : chr "2018-2020"
    #>  $ qb_count       : chr "1-2"
    #>  $ roster_size    : int 24
    #>  $ league_depth   : num 240
    #>  $ keeper_count   : int 22

Okay, so it’s the Sucio Boys league, it’s a 2QB league with 12 teams, half ppr scoring, and rosters about 240 players.

Let’s grab the rosters now.

    sucioboys_rosters <- ff_rosters(sucioboys)

    head(sucioboys_rosters) # quick snapshot of rosters
    #> # A tibble: 6 × 10
    #>   franchise_id franchise_name playe…¹ playe…² team  pos   eligi…³ status acqui…⁴
    #>          <int> <chr>            <int> <chr>   <chr> <chr> <list>  <chr>  <chr>
    #> 1            1 The Early GGod 4036348 Michae… DAL   WR    <chr>   NORMAL DRAFT
    #> 2            1 The Early GGod 4036131 Noah F… DEN   TE    <chr>   NORMAL DRAFT
    #> 3            1 The Early GGod  -16003 Bears … CHI   DST   <chr>   NORMAL DRAFT
    #> 4            1 The Early GGod   15920 Latavi… NOS   RB    <chr>   NORMAL DRAFT
    #> 5            1 The Early GGod 3055899 Harris… KCC   K     <chr>   NORMAL DRAFT
    #> 6            1 The Early GGod 4241372 Marqui… BAL   WR    <chr>   NORMAL DRAFT
    #> # … with 1 more variable: acquisition_date <dttm>, and abbreviated variable
    #> #   names ¹​player_id, ²​player_name, ³​eligible_pos, ⁴​acquisition_type
    #> # ℹ Use `colnames()` to see all variable names

## Values

Cool! Let’s pull in some additional context by adding DynastyProcess player values.

    player_values <- dp_values("values-players.csv")

    # The values are stored by fantasypros ID since that's where the data comes from.
    # To join it to our rosters, we'll need playerID mappings.

    player_ids <- dp_playerids() %>%
      select(espn_id,fantasypros_id) %>%
      filter(!is.na(espn_id),!is.na(fantasypros_id))

    # We'll be joining it onto rosters, so we can trim down the values dataframe
    # to just IDs, age, and values

    player_values <- player_values %>%
      left_join(player_ids, by = c("fp_id" = "fantasypros_id")) %>%
      select(espn_id,age,ecr_2qb,ecr_pos,value_2qb)

    # we can join the roster's player_ids on the values' espn_id, with a bit of a type conversion first
    sucioboys_values <- sucioboys_rosters %>%
      mutate(player_id = as.character(player_id)) %>%
      left_join(player_values, by = c("player_id"="espn_id")) %>%
      arrange(franchise_id,desc(value_2qb))

    head(sucioboys_values)
    #> # A tibble: 6 × 14
    #>   franchise_id franchise_name playe…¹ playe…² team  pos   eligi…³ status acqui…⁴
    #>          <int> <chr>          <chr>   <chr>   <chr> <chr> <list>  <chr>  <chr>
    #> 1            1 The Early GGod 4242335 Jonath… IND   RB    <chr>   NORMAL DRAFT
    #> 2            1 The Early GGod 4241985 J.K. D… BAL   RB    <chr>   NORMAL DRAFT
    #> 3            1 The Early GGod 2976316 Michae… NOS   WR    <chr>   NORMAL DRAFT
    #> 4            1 The Early GGod 4040715 Jalen … PHI   QB    <chr>   NORMAL ADD
    #> 5            1 The Early GGod 4239993 Tee Hi… CIN   WR    <chr>   NORMAL ADD
    #> 6            1 The Early GGod 4241479 Tua Ta… MIA   QB    <chr>   NORMAL DRAFT
    #> # … with 5 more variables: acquisition_date <dttm>, age <dbl>, ecr_2qb <dbl>,
    #> #   ecr_pos <dbl>, value_2qb <int>, and abbreviated variable names ¹​player_id,
    #> #   ²​player_name, ³​eligible_pos, ⁴​acquisition_type
    #> # ℹ Use `colnames()` to see all variable names

Let’s do some team summaries now!

    value_summary <- sucioboys_values %>%
      group_by(franchise_id,franchise_name,pos) %>%
      summarise(total_value = sum(value_2qb,na.rm = TRUE)) %>%
      ungroup() %>%
      group_by(franchise_id,franchise_name) %>%
      mutate(team_value = sum(total_value)) %>%
      ungroup() %>%
      pivot_wider(names_from = pos, values_from = total_value) %>%
      arrange(desc(team_value)) %>%
      select(franchise_id,franchise_name,team_value,QB,RB,WR,TE)

    value_summary
    #> # A tibble: 10 × 7
    #>    franchise_id franchise_name               team_value    QB    RB    WR    TE
    #>           <int> <chr>                             <int> <int> <int> <int> <int>
    #>  1            5 "The Juggernaut"                  49693  8628 18592 16747  5726
    #>  2            6 "OBJ's Personal Porta Potty"      46447 20424 22738   997  2288
    #>  3            7 "Tony El Tigre"                   44547 15508 17020  5921  6098
    #>  4            2 "Coom  Dumpster"                  41599 13314  2329 24668  1288
    #>  5            4 "I'm Also Sad "                   37216  1467 15597 16565  3587
    #>  6            3 "PAKI STANS"                      32697  6048 11980 12829  1840
    #>  7            1 "The Early GGod"                  32247  6642 13916  9406  2283
    #>  8            9 "RAFI CUNADO"                     31958  6878 10726 13365   989
    #>  9            8 "Big Coomers"                     21493  7416  1453 12408   216
    #> 10           10 "Austin 🐐Drew Lock🐐"            20832  7153   276 13324    79

So with that, we’ve got a team summary of values! I like applying some context, so let’s turn these into percentages - this helps normalise it to your league environment.

    value_summary_pct <- value_summary %>%
      mutate_at(c("team_value","QB","RB","WR","TE"),~.x/sum(.x)) %>%
      mutate_at(c("team_value","QB","RB","WR","TE"),round, 3)

    value_summary_pct
    #> # A tibble: 10 × 7
    #>    franchise_id franchise_name               team_value    QB    RB    WR    TE
    #>           <int> <chr>                             <dbl> <dbl> <dbl> <dbl> <dbl>
    #>  1            5 "The Juggernaut"                  0.139 0.092 0.162 0.133 0.235
    #>  2            6 "OBJ's Personal Porta Potty"      0.129 0.218 0.198 0.008 0.094
    #>  3            7 "Tony El Tigre"                   0.124 0.166 0.148 0.047 0.25
    #>  4            2 "Coom  Dumpster"                  0.116 0.142 0.02  0.195 0.053
    #>  5            4 "I'm Also Sad "                   0.104 0.016 0.136 0.131 0.147
    #>  6            3 "PAKI STANS"                      0.091 0.065 0.105 0.102 0.075
    #>  7            1 "The Early GGod"                  0.09  0.071 0.121 0.075 0.094
    #>  8            9 "RAFI CUNADO"                     0.089 0.074 0.094 0.106 0.041
    #>  9            8 "Big Coomers"                     0.06  0.079 0.013 0.098 0.009
    #> 10           10 "Austin 🐐Drew Lock🐐"            0.058 0.077 0.002 0.106 0.003

Armed with a value summary like this, we can see team strengths and weaknesses pretty quickly, and figure out who might be interested in your positional surpluses and who might have a surplus at a position you want to look at.

## Age

Another question you might ask: what is the average age of any given team?

I like looking at average age by position, but weighted by dynasty value. This helps give a better idea of age for each team - including who might be looking to offload an older veteran!

    age_summary <- sucioboys_values %>%
      filter(pos %in% c("QB","RB","WR","TE")) %>%
      group_by(franchise_id,pos) %>%
      mutate(position_value = sum(value_2qb,na.rm=TRUE)) %>%
      ungroup() %>%
      mutate(weighted_age = age*value_2qb/position_value,
             weighted_age = round(weighted_age, 1)) %>%
      group_by(franchise_id,franchise_name,pos) %>%
      summarise(count = n(),
                age = sum(weighted_age,na.rm = TRUE)) %>%
      pivot_wider(names_from = pos,
                  values_from = c(age,count))

    age_summary
    #> # A tibble: 10 × 10
    #> # Groups:   franchise_id, franchise_name [10]
    #>    franchi…¹ franc…² age_QB age_RB age_TE age_WR count…³ count…⁴ count…⁵ count…⁶
    #>        <int> <chr>    <dbl>  <dbl>  <dbl>  <dbl>   <int>   <int>   <int>   <int>
    #>  1         1 "The E…   23.5   22.4   24.7   26         4       6       3       7
    #>  2         2 "Coom …   28.7   25.9   26.8   25.6       4       7       3       6
    #>  3         3 "PAKI …   29.1   25.3   23.9   25.9       3       6       2       9
    #>  4         4 "I'm A…   35.4   24.8   28.7   27.4       2       5       2       8
    #>  5         5 "The J…   25     24.6   31.6   25.3       3       8       2       7
    #>  6         6 "OBJ's…   24.8   24.7   25.3   23.4       3       6       2       7
    #>  7         7 "Tony …   24.8   25.3   27.8   26.6       3       5       3       6
    #>  8         8 "Big C…   23.5   26     27.2   27.1       3       7       2       6
    #>  9         9 "RAFI …   35.1   25.9   26.4   24.4       3       5       3       8
    #> 10        10 "Austi…   32.2   24.4   32.2   25.5       3       5       3       5
    #> # … with abbreviated variable names ¹​franchise_id, ²​franchise_name, ³​count_QB,
    #> #   ⁴​count_RB, ⁵​count_TE, ⁶​count_WR

## Next steps

In this vignette, I’ve used only a few functions: ff_connect, ff_league, ff_rosters, and dp_values. Now that you’ve gotten this far, why not check out some of the other possibilities?