pydfs-lineup-optimizer icon indicating copy to clipboard operation
pydfs-lineup-optimizer copied to clipboard

Feature Request: Lineup Ownership

Open cmay10 opened this issue 3 years ago • 6 comments

I am not so much concerned with individual player ownership as much as total lineup ownership.

For example, in PGA if I have six golfers projected at 25% ownership each, that means my lineup is projected to have a ownership of (0.25^6) * 100 = 0.02%. That means in a field of 400,000 you would share a lineup with roughly 100 people. I'm trying to prevent from doing this.

Is there currently a way to set a maximum lineup ownership, and if not could this be added? Thanks.

cmay10 avatar Apr 12 '21 13:04 cmay10

Currently optimizer has set_projected_ownership method and it calculates average ownership of players in lineup. So in your case you can set optimizer.set_projected_ownership(max_projected_ownership=0.25) and lineup will include players with approximately 25% ownership, roughly it should generate close result to what you described. According to this feature it will hard to implement it because MIP problem doesn't support multiplying solver variables (player appearance in lineup is solver variable under the hood) and therefore I can't add it as constraint to MIP problem.

DimaKudosh avatar Apr 13 '21 18:04 DimaKudosh

@DimaKudosh Would it be possible to use the set_projected_ownership method for X amount of players per lineup? For example, what if I wanted each lineup to contain 2 players under 5% projected ownership. The intuition is that you might be able to create more studs and scrubs lineups with a high medium projection but also a decent amount of variance.

McCampy avatar Apr 17 '21 00:04 McCampy

@McCampy You can achieve this without using set_projected_ownership. You can create group with all players under 5% ownership and set min players from this group.

optimizer.add_players_group(PlayersGroup(
   players=[player for player in optimizer.players if p.projected_ownership <= 0.05],
   min_from_group=2,
))

DimaKudosh avatar Apr 17 '21 11:04 DimaKudosh

@DimaKudosh This is perfect, thank you.

McCampy avatar Apr 17 '21 17:04 McCampy

You can implement the constraint as a sum, not a product.

The user of the library would determine the appropriate max_lineup_ownership_sum. In the example above, if you have a field of 400,000 and you want an estimated chance of duplication less than 1%, set max_lineup_ownership_sum ~ .75.

The rule would be something like

prob += lpSum([player_var * projected_ownership for player_var, projected_ownership in player_vars, ownership_projections]) <= max_lineup_ownership_sum

I ran a quick simulation that can give you some guidelines on what the appropriate max_lineup_ownership_sum should be for your use case. For large fields, it looks like < 1 would be a reasonable choice.

import numpy as np
import pandas as pd

field_size = 400000
samples = []
for _ in range(500000):
    owns = np.random.randint(1, 40, size=6) / 100
    samples.append({'ownsum': np.sum(owns), 'stdev': np.std(owns), 'dups': np.product(owns) * field_size})

df = pd.DataFrame(samples)

(
  df
  .assign(ownsum=lambda x: x.ownsum.round(2))
  .groupby('ownsum')
  .agg(avg_dups=('dups', 'mean'))
  .sort_values('ownsum')
)

sansbacon avatar May 06 '21 23:05 sansbacon

@McCampy You can achieve this without using set_projected_ownership. You can create group with all players under 5% ownership and set min players from this group.

optimizer.add_players_group(PlayersGroup(
   players=[player for player in optimizer.players if p.projected_ownership <= 0.05],
   min_from_group=2,
))

@DimaKudosh This was working for a short time for me, now i get this error

NameError Traceback (most recent call last) in 21 22 optimizer.add_players_group(PlayersGroup( ---> 23 players=[player for player in optimizer.players if p.projected_ownership <= 0.05], 24 min_from_group=2, 25 ))

in (.0) 21 22 optimizer.add_players_group(PlayersGroup( ---> 23 players=[player for player in optimizer.players if p.projected_ownership <= 0.05], 24 min_from_group=2, 25 ))

NameError: name 'p' is not defined

lightninglarry avatar Aug 29 '21 22:08 lightninglarry