-
Notifications
You must be signed in to change notification settings - Fork 13
/
README.Rmd
194 lines (148 loc) · 6.16 KB
/
README.Rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
---
output: github_document
---
<!-- README.md is generated from README.Rmd. Please edit that file -->
```{r setup, include = FALSE}
knitr::opts_chunk$set(
collapse = TRUE,
comment = "#>",
fig.path = "man/figures/README-",
out.width = "100%"
)
```
# coach
<!-- badges: start -->
[![R-CMD-check](https://github.com/dfs-with-r/coach/workflows/R-CMD-check/badge.svg)](https://github.com/dfs-with-r/coach/actions)
[![Coverage status](https://codecov.io/gh/dfs-with-r/coach/branch/master/graph/badge.svg)](https://codecov.io/github/dfs-with-r/coach?branch=master)
<!-- badges: end -->
The goal of coach is to provide functions to optimize lineups for a variety of sites (draftkings, fanduel, fantasydraft) and sports (nba, mlb, nfl, nhl). Not every site/sport combination has been created yet. If you want something added, file an issue.
## Installation
You can install the released version of coach from [github](https://github.com/zamorarr/coach) with:
``` r
remotes::install_github("dfs-with-r/coach")
```
## Usage
Load the library.
```{r load-libraies,message=FALSE}
library(coach)
```
Load lineup data exported from a fantasy site and read it in. Check the documention of the `read_*_*` functions for instructions on how to export the data. For example, for Draftkings you have to goto your contest page and select *Export to csv*.
```{r preview-data,eval=FALSE}
data <- read_dk("mydata.csv")
print(data)
```
```{r preview-data2,echo=FALSE}
# for prettier printing
slim <- function(df) {
cols <- c("player_id", "player", "team", "position", "salary", "fpts_avg", "fpts_proj")
use_cols <- intersect(cols, colnames(df))
df[order(-df[["salary"]]), use_cols]
}
data <- read_dk("tests/testthat/data/dk-nfl.csv")
print(slim(data))
```
Add your custom projections into a column called `fpts_proj`. This is very important! If your projections aren't good then your optimized lineups won't be good either. For this example we'll just add some random noise to the player's season average fantasy points.
```{r random-proj,eval=FALSE}
set.seed(100)
n <- nrow(data)
data$fpts_proj <- rnorm(n, data$fpts_avg)
print(data)
```
```{r random-proj2,echo=FALSE}
n <- nrow(data)
data$fpts_proj <- rnorm(n, data$fpts_avg)
print(slim(data))
```
### Built-In Models
Build a fantasy model. This model contains all the constraints imposed by the site and sport.
```{r build-model}
model <- model_dk_nfl(data)
```
Generate three optimized lineups using your projections and the fantasy model
```{r optimize-model,eval=FALSE}
optimize_generic(data, model, L = 3)
```
```{r optimize-model2,echo=FALSE}
# cleaner printing
results <- optimize_generic(data, model, L = 3)
print(lapply(results, slim))
```
Write these results to a file. This file can be submitted directly to the DFS site.
```{r write-lineups,eval=FALSE}
write_lineups(results, "mylineups.csv", site = "draftkings", sport = "nfl")
```
```{r write-lineups2,echo=FALSE}
write_lineups(results, site = "draftkings", sport = "nfl")
```
### Custom Models
You can now build custom models with the functions `model_generic()` and `add_generic_positions_constraint()`. To start, define a generic model by providing total salary allowed, roster size, and max number of players per team allowed. We will use our NFL data from above.
```{r custom-model}
model <- model_generic(data, total_salary = 50000, roster_size = 9, max_from_team = 4)
```
Now we can provide custom position constraints. These will be in the form of a named list, with FLEX or wildcard positions named with a forward slash (`/`) between positions. In the example below, we have one FLEX position that allows an RB, WR, or TE.
```{r custom-positions}
constraints <- list(
"QB" = 1,
"RB" = 2,
"WR" = 3,
"TE" = 1,
"RB/WR/TE" = 1,
"DST" = 1
)
model <- add_generic_positions_constraint(model, data, constraints)
```
These contraints are actually the same as the draftkings built-in model above, so we should get the same results when we optimize:
```{r custom-optimization,eval=FALSE}
optimize_generic(data, model, L = 3)
```
```{r custom-optimization2,echo=FALSE}
# cleaner printing
results <- optimize_generic(data, model, L = 3)
print(lapply(results, slim))
```
### Max Exposure
Many times you want to limit the exposure of your lineups to certain players (due to effects not captured in the model). You can do this by setting a global `max_exposure` for every player to a constant:
```{r max-exposure, eval=FALSE}
optimize_generic(data, model, L = 5, max_exposure = 3/5)
```
```{r max-exposure-print, echo=FALSE}
# cleaner printing
results <- optimize_generic(data, model, L = 5, max_exposure = 0.5)
print(lapply(results, slim))
```
You can also provide a vector of individual `max_exposure` for every player. I find it is typically easiest to add a column to your data frame that defaults to a global value except for a few specific instances:
```{r individual-max-exposure, message=FALSE}
library(dplyr)
data <- data %>% mutate(
exposure = case_when(
player == "LeSean McCoy" ~ 0.4,
player == "Deshaun Watson" ~ 0.5,
player == "Alex Smith" ~ 0.2,
TRUE ~ 1
)
)
```
You can then reference this column in the optimizer:
```{r individual-max-exposure-optimize, eval=FALSE}
optimize_generic(data, model, L = 5, max_exposure = data$exposure)
```
```{r individual-exposure-optimize-print, echo=FALSE}
# cleaner printing
results <- optimize_generic(data, model, L = 5, max_exposure = data$exposure)
print(lapply(results, slim))
```
### Adding Randomness to Projections
You can also now add randomness to your projections by providing a function. This function will run on `fpts_proj` before each lineup is generated. For example, to generate projections that are randomly distributed around a center value with a standard deviation of 10 you could do this:
```{r random-projections}
n <- nrow(data)
randomness <- function(x) rnorm(n, x, 10)
```
When you generate the lineups you can see how the `fpts_proj` changes between samples.
```{r random-projections-optimize, eval=FALSE}
optimize_generic(data, model, L = 5, randomness = randomness)
```
```{r random-projections-optimize-print, echo=FALSE}
# cleaner printing
results <- optimize_generic(data, model, L = 5, randomness = randomness)
print(lapply(results, slim))
```