Skip to contents

Understanding Lineup Optimization

Lineup optimization is a crucial piece of daily fantasy sports (DFS) that involves selecting the best possible combination of players within given constraints to maximize potential points. This process is particularly important in DFS platforms like DraftKings, where participants must create lineups under specific rules and salary caps.

Key aspects of lineup optimization in DFS include:

  1. Salary Cap Management: Balancing high-value players with budget-friendly options to stay within the allocated salary cap.

  2. Position Requirements: Fulfilling specific position quotas required by the contest rules (e.g., 1 QB, 2 RBs, 3 WRs for NFL contests).

  3. Player Projections: Utilizing accurate projections of player performance, which can be based on historical data, recent form, matchups, and other relevant factors.

The draft.kings package provides tools to streamline this optimization process, allowing users to leverage DraftKings’ data and perform lineup optimization programmatically. By default, optimization uses Draft Kings player point projections, but you can pass in your own player point projections. Only NFL and NBA contest types are supported currently.

Prepare schematic

To perform optimization you must first prepare a schematic. A schematic contains all the necessary information to perform optimization including the contest type, set of players, rules, and expected player points.

schematic <- dk_prepare_schematic(draft_group_id = 80584)
dplyr::glimpse(schematic)
#> List of 3
#>  $ draft_group   : tibble [106 × 27] (S3: tbl_df/tbl/data.frame)
#>   ..$ draftable_id          : num [1:106] 26368922 26368923 26368924 26368925 26368926 ...
#>   ..$ first_name            : chr [1:106] "Josh" "Tyreek" "Stefon" "Tua" ...
#>   ..$ last_name             : chr [1:106] "Allen" "Hill" "Diggs" "Tagovailoa" ...
#>   ..$ display_name          : chr [1:106] "Josh Allen" "Tyreek Hill" "Stefon Diggs" "Tua Tagovailoa" ...
#>   ..$ short_name            : chr [1:106] "J. Allen" "T. Hill" "S. Diggs" "T. Tagovailoa" ...
#>   ..$ player_id             : num [1:106] 868199 823156 694041 973947 592195 ...
#>   ..$ player_dk_id          : num [1:106] 11370 11477 17102 468529 18260 ...
#>   ..$ position              : chr [1:106] "QB" "WR" "WR" "QB" ...
#>   ..$ roster_slot_id        : num [1:106] 511 511 511 511 511 511 511 512 511 511 ...
#>   ..$ salary                : num [1:106] 18600 16500 15900 15600 14100 13500 13200 12400 12000 11700 ...
#>   ..$ status                : chr [1:106] "None" "None" "None" "None" ...
#>   ..$ is_swappable          : logi [1:106] FALSE FALSE FALSE FALSE FALSE FALSE ...
#>   ..$ is_disabled           : logi [1:106] FALSE FALSE FALSE FALSE FALSE FALSE ...
#>   ..$ news_status           : chr [1:106] "Recent" "Recent" "Recent" "Recent" ...
#>   ..$ player_image50        : chr [1:106] "https://dkn.gs/sports/images/nfl/players/50/11370.png" "https://dkn.gs/sports/images/nfl/players/50/11477.png" "https://dkn.gs/sports/images/nfl/players/50/17102.png" "https://dkn.gs/sports/images/nfl/players/50/468529.png" ...
#>   ..$ player_image160       : chr [1:106] "https://dkn.gs/sports/images/nfl/players/160/11370.png" "https://dkn.gs/sports/images/nfl/players/160/11477.png" "https://dkn.gs/sports/images/nfl/players/160/17102.png" "https://dkn.gs/sports/images/nfl/players/160/468529.png" ...
#>   ..$ alt_player_image50    : chr [1:106] "" "" "" "" ...
#>   ..$ alt_player_image160   : chr [1:106] "" "" "" "" ...
#>   ..$ team_id               : num [1:106] 324 345 324 345 345 345 345 324 345 345 ...
#>   ..$ team_abbreviation     : chr [1:106] "BUF" "MIA" "BUF" "MIA" ...
#>   ..$ player_game_hash      : chr [1:106] "868199-5819869" "823156-5819869" "694041-5819869" "973947-5819869" ...
#>   ..$ competition_id        : num [1:106] 5819869 5819869 5819869 5819869 5819869 ...
#>   ..$ competition_name      : chr [1:106] "MIA @ BUF" "MIA @ BUF" "MIA @ BUF" "MIA @ BUF" ...
#>   ..$ competition_start_time: chr [1:106] "2023-01-15T18:00:00.0000000Z" "2023-01-15T18:00:00.0000000Z" "2023-01-15T18:00:00.0000000Z" "2023-01-15T18:00:00.0000000Z" ...
#>   ..$ exp_fp                : num [1:106] 39 36.9 24.3 26.5 -0.3 ...
#>   ..$ is_captain            : logi [1:106] TRUE TRUE TRUE TRUE TRUE TRUE ...
#>   ..$ row_number            : int [1:106] 1 2 3 4 5 6 7 8 9 10 ...
#>  $ rules         : tibble [1 × 26] (S3: tbl_df/tbl/data.frame)
#>   ..$ game_type_id                  : int 96
#>   ..$ game_type_name                : chr "Showdown Captain Mode"
#>   ..$ game_type_description         : chr "Create your team from 1 game, while staying under the $50,000 salary cap"
#>   ..$ lineup_configuration_id       : int 81
#>   ..$ unique_players                : logi TRUE
#>   ..$ allow_late_swap               : logi FALSE
#>   ..$ error_status                  : logi NA
#>   ..$ rules_url                     : chr "/help/rules/1/96"
#>   ..$ draft_type                    : chr "SalaryCap"
#>   ..$ allowed_competition_attributes: logi NA
#>   ..$ scoring_divider               : logi NA
#>   ..$ use_optimal_lineups           : logi FALSE
#>   ..$ supports_players_tab          : logi FALSE
#>   ..$ show_bye_week_info            : logi FALSE
#>   ..$ original_draft_type           : logi NA
#>   ..$ is_season_long                : logi FALSE
#>   ..$ team_position_limits          : logi NA
#>   ..$ salary_cap_is_enabled         : logi TRUE
#>   ..$ salary_cap_min_value          : int 0
#>   ..$ salary_cap_max_value          : int 50000
#>   ..$ game_count_is_enabled         : logi FALSE
#>   ..$ game_count_min_value          : logi NA
#>   ..$ game_count_max_value          : logi NA
#>   ..$ team_count_is_enabled         : logi TRUE
#>   ..$ team_count_min_value          : int 2
#>   ..$ team_count_max_value          : logi NA
#>  $ draft_group_id: num 80584
#>  - attr(*, "class")= chr [1:2] "showdown_captain_mode" "list"

Perform optimization

Pass the schematic object to the optimization function:

optimal_lineup <- dk_optimize_lineup(schematic)

Extract solution

Finally, extract the solution from the solved model object:

dk_extract_solution(optimal_lineup) |> dplyr::glimpse()
#> List of 4
#>  $ optimal_lineup:'data.frame':  6 obs. of  26 variables:
#>   ..$ draftable_id          : num [1:6] 26368922 26368976 26368982 26368990 26368996 ...
#>   ..$ first_name            : chr [1:6] "Josh" "Tyreek" "Raheem" "James" ...
#>   ..$ last_name             : chr [1:6] "Allen" "Hill" "Mostert" "Cook" ...
#>   ..$ display_name          : chr [1:6] "Josh Allen" "Tyreek Hill" "Raheem Mostert" "James Cook" ...
#>   ..$ short_name            : chr [1:6] "J. Allen" "T. Hill" "R. Mostert" "J. Cook" ...
#>   ..$ player_id             : num [1:6] 868199 823156 606501 1131012 821895 ...
#>   ..$ player_dk_id          : num [1:6] 11370 11477 19614 640895 14871 ...
#>   ..$ position              : chr [1:6] "QB" "WR" "RB" "RB" ...
#>   ..$ roster_slot_id        : num [1:6] 511 512 512 512 512 512
#>   ..$ salary                : num [1:6] 18600 11000 8000 5400 3800 3200
#>   ..$ status                : chr [1:6] "None" "None" "None" "None" ...
#>   ..$ is_swappable          : logi [1:6] FALSE FALSE FALSE FALSE FALSE FALSE
#>   ..$ is_disabled           : logi [1:6] FALSE FALSE FALSE FALSE FALSE FALSE
#>   ..$ news_status           : chr [1:6] "Recent" "Recent" "Breaking" "Recent" ...
#>   ..$ player_image50        : chr [1:6] "https://dkn.gs/sports/images/nfl/players/50/11370.png" "https://dkn.gs/sports/images/nfl/players/50/11477.png" "https://dkn.gs/sports/images/nfl/players/50/19614.png" "https://dkn.gs/sports/images/nfl/players/50/640895.png" ...
#>   ..$ player_image160       : chr [1:6] "https://dkn.gs/sports/images/nfl/players/160/11370.png" "https://dkn.gs/sports/images/nfl/players/160/11477.png" "https://dkn.gs/sports/images/nfl/players/160/19614.png" "https://dkn.gs/sports/images/nfl/players/160/640895.png" ...
#>   ..$ alt_player_image50    : chr [1:6] "" "" "" "" ...
#>   ..$ alt_player_image160   : chr [1:6] "" "" "" "" ...
#>   ..$ team_id               : num [1:6] 324 345 345 324 345 345
#>   ..$ team_abbreviation     : chr [1:6] "BUF" "MIA" "MIA" "BUF" ...
#>   ..$ player_game_hash      : chr [1:6] "868199-5819869" "823156-5819869" "606501-5819869" "1131012-5819869" ...
#>   ..$ competition_id        : num [1:6] 5819869 5819869 5819869 5819869 5819869 ...
#>   ..$ competition_name      : chr [1:6] "MIA @ BUF" "MIA @ BUF" "MIA @ BUF" "MIA @ BUF" ...
#>   ..$ competition_start_time: chr [1:6] "2023-01-15T18:00:00.0000000Z" "2023-01-15T18:00:00.0000000Z" "2023-01-15T18:00:00.0000000Z" "2023-01-15T18:00:00.0000000Z" ...
#>   ..$ exp_fp                : num [1:6] 39 24.6 17.4 14.1 8.2 8.6
#>   ..$ is_captain            : logi [1:6] TRUE FALSE FALSE FALSE FALSE FALSE
#>  $ draft_group_id: num 80584
#>  $ salary_total  : num 50000
#>  $ exp_fp_total  : num 112