DimaKudosh / pydfs-lineup-optimizer

Daily Fantasy Sports lineup optimzer for all popular daily fantasy sports sites
MIT License
419 stars 157 forks source link

Inapplicable conditional stack prevents optimal lineup generation #298

Open coltonfischer opened 3 years ago

coltonfischer commented 3 years ago

I am trying to use the conditional stacks functionality introduced here 353332e5d9ada580b92507597ca9231f75a26a31. I am finding that adding a conditional stack is preventing the optimizer from generating optimal lineups that it would have otherwise generated if no conditional stack was defined. For example in a Showdown NFL slate with no rules/stacks defined, the optimizer is outputting the optimal lineup as:

1. CPT     Sterling Shepard              CPT   NYG            NYG@WAS  40.95          12000.0$  
2. FLEX    Antonio Gibson                FLEX  WAS            NYG@WAS  12.8           9600.0$
3. FLEX    Daniel Jones                  FLEX  NYG            NYG@WAS  22.38          10400.0$
4. FLEX    Darius Slayton                FLEX  NYG            NYG@WAS  9.5            6600.0$
5. FLEX    Dustin Hopkins                FLEX  WAS            NYG@WAS  12.0           3800.0$
6. FLEX    Logan Thomas                  FLEX  WAS            NYG@WAS  12.0           7400.0$

Fantasy Points 109.63
Salary 49800.00

However when I introduce a conditional stack that requires Daniel Jones to be in the FLEX when Darius Slayton is CPT, the optimizer outputs the optimal lineup as:

1. CPT     Daniel Jones                  CPT   NYG            NYG@WAS  33.57          15600.0$  
2. FLEX    Darius Slayton                FLEX  NYG            NYG@WAS  9.5            6600.0$
3. FLEX    Dustin Hopkins                FLEX  WAS            NYG@WAS  12.0           3800.0$
4. FLEX    Kenny Golladay                FLEX  NYG            NYG@WAS  10.4           8200.0$
5. FLEX    Logan Thomas                  FLEX  WAS            NYG@WAS  12.0           7400.0$
6. FLEX    Sterling Shepard              FLEX  NYG            NYG@WAS  27.3           8000.0$

Fantasy Points 104.77
Salary 49600.00

I think that introducing this particular conditional stack in this scenario should have no impact on the generation of the single lineup that the optimizer produced when the conditional stack was not applied because the depends_on player (Darius Slayton CPT) was not selected in the lineup to begin with.

Below is the code I am using the replicate this issue and the DK csv with the player data.

from pydfs_lineup_optimizer import Site, Sport, get_optimizer, PlayersGroup

optimizer = get_optimizer(Site.DRAFTKINGS_CAPTAIN_MODE, Sport.FOOTBALL)
optimizer.load_players_from_csv("DKSalaries.csv")

# When Darius Slayton is Captain, ensure Daniel Jones is in the FLEX
Darius_Slayton_CPT_ID = "19193137"
Daniel_Jones_FLEX_ID = "19193054"

depends_on = optimizer.get_player_by_id(Darius_Slayton_CPT_ID)
group = PlayersGroup([optimizer.get_player_by_id(Daniel_Jones_FLEX_ID)], min_from_group=1, max_from_group=1, depends_on=depends_on)
optimizer.add_players_group(group)

lineup_generator = optimizer.optimize(1)
for lineup in lineup_generator:
    print(lineup)
optimizer.print_statistic()

Please let me know if anyone has any ideas on this.

DimaKudosh commented 3 years ago

Conditional stack doesn't impact on the optimal lineup, you setup optimizer that Daniel Jones FLEX can be used only with Slayton CPT, but Jones FLEX was used in the optimal lineup without any stack, so most optimal lineup with this stack should include Jones FLEX with Slayton CPT or none of them and the new optimal lineup doesn't include Jones FLEX and Slayton CPT.

coltonfischer commented 3 years ago

Perhaps my understanding of the conditional stacking feature is incorrect or I am not properly expressing the rule to the optimizer that I want to have enforced. I am not trying to say Daniel Jones FLEX can be used only with Slayton CPT. What I would like to ensure is that in the event Slayton is CPT, Jones must show up in the FLEX.

So what I want is for this stack to be conditioned upon Slayton CPT being in the lineup. If Slayton CPT is not in the lineup, then the condition is not met and the stack should be ignored.

Is what I am trying to achieve out of the scope of the conditional stacking feature? Is there a way that I can express this type of rule with the way the conditional stacking feature is implemented?

DimaKudosh commented 3 years ago

It applies group only if a conditional player is in the lineup, I'll add an option to allow group without a conditional player, right now you can't do this.

coltonfischer commented 3 years ago

Ok I see. It’d be great if conditional stacks could be implemented the way the author of #222 outlined conditional stacks:

IF player X appears in a lineup, INCLUDE a minimum 1, maximum 3 of players A,B,C

The PlayersGroup API change that you made by introducing depends_on allows for expressing groups in this manner, but it seems to follow an IFF (if and only if) type conditional rather than a simple IF. I hope this makes sense.

coltonfischer commented 3 years ago

I just wanted to follow up with an example case that I trying to accomplish with conditional stacks. I want to target the Chiefs and Chargers game and ensure that if I get one of the QBs then I should have at least 2 pass catchers from the QBs team and at least two players from the opposing team. Here are the four rules that I am trying to enforce with conditional player groups:

1.

When lineups include Patrick Mahomes (QB)
Use at least 2 of:
Tyreek Hill (WR), Travis Kelce (TE), Mecole Hardman (WR), Byron Pringle (WR)

2.

When lineups include Patrick Mahomes (QB)
Use at least 2 of:
Austin Ekeler (RB), Keenan Allen (WR), Jared Cook (TE), Jalen Guyton (WR)

3.

When lineups include Justin Herbert (QB)
Use at least 2 of:
Austin Ekeler (RB), Keenan Allen (WR), Jared Cook (TE), Jalen Guyton (WR)

4.

When lineups include Justin Herbert (QB)
Use at least 2 of:
Tyreek Hill (WR), Travis Kelce (TE), Mecole Hardman (WR), Byron Pringle (WR)

The current implementation of conditional player groups prevents the optimizer from generating any lineups that contain the stacks that I am looking to achieve for this game (regardless of projected point values). If I remove the last two rules (the ones conditioned on Justin Herbert), then the optimizer returns lineups with the KC stack and LAC run back like I would expect.

It makes sense as to why this does not work considering the “if and only if” nature of the conditional player group implementation, but I just wanted to share this use case to further highlight this inefficiency.

coltonfischer commented 3 years ago

Thank you very much for adding the strict_depend parameter. This works great for implementing the conditional stacks that I mentioned in my previous comment. I did notice that the strict_depend parameter seems to get ignored for “at most” type rules. For example if you wanted to enforce a single rule as follows:

When lineups include Patrick Mahomes (QB)
Use at most 1 of:
Austin Ekeler (RB), Keenan Allen (WR), Jared Cook (TE), Jalen Guyton (WR)

The optimizer still enforces the “at most” 1 even when Patrick Mahomes is not selected in the lineup. It would be great if the optimizer would not enforce the “at most” type rule when the depends_on player is not in the lineup and strict_depends is False.

coltonfischer commented 3 years ago

I thought some more about how to enforce the “at most” type conditional stacks that I am looking to achieve and turns out that it is possible by splitting the single conditional stack into multiple normal player groups (player groups without a depends_on). For example, the conditional stack mentioned in my previous comment can be achieved by splitting the conditional stack into six separate player groups as follows:

Use at Most 2 of Patrick Mahomes, Austin Ekeler, Keenan Allen
Use at Most 2 of Patrick Mahomes, Austin Ekeler, Jared Cook
Use at Most 2 of Patrick Mahomes, Austin Ekeler, Jalen Guyton
Use at Most 2 of Patrick Mahomes, Keenan Allen, Jared Cook
Use at Most 2 of Patrick Mahomes, Keenan Allen, Jalen Guyton
Use at Most 2 of Patrick Mahomes, Jared Cook, Jalen Guyton

I am not entirely sure, but I think this same splitting technique could be used to enforce “at most” type conditional stacks for any number of players. It will just result in more player groups for higher numbers of players. While this is a workaround for the limitation I pointed out in my previous comment, it is certainly not ideal to express groups in this split manner.