Skip to content

penalty

Penalty framework

Idea is to replace optimizer rules with penalties. Penalties can be negative (bad) or positive (good). * Advantages * Doesn't throw away reasonable options (125% ownership arbitrary) and is flexible. * Does not require absurdly complex optimizer rules. * Can easily layer penalties on top of each other. * Disadvantages * Takes some fiddling to get the parameters correct.

Possible penalties

  • Individual ownership penalty (global or just high-owned)
  • Cumulative ownership penalty (global or just high-owned)
  • Distances (too many similar lineups)
  • Diversity (another way of measuring too many similar lineups)
  • Position combinations (QB vs DST, WR + own DST, etc.)

DistancePenalty

penalty(self, *, population)

Calculates distance penalty for overlapping lineups

Parameters:

Name Type Description Default
population ndarray

the population

required

Returns:

Type Description
ndarray

np.ndarray: 1D array of float

add parameters for positional weighting

that is, can prioritize distance at WR or other position conversely, can deprioritize distance at RB or other position

Source code in pangadfs/penalty.py
def penalty(self, *, population: np.ndarray) -> np.ndarray:
    """Calculates distance penalty for overlapping lineups

    Args:
        population (np.ndarray): the population

    Returns:
        np.ndarray: 1D array of float

    TODO: add parameters for positional weighting
          that is, can prioritize distance at WR or other position
          conversely, can deprioritize distance at RB or other position
    """
    # one-hot encoded population
    # so, assume pool has ids 0, 1, 2, 3, 4
    # lineup is 1, 2
    # ohe would be [0, 1, 1, 0, 0] for that lineup
    ohe = np.sum((np.arange(population.max()) == population[...,None]-1).astype(int), axis=1)

    # now calculate distance between individuals in population
    # dist is a square matrix same length as population
    b = ohe.reshape(ohe.shape[0], 1, ohe.shape[1])
    dist = np.sqrt(np.einsum('ijk, ijk->ij', ohe-b, ohe-b))
    return 0 - ((dist - dist.mean()) / dist.std())

DiversityPenalty

penalty(self, *, population)

Calculates diversity penalty for overlapping lineups

Parameters:

Name Type Description Default
population ndarray

the population

required

Returns:

Type Description
ndarray

np.ndarray: 1D array of float

Source code in pangadfs/penalty.py
def penalty(self, *, population: np.ndarray) -> np.ndarray:
    """Calculates diversity penalty for overlapping lineups

    Args:
        population (np.ndarray): the population

    Returns:
        np.ndarray: 1D array of float

    """
    uniques = np.unique(population)
    a = (population[..., None] == uniques).sum(1)
    out = np.einsum('ij,kj->ik', a, a)
    diversity = np.sum(out, axis=1) / population.size
    return 0 - ((diversity - diversity.mean()) / diversity.std())

HighOwnershipPenalty

penalty(self, *, ownership, base=3, boost=2)

Calculates penalties that are inverse to projected ownership

Parameters:

Name Type Description Default
ownership ndarray

1D array of ownership

required
base float

the logarithm base, default 3

3
boost float

the constant to boost low-owned players

2

Returns:

Type Description
ndarray

np.ndarray: 1D array of penalties

TODO: implement this method

Source code in pangadfs/penalty.py
def penalty(self, *, ownership: np.ndarray, base: float =3, boost: float = 2) -> np.ndarray:
    """Calculates penalties that are inverse to projected ownership

    Args:
        ownership (np.ndarray): 1D array of ownership
        base (int): the logarithm base, default 3
        boost (int): the constant to boost low-owned players

    Returns:
        np.ndarray: 1D array of penalties

    TODO: implement this method
    """
    pass
    #return 0 - np.log(ownership) / np.log(base) + boost

OwnershipPenalty

penalty(self, *, ownership, base=3, boost=2)

Calculates penalties that are inverse to projected ownership

Parameters:

Name Type Description Default
ownership ndarray

1D array of ownership

required
base float

the logarithm base, default 3

3
boost float

the constant to boost low-owned players

2

Returns:

Type Description
ndarray

np.ndarray: 1D array of penalties

Source code in pangadfs/penalty.py
def penalty(self, *, ownership: np.ndarray, base: float =3, boost: float = 2) -> np.ndarray:
    """Calculates penalties that are inverse to projected ownership

    Args:
        ownership (np.ndarray): 1D array of ownership
        base (int): the logarithm base, default 3
        boost (int): the constant to boost low-owned players

    Returns:
        np.ndarray: 1D array of penalties

    """
    return 0 - np.log(ownership) / np.log(base) + boost