Week 11 DraftKings Optimal Lineups
We are BACK with optimal lineups from week 11 simulations! (Better Late than Never!)
Not much commentary this week, we have the sickness roaring through our household, and just had family visiting, so didn’t have much time/energy to make changes. However, I did add some plotly wrappers to some plots, inspired by Jonathan Regenstein’s blog post on IPO exploration
If you want to review the overall code for scraping and optimizing projections, the initial post is here.
Setup
library(data.table)
library(dtplyr)
library(tidyverse)
library(rPref)
library(kableExtra)
library(plotly)
library(scales)
library(labeling)
week <- 11
proj <- readRDS(paste0('week_', week, '_proj.RDS'))
sal <- read_csv(paste0('DKSalaries_wk_', week, '.csv'))
I’ll start with the optimized lineups pulled for the week, with the same details as last time: 10,000 lineups, using the standard deviation of projections, completely individually based (still working on that).
sim_lu <- readRDS(paste0('sim_lineups_week_', week, '.RDS')) %>%
rename(pts_base=points) %>%
select(lineup, Name, team, position, pts_base, pts_pred, sd_pts, Salary)
glimpse(sim_lu)
## Observations: 90,000
## Variables: 8
## Groups: Name [153]
## $ lineup <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2,...
## $ Name <chr> "Cardinals", "Tyler Kroft", "Leonard Fournette", "Chr...
## $ team <chr> "ARI", "BUF", "JAC", "CAR", "JAC", "TBB", "WAS", "CAR...
## $ position <chr> "DST", "TE", "RB", "RB", "WR", "WR", "WR", "QB", "RB"...
## $ pts_base <dbl> 5.841981, 3.451956, 18.860242, 26.315687, 10.922359, ...
## $ pts_pred <dbl> 7.115542, 9.499117, 24.304505, 30.701401, 14.070445, ...
## $ sd_pts <dbl> 1.4228211, 2.1754744, 1.9781903, 3.2835311, 1.6836537...
## $ Salary <dbl> 1500, 2800, 7900, 10500, 4500, 7300, 3300, 5300, 6900...
sim_lu %>%
filter(lineup<=3) %>%
arrange(lineup, position, desc(pts_pred)) %>%
mutate_at(vars(pts_base, pts_pred, sd_pts), function(x) round(x, 2)) %>%
knitr::kable() %>%
kable_styling() %>%
column_spec(1, bold=TRUE) %>%
collapse_rows(columns = 1, valign = 'top') %>%
scroll_box(height = '600px', width = '100%')
lineup | Name | team | position | pts_base | pts_pred | sd_pts | Salary |
---|---|---|---|---|---|---|---|
1 | Cardinals | ARI | DST | 5.84 | 7.12 | 1.42 | 1500 |
Kyle Allen | CAR | QB | 17.93 | 19.02 | 0.67 | 5300 | |
Christian McCaffrey | CAR | RB | 26.32 | 30.70 | 3.28 | 10500 | |
Leonard Fournette | JAC | RB | 18.86 | 24.30 | 1.98 | 7900 | |
Josh Jacobs | OAK | RB | 17.81 | 20.14 | 2.50 | 6900 | |
Tyler Kroft | BUF | TE | 3.45 | 9.50 | 2.18 | 2800 | |
Chris Godwin | TBB | WR | 17.01 | 19.92 | 1.99 | 7300 | |
Dede Westbrook | JAC | WR | 10.92 | 14.07 | 1.68 | 4500 | |
Trey Quinn | WAS | WR | 6.93 | 9.11 | 1.41 | 3300 | |
2 | Cardinals | ARI | DST | 5.84 | 8.91 | 1.42 | 1500 |
Lamar Jackson | BAL | QB | 24.49 | 24.74 | 1.58 | 7700 | |
Alvin Kamara | NOS | RB | 20.48 | 21.58 | 1.11 | 7400 | |
Raheem Mostert | SFO | RB | 7.95 | 10.98 | 2.27 | 3400 | |
Darren Waller | OAK | TE | 14.66 | 17.84 | 2.73 | 5500 | |
Julio Jones | ATL | WR | 19.91 | 21.34 | 1.80 | 7500 | |
Chris Godwin | TBB | WR | 17.01 | 20.89 | 1.99 | 7300 | |
Curtis Samuel | CAR | WR | 12.57 | 17.13 | 1.24 | 5300 | |
Deebo Samuel | SFO | WR | 11.25 | 13.57 | 2.25 | 4000 | |
3 | Saints | NOS | DST | 8.52 | 12.42 | 1.80 | 2900 |
Kyle Allen | CAR | QB | 17.93 | 19.01 | 0.67 | 5300 | |
Dalvin Cook | MIN | RB | 22.93 | 27.37 | 2.14 | 8900 | |
Josh Jacobs | OAK | RB | 17.81 | 19.03 | 2.50 | 6900 | |
Brian Hill | ATL | RB | 13.69 | 15.22 | 2.42 | 4800 | |
Darren Waller | OAK | TE | 14.66 | 15.78 | 2.73 | 5500 | |
John Brown | BUF | WR | 14.54 | 18.37 | 2.07 | 6400 | |
Deebo Samuel | SFO | WR | 11.25 | 16.36 | 2.25 | 4000 | |
Tyler Boyd | CIN | WR | 14.25 | 13.57 | 0.50 | 5200 |
Who is in Optimal Lineups?
ggplotly(
sim_lu %>%
group_by(Name, position, Salary) %>%
dplyr::summarize(lu=n_distinct(lineup)) %>%
ungroup() %>%
group_by(position) %>%
top_n(10, lu) %>%
ungroup() %>%
arrange(position, desc(lu)) %>%
mutate(Name=factor(Name),
Name=fct_reorder(Name, lu)) %>%
ggplot(aes(x=Name, y=round(lu/1000, 2), fill=Salary, text=paste(Name, 'in', lu, 'lineups with', dollar(Salary), 'salary'))) +
geom_bar(stat='identity') +
facet_wrap(~position, ncol = 3, scales='free_y') +
coord_flip() +
#scale_y_continuous(labels = scales::comma) +
scale_fill_viridis_c() +
xlab('') +
ylab('Lineups (Thousands)') +
ggtitle('Top 10 Players Present by Position')
) %>% ggplotly(tooltip = 'text')
(Still new to Plotly, sorry about the weird facet widths and funky labels, but since I’m short on time, I thought the benefit of interactivity was worth the funky formatting)
Some of my observations:
A top-heavy week at QB, we’re still riding Lamar Jackson and Deshaun Watson, with Dak Prescott thrown in there
Alvin Kamar is the top RB represented, with Brian Hill and Miles Sanders being the value plays.
They really upped Michael Thomas’ salary, so we won’t be riding him as hard this week. Deebo Samuel is the most represented WR this week, due to low salary. Hopefully he fixes the drops this week
Second week in a row with a heavy TE favorite, this week being Darren Waller. Eric Ebron is the second most represented.
Cardinals, Saints, and Lions D Most Represented
Who is getting placed in Lineups?
DraftKings provides scoring for 379 players this week, but only 153 make it into optimized lineups. Why is that? To determine, I’ll plot projected points vs salary, colored by whether or not they make it into optimized lineups, and sized by their projection standard deviation
plyr_lu <- sim_lu %>%
group_by(Name, position) %>%
dplyr::summarize(lu=n_distinct(lineup)) %>%
ungroup()
ggplotly(
proj %>%
dplyr::filter(avg_type=='weighted') %>%
mutate(Name = ifelse(pos=="DST", last_name, paste(first_name, last_name))) %>%
inner_join(sal, by=c("Name")) %>%
select(Name, team, position, points, Salary, sd_pts) %>%
left_join(plyr_lu, by='Name') %>%
replace_na(list(lu=0)) %>%
mutate(lu_bin=ifelse(lu==0, '0 Lineups', '>=1 Lineups'),
lu_5=cut(lu,5, labels = FALSE)) %>%
ggplot(aes(x=Salary, y=points, color=lu_bin, size=sd_pts, text=Name)) +
geom_point() +
theme_minimal() +
scale_color_manual(values = c('red', 'blue'), name="") +
geom_smooth(inherit.aes = FALSE, aes(x=Salary, y=points), method = 'lm') +
ylab('Projected Points') +
xlab('Salary') +
ggtitle('Who makes it into Optimized Lineups?') +
scale_x_continuous(labels=scales::dollar))
This week, not many players below the line get into lineups, but some above get excluded due to their small uncertainty. Remember, this method takes players who have the potential to blow up rather than players with solid floors.
Flex Configurations
In DFS lineups, you have an extra spot to use on an RB, WR, and TE of your chosing
sim_lu %>%
group_by(lineup) %>%
mutate(lineup_pts=sum(pts_pred)) %>%
group_by(lineup, position) %>%
mutate(n=n()) %>%
select(lineup, position, n, lineup_pts) %>%
distinct() %>%
spread(key=position, value=n) %>%
filter(RB>=2, TE>=1, WR>=3) %>%
mutate(flex=case_when(RB==3 ~ 'RB',
TE==2 ~ 'TE',
WR==4 ~ 'WR')) %>%
group_by(flex) %>%
dplyr::summarize(pts=median(lineup_pts),
cases=n()) %>%
knitr::kable() %>%
kable_styling(full_width = FALSE)
flex | pts | cases |
---|---|---|
RB | 152.5108 | 6622 |
TE | 152.0526 | 1839 |
WR | 151.8612 | 1539 |
HEAVY RB week this week, with more than 60% of Flex Spots being taken by RBs
Pareto Lineups
lu_df <- sim_lu %>%
group_by(lineup) %>%
dplyr::summarize(lineup_pts=sum(pts_pred),
lineup_sd=sum(sd_pts)) %>%
ungroup()
pto <- psel(lu_df, low(lineup_sd) * high(lineup_pts))
ggplot(lu_df, aes(y=lineup_pts, x=lineup_sd)) +
geom_point() +
geom_point(data=pto, size=5) +
ylab('Lineup Points') +
xlab('Lineup Points St Dev') +
ggtitle('Lineup Points vs Uncertainty',
subtitle = 'Pareto Lineups Bolded')
Here’s a look at the pareto lineups.
psel(lu_df, low(lineup_sd) * high(lineup_pts)) %>%
left_join(sim_lu, by='lineup') %>%
group_by(lineup) %>%
arrange(lineup_pts, position, desc(Salary)) %>%
select(lineup, lineup_pts, lineup_sd, Name, team, position, pts_pred, sd_pts, Salary) %>%
mutate_at(vars(lineup_pts, lineup_sd, pts_pred, sd_pts), function(x) round(x, 2)) %>%
knitr::kable() %>%
kable_styling(fixed_thead = T) %>%
column_spec(1:3, bold=TRUE) %>%
collapse_rows(columns = 1:3, valign = 'top') %>%
scroll_box(height = '700px', width = '100%')
lineup | lineup_pts | lineup_sd | Name | team | position | pts_pred | sd_pts | Salary |
---|---|---|---|---|---|---|---|---|
7674 | 142.50 | 9.78 | Dolphins | MIA | DST | 7.10 | 1.01 | 2500 |
Lamar Jackson | BAL | QB | 26.41 | 1.58 | 7700 | |||
Leonard Fournette | JAC | RB | 21.32 | 1.98 | 7900 | |||
Alvin Kamara | NOS | RB | 21.47 | 1.11 | 7400 | |||
Kenyan Drake | ARI | RB | 15.47 | 1.47 | 5400 | |||
Dallas Goedert | PHI | TE | 9.35 | 0.97 | 3200 | |||
Courtland Sutton | DEN | WR | 15.58 | 0.82 | 6000 | |||
Tyler Boyd | CIN | WR | 13.46 | 0.50 | 5200 | |||
DeVante Parker | MIA | WR | 12.34 | 0.35 | 4700 | |||
7722 | 146.57 | 10.24 | Cardinals | ARI | DST | 5.81 | 1.42 | 1500 |
Dak Prescott | DAL | QB | 22.59 | 0.55 | 6700 | |||
Alvin Kamara | NOS | RB | 21.13 | 1.11 | 7400 | |||
Duke Johnson | HOU | RB | 11.27 | 1.19 | 4000 | |||
Zach Ertz | PHI | TE | 13.80 | 0.67 | 5000 | |||
Julio Jones | ATL | WR | 22.72 | 1.80 | 7500 | |||
Mike Evans | TBB | WR | 20.86 | 1.75 | 7400 | |||
Curtis Samuel | CAR | WR | 14.27 | 1.24 | 5300 | |||
Tyler Boyd | CIN | WR | 14.11 | 0.50 | 5200 | |||
7776 | 147.94 | 10.94 | Cardinals | ARI | DST | 6.63 | 1.42 | 1500 |
Dak Prescott | DAL | QB | 22.36 | 0.55 | 6700 | |||
Dalvin Cook | MIN | RB | 26.74 | 2.14 | 8900 | |||
Alvin Kamara | NOS | RB | 21.34 | 1.11 | 7400 | |||
Tyler Eifert | CIN | TE | 8.60 | 0.75 | 3200 | |||
Michael Thomas | NOS | WR | 27.34 | 1.80 | 9900 | |||
Tyler Boyd | CIN | WR | 14.32 | 0.50 | 5200 | |||
Danny Amendola | DET | WR | 10.86 | 1.28 | 4200 | |||
Kendrick Bourne | SFO | WR | 9.75 | 1.39 | 3000 | |||
5738 | 149.65 | 11.35 | Lions | DET | DST | 6.93 | 1.18 | 1800 |
Dak Prescott | DAL | QB | 22.31 | 0.55 | 6700 | |||
Alvin Kamara | NOS | RB | 20.85 | 1.11 | 7400 | |||
Miles Sanders | PHI | RB | 14.16 | 2.58 | 4100 | |||
Greg Olsen | CAR | TE | 12.10 | 1.07 | 3900 | |||
Julio Jones | ATL | WR | 22.83 | 1.80 | 7500 | |||
Mike Evans | TBB | WR | 20.21 | 1.75 | 7400 | |||
Courtland Sutton | DEN | WR | 16.11 | 0.82 | 6000 | |||
Tyler Boyd | CIN | WR | 14.17 | 0.50 | 5200 | |||
7422 | 150.16 | 11.47 | Cardinals | ARI | DST | 7.17 | 1.42 | 1500 |
Lamar Jackson | BAL | QB | 25.72 | 1.58 | 7700 | |||
Alvin Kamara | NOS | RB | 19.99 | 1.11 | 7400 | |||
James White | NEP | RB | 15.45 | 0.96 | 5400 | |||
Zach Ertz | PHI | TE | 13.62 | 0.67 | 5000 | |||
Julio Jones | ATL | WR | 23.84 | 1.80 | 7500 | |||
Christian Kirk | ARI | WR | 15.06 | 0.90 | 5700 | |||
Tyler Boyd | CIN | WR | 14.78 | 0.50 | 5200 | |||
Kenny Stills | HOU | WR | 14.53 | 2.53 | 4600 | |||
2258 | 151.03 | 11.48 | Cardinals | ARI | DST | 6.32 | 1.42 | 1500 |
Dak Prescott | DAL | QB | 22.96 | 0.55 | 6700 | |||
Dalvin Cook | MIN | RB | 26.62 | 2.14 | 8900 | |||
Alvin Kamara | NOS | RB | 21.44 | 1.11 | 7400 | |||
Greg Olsen | CAR | TE | 12.93 | 1.07 | 3900 | |||
Eric Ebron | IND | TE | 11.73 | 1.64 | 3600 | |||
Julio Jones | ATL | WR | 20.68 | 1.80 | 7500 | |||
Curtis Samuel | CAR | WR | 14.22 | 1.24 | 5300 | |||
Tyler Boyd | CIN | WR | 14.12 | 0.50 | 5200 | |||
7077 | 155.14 | 11.94 | Redskins | WAS | DST | 10.22 | 1.20 | 2800 |
Dak Prescott | DAL | QB | 22.65 | 0.55 | 6700 | |||
Dalvin Cook | MIN | RB | 28.66 | 2.14 | 8900 | |||
Alvin Kamara | NOS | RB | 22.53 | 1.11 | 7400 | |||
Brian Hill | ATL | RB | 18.49 | 2.42 | 4800 | |||
O.J. Howard | TBB | TE | 9.97 | 0.97 | 3600 | |||
DeAndre Hopkins | HOU | WR | 22.55 | 1.81 | 8100 | |||
DeVante Parker | MIA | WR | 12.33 | 0.35 | 4700 | |||
Kendrick Bourne | SFO | WR | 7.75 | 1.39 | 3000 | |||
5943 | 156.00 | 12.64 | Broncos | DEN | DST | 6.53 | 0.73 | 2400 |
Dak Prescott | DAL | QB | 22.68 | 0.55 | 6700 | |||
Dalvin Cook | MIN | RB | 26.09 | 2.14 | 8900 | |||
Brian Hill | ATL | RB | 17.04 | 2.42 | 4800 | |||
Miles Sanders | PHI | RB | 16.75 | 2.58 | 4100 | |||
Zach Ertz | PHI | TE | 13.96 | 0.67 | 5000 | |||
Julio Jones | ATL | WR | 22.97 | 1.80 | 7500 | |||
Curtis Samuel | CAR | WR | 15.27 | 1.24 | 5300 | |||
Tyler Boyd | CIN | WR | 14.72 | 0.50 | 5200 | |||
3116 | 156.18 | 13.14 | Cardinals | ARI | DST | 8.22 | 1.42 | 1500 |
Deshaun Watson | HOU | QB | 24.01 | 1.74 | 6800 | |||
Dalvin Cook | MIN | RB | 30.04 | 2.14 | 8900 | |||
Alvin Kamara | NOS | RB | 20.77 | 1.11 | 7400 | |||
Brian Hill | ATL | RB | 13.92 | 2.42 | 4800 | |||
Zach Ertz | PHI | TE | 14.54 | 0.67 | 5000 | |||
Mike Evans | TBB | WR | 20.62 | 1.75 | 7400 | |||
Tyler Boyd | CIN | WR | 14.85 | 0.50 | 5200 | |||
Kendrick Bourne | SFO | WR | 9.20 | 1.39 | 3000 | |||
7102 | 158.92 | 13.19 | Lions | DET | DST | 6.16 | 1.18 | 1800 |
Dak Prescott | DAL | QB | 22.81 | 0.55 | 6700 | |||
Dalvin Cook | MIN | RB | 26.69 | 2.14 | 8900 | |||
Alvin Kamara | NOS | RB | 22.69 | 1.11 | 7400 | |||
Miles Sanders | PHI | RB | 18.32 | 2.58 | 4100 | |||
Eric Ebron | IND | TE | 12.83 | 1.64 | 3600 | |||
Julio Jones | ATL | WR | 21.25 | 1.80 | 7500 | |||
Tyler Boyd | CIN | WR | 14.78 | 0.50 | 5200 | |||
Dede Westbrook | JAC | WR | 13.40 | 1.68 | 4500 | |||
5223 | 159.34 | 13.23 | Cardinals | ARI | DST | 6.63 | 1.42 | 1500 |
Dak Prescott | DAL | QB | 23.06 | 0.55 | 6700 | |||
Alvin Kamara | NOS | RB | 23.88 | 1.11 | 7400 | |||
Josh Jacobs | OAK | RB | 21.25 | 2.50 | 6900 | |||
Brian Hill | ATL | RB | 19.16 | 2.42 | 4800 | |||
Zach Ertz | PHI | TE | 13.48 | 0.67 | 5000 | |||
DeAndre Hopkins | HOU | WR | 20.87 | 1.81 | 8100 | |||
Tyler Boyd | CIN | WR | 14.29 | 0.50 | 5200 | |||
Deebo Samuel | SFO | WR | 16.71 | 2.25 | 4000 | |||
9981 | 159.72 | 13.52 | Cardinals | ARI | DST | 8.10 | 1.42 | 1500 |
Dak Prescott | DAL | QB | 22.40 | 0.55 | 6700 | |||
Alvin Kamara | NOS | RB | 22.19 | 1.11 | 7400 | |||
Tevin Coleman | SFO | RB | 17.04 | 2.47 | 6100 | |||
Darren Waller | OAK | TE | 20.06 | 2.73 | 5500 | |||
Julio Jones | ATL | WR | 24.11 | 1.80 | 7500 | |||
Calvin Ridley | ATL | WR | 16.61 | 1.26 | 5500 | |||
Tyler Boyd | CIN | WR | 14.99 | 0.50 | 5200 | |||
Dede Westbrook | JAC | WR | 14.22 | 1.68 | 4500 | |||
9574 | 161.18 | 13.69 | Cardinals | ARI | DST | 8.19 | 1.42 | 1500 |
Dak Prescott | DAL | QB | 22.66 | 0.55 | 6700 | |||
Alvin Kamara | NOS | RB | 22.18 | 1.11 | 7400 | |||
Josh Jacobs | OAK | RB | 23.17 | 2.50 | 6900 | |||
Zach Ertz | PHI | TE | 13.80 | 0.67 | 5000 | |||
Eric Ebron | IND | TE | 11.60 | 1.64 | 3600 | |||
Julio Jones | ATL | WR | 21.46 | 1.80 | 7500 | |||
Mike Evans | TBB | WR | 21.81 | 1.75 | 7400 | |||
Deebo Samuel | SFO | WR | 16.30 | 2.25 | 4000 | |||
3623 | 169.36 | 14.81 | Saints | NOS | DST | 12.00 | 1.80 | 2900 |
Kyle Allen | CAR | QB | 18.43 | 0.67 | 5300 | |||
Dalvin Cook | MIN | RB | 28.92 | 2.14 | 8900 | |||
Alvin Kamara | NOS | RB | 22.88 | 1.11 | 7400 | |||
Miles Sanders | PHI | RB | 17.92 | 2.58 | 4100 | |||
Eric Ebron | IND | TE | 11.22 | 1.64 | 3600 | |||
Julio Jones | ATL | WR | 22.15 | 1.80 | 7500 | |||
Courtland Sutton | DEN | WR | 16.84 | 0.82 | 6000 | |||
Deebo Samuel | SFO | WR | 19.00 | 2.25 | 4000 | |||
3825 | 170.96 | 16.47 | Saints | NOS | DST | 12.05 | 1.80 | 2900 |
Dak Prescott | DAL | QB | 23.40 | 0.55 | 6700 | |||
Josh Jacobs | OAK | RB | 26.01 | 2.50 | 6900 | |||
Brian Hill | ATL | RB | 18.70 | 2.42 | 4800 | |||
Mark Andrews | BAL | TE | 18.37 | 1.83 | 6100 | |||
Eric Ebron | IND | TE | 13.84 | 1.64 | 3600 | |||
Michael Thomas | NOS | WR | 28.60 | 1.80 | 9900 | |||
Dede Westbrook | JAC | WR | 14.53 | 1.68 | 4500 | |||
Deebo Samuel | SFO | WR | 15.46 | 2.25 | 4000 | |||
9792 | 172.38 | 19.61 | Saints | NOS | DST | 11.71 | 1.80 | 2900 |
Lamar Jackson | BAL | QB | 26.02 | 1.58 | 7700 | |||
Le’Veon Bell | NYJ | RB | 23.41 | 2.27 | 7200 | |||
Josh Jacobs | OAK | RB | 23.08 | 2.50 | 6900 | |||
Brian Hill | ATL | RB | 18.47 | 2.42 | 4800 | |||
Darren Waller | OAK | TE | 24.38 | 2.73 | 5500 | |||
Amari Cooper | DAL | WR | 23.06 | 2.68 | 7700 | |||
Deebo Samuel | SFO | WR | 14.16 | 2.25 | 4000 | |||
Kendrick Bourne | SFO | WR | 8.09 | 1.39 | 3000 |
Week 11 optimal lineups can be found here