The hardware and bandwidth for this mirror is donated by METANET, the Webhosting and Full Service-Cloud Provider.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]metanet.ch.
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:
<- espn_connect(season = 2020, league_id = 899513)
sucioboys
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.
<- ff_league(sucioboys)
sucioboys_summary #> 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.
<- ff_rosters(sucioboys)
sucioboys_rosters
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
Cool! Let’s pull in some additional context by adding DynastyProcess player values.
<- dp_values("values-players.csv")
player_values
# 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.
<- dp_playerids() %>%
player_ids 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_rosters %>%
sucioboys_values 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!
<- sucioboys_values %>%
value_summary 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 %>%
value_summary_pct 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.
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!
<- sucioboys_values %>%
age_summary 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
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?
These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.