paper-dynasty-card-creation/batters/stat_prep.py

107 lines
3.9 KiB
Python

import pandas as pd
import pydantic
from pydantic import root_validator, validator
from typing import Literal, Optional
class DataMismatchError(Exception):
pass
class BattingCardModel(pydantic.BaseModel):
player_id: Optional[int] = None
variant: int = 0
steal_low: int = 3
steal_high: int = 20
steal_auto: bool = False
steal_jump: float = 0
bunting: str = 'C'
hit_and_run: str = 'C'
running: int = 10
offense_col: int = None
hand: Literal['R', 'L', 'S'] = 'R'
class CardPositionModel(pydantic.BaseModel):
player_id: int
variant: int = 0
position: Literal['P', 'C', '1B', '2B', '3B', 'SS', 'LF', 'CF', 'RF', 'DH']
innings: int = 1
range: int = 5
error: int = 0
arm: Optional[int] = None
pb: Optional[int] = None
overthrow: Optional[int] = None
@root_validator
def position_validator(cls, values):
if values['position'] in ['C', 'LF', 'CF', 'RF'] and values['arm'] is None:
raise ValueError(f'{values["position"]} must have an arm rating')
if values['position'] == 'C' and (values['pb'] is None or values['overthrow'] is None):
raise ValueError('Catchers must have a pb and overthrow rating')
return values
class BattingCardRatingsModel(pydantic.BaseModel):
battingcard_id: int
vs_hand: Literal['R', 'L', 'vR', 'vL']
homerun: float = 0.0
bp_homerun: float = 0.0
triple: float = 0.0
double_three: float = 0.0
double_two: float = 0.0
double_pull: float = 0.0
single_two: float = 0.0
single_one: float = 0.0
single_center: float = 0.0
bp_single: float = 0.0
hbp: float = 0.0
walk: float = 0.0
strikeout: float = 0.0
lineout: float = 0.0
popout: float = 0.0
flyout_a: float = 0.0
flyout_bq: float = 0.0
flyout_lf_b: float = 0.0
flyout_rf_b: float = 0.0
groundout_a: float = 0.0
groundout_b: float = 0.0
groundout_c: float = 0.0
avg: float = 0.0
obp: float = 0.0
slg: float = 0.0
pull_rate: float = 0.0
center_rate: float = 0.0
slap_rate: float = 0.0
@validator("avg", always=True)
def avg_validator(cls, v, values, **kwargs):
return (values['homerun'] + values['bp_homerun'] / 2 + values['triple'] + values['double_three'] +
values['double_two'] + values['double_pull'] + values['single_two'] + values['single_one'] +
values['single_center'] + values['bp_single'] / 2) / 108
@validator("obp", always=True)
def obp_validator(cls, v, values, **kwargs):
return ((values['hbp'] + values['walk']) / 108) + values['avg']
@validator("slg", always=True)
def slg_validator(cls, v, values, **kwargs):
return (values['homerun'] * 4 + values['bp_homerun'] * 2 + values['triple'] * 3 + values['double_three'] * 2 +
values['double_two'] * 2 + values['double_pull'] * 2 + values['single_two'] + values['single_one'] +
values['single_center'] + values['bp_single'] / 2) / 108
@root_validator
def validate_chance_total(cls, values):
total_chances = (
values['homerun'] + values['bp_homerun'] + values['triple'] + values['double_three'] +
values['double_two'] + values['double_pull'] + values['single_two'] + values['single_one'] +
values['single_center'] + values['bp_single'] + values['hbp'] + values['walk'] +
values['strikeout'] + values['lineout'] + values['popout'] + values['flyout_a'] +
values['flyout_bq'] + values['flyout_lf_b'] + values['flyout_rf_b'] + values['groundout_a'] +
values['groundout_b'] + values['groundout_c'])
if round(total_chances) != 108:
raise ValueError(f'BC {values["battingcard_id"]} must have exactly 108 chances on the card '
f'{values["vs_hand"]}; {round(total_chances)} listed')
return values