Plays/pitching is functional

This commit is contained in:
Cal Corum 2023-10-21 23:32:05 -05:00
parent edde7a1b82
commit 25be95090a
2 changed files with 566 additions and 7 deletions

View File

@ -1,10 +1,11 @@
from fastapi import APIRouter, Depends, HTTPException, Query, Response from fastapi import APIRouter, Depends, HTTPException, Query, Response
from typing import List, Optional, Literal from typing import List, Optional, Literal
import logging import logging
import pandas as pd
from pydantic import BaseModel, validator from pydantic import BaseModel, validator
from ..db_engine import db, StratPlay, StratGame, Team, Player, model_to_dict, chunked, fn, SQL, \ from ..db_engine import db, StratPlay, StratGame, Team, Player, model_to_dict, chunked, fn, SQL, \
complex_data_to_csv complex_data_to_csv, Decision
from ..dependencies import oauth2_scheme, valid_token, LOG_DATA from ..dependencies import oauth2_scheme, valid_token, LOG_DATA
logging.basicConfig( logging.basicConfig(
@ -128,7 +129,7 @@ async def get_plays(
offense_team_id: list = Query(default=None), defense_team_id: list = Query(default=None), offense_team_id: list = Query(default=None), defense_team_id: list = Query(default=None),
hit: Optional[int] = None, double: Optional[int] = None, triple: Optional[int] = None, hit: Optional[int] = None, double: Optional[int] = None, triple: Optional[int] = None,
homerun: Optional[int] = None, play_num: list = Query(default=None), game_type: list = Query(default=None), homerun: Optional[int] = None, play_num: list = Query(default=None), game_type: list = Query(default=None),
sb: Optional[int] = None, cs: Optional[int] = None, manager_id: list = Query(default=None), sb: Optional[int] = None, cs: Optional[int] = None, csv: Optional[bool] = False,
run: Optional[int] = None, e_run: Optional[int] = None, rbi: list = Query(default=None), run: Optional[int] = None, e_run: Optional[int] = None, rbi: list = Query(default=None),
outs: list = Query(default=None), wild_pitch: Optional[int] = None, is_final_out: Optional[bool] = None, outs: list = Query(default=None), wild_pitch: Optional[int] = None, is_final_out: Optional[bool] = None,
is_go_ahead: Optional[bool] = None, is_tied: Optional[bool] = None, is_new_inning: Optional[bool] = None, is_go_ahead: Optional[bool] = None, is_tied: Optional[bool] = None, is_new_inning: Optional[bool] = None,
@ -204,11 +205,6 @@ async def get_plays(
all_plays = all_plays.where(StratPlay.rbi << rbi) all_plays = all_plays.where(StratPlay.rbi << rbi)
if outs is not None: if outs is not None:
all_plays = all_plays.where(StratPlay.outs << outs) all_plays = all_plays.where(StratPlay.outs << outs)
if manager_id is not None:
all_games = StratGame.select().where(
(StratGame.away_manager_id << manager_id) | (StratGame.home_manager_id << manager_id)
)
all_plays = all_plays.where(StratPlay.game << all_games)
if is_final_out is not None: if is_final_out is not None:
all_plays = all_plays.where(StratPlay.starting_outs + StratPlay.outs == 3) all_plays = all_plays.where(StratPlay.starting_outs + StratPlay.outs == 3)
if is_go_ahead is not None: if is_go_ahead is not None:
@ -255,6 +251,67 @@ async def get_plays(
all_plays = all_plays.paginate(page_num, limit) all_plays = all_plays.paginate(page_num, limit)
if csv:
return_vals = [model_to_dict(x) for x in all_plays]
for x in return_vals:
x['game_id'] = x['game']['id']
x['game_type'] = x['game']['game_type']
x['batter_id'] = x['batter']['player_id']
x['batter_name'] = x['batter']['p_name']
x['batter_cardset'] = x['batter']['cardset']['name']
x['batter_team_id'] = x['batter_team']['id']
x['batter_team_abbrev'] = x['batter_team']['abbrev']
x['pitcher_id'] = x['pitcher']['player_id']
x['pitcher_name'] = x['pitcher']['p_name']
x['pitcher_cardset'] = x['pitcher']['cardset']['name']
x['pitcher_team_id'] = x['pitcher_team']['id']
x['pitcher_team_abbrev'] = x['pitcher_team']['abbrev']
if x['catcher'] is not None:
x['catcher_id'] = x['catcher']['player_id']
x['catcher_name'] = x['catcher']['p_name']
x['catcher_cardset'] = x['catcher']['cardset']['name']
x['catcher_team_id'] = x['catcher_team']['id']
x['catcher_team_abbrev'] = x['catcher_team']['abbrev']
else:
x['catcher_id'] = None
x['catcher_name'] = None
x['catcher_cardset'] = None
x['catcher_team_id'] = None
x['catcher_team_abbrev'] = None
if x['defender'] is not None:
x['defender_id'] = x['defender']['player_id']
x['defender_name'] = x['defender']['p_name']
x['defender_cardset'] = x['defender']['cardset']['name']
x['defender_team_id'] = x['defender_team']['id']
x['defender_team_abbrev'] = x['defender_team']['abbrev']
else:
x['defender_id'] = None
x['defender_name'] = None
x['defender_cardset'] = None
x['defender_team_id'] = None
x['defender_team_abbrev'] = None
if x['runner'] is not None:
x['runner_id'] = x['runner']['player_id']
x['runner_name'] = x['runner']['p_name']
x['runner_cardset'] = x['runner']['cardset']['name']
x['runner_team_id'] = x['runner_team']['id']
x['runner_team_abbrev'] = x['runner_team']['abbrev']
else:
x['runner_id'] = None
x['runner_name'] = None
x['runner_cardset'] = None
x['runner_team_id'] = None
x['runner_team_abbrev'] = None
del x['game'], x['batter'], x['batter_team'], x['pitcher'], x['pitcher_team'], x['catcher'], \
x['catcher_team'], x['defender'], x['defender_team'], x['runner'], x['runner_team']
db.close()
return Response(content=pd.DataFrame(return_vals).to_csv(index=False), media_type='text/csv')
return_plays = { return_plays = {
'count': all_plays.count(), 'count': all_plays.count(),
'plays': [model_to_dict(x, recurse=not short_output) for x in all_plays] 'plays': [model_to_dict(x, recurse=not short_output) for x in all_plays]
@ -263,6 +320,507 @@ async def get_plays(
return return_plays return return_plays
@router.get('/batting')
async def get_batting_totals(
season: list = Query(default=None), week: list = Query(default=None), position: list = Query(default=None),
player_id: list = Query(default=None), min_wpa: Optional[float] = -999, max_wpa: Optional[float] = 999,
group_by: Literal['team', 'player', 'playerteam', 'playergame', 'teamgame', 'league', 'gametype'] = 'player',
min_pa: Optional[int] = 1, team_id: list = Query(default=None), inning: list = Query(default=None),
obc: list = Query(default=None), risp: Optional[bool] = None, game_type: list = Query(default=None),
page_num: Optional[int] = 1, sort: Optional[str] = None, limit: Optional[int] = 500,
short_output: Optional[bool] = False, csv: Optional[bool] = False):
season_games = StratGame.select()
if season is not None:
season_games = season_games.where(StratGame.season << season)
if week is not None:
season_games = season_games.where(StratGame.week << week)
bat_plays = (
StratPlay
.select(StratPlay.batter, StratPlay.game, fn.SUM(StratPlay.pa).alias('sum_pa'),
fn.SUM(StratPlay.ab).alias('sum_ab'), fn.SUM(StratPlay.run).alias('sum_run'),
fn.SUM(StratPlay.hit).alias('sum_hit'), fn.SUM(StratPlay.rbi).alias('sum_rbi'),
fn.SUM(StratPlay.double).alias('sum_double'), fn.SUM(StratPlay.triple).alias('sum_triple'),
fn.SUM(StratPlay.homerun).alias('sum_hr'), fn.SUM(StratPlay.bb).alias('sum_bb'),
fn.SUM(StratPlay.so).alias('sum_so'), StratPlay.batter_team,
fn.SUM(StratPlay.hbp).alias('sum_hbp'), fn.SUM(StratPlay.sac).alias('sum_sac'),
fn.SUM(StratPlay.ibb).alias('sum_ibb'), fn.SUM(StratPlay.gidp).alias('sum_gidp'),
fn.SUM(StratPlay.sb).alias('sum_sb'), fn.SUM(StratPlay.cs).alias('sum_cs'),
fn.SUM(StratPlay.bphr).alias('sum_bphr'), fn.SUM(StratPlay.bpfo).alias('sum_bpfo'),
fn.SUM(StratPlay.bp1b).alias('sum_bp1b'), fn.SUM(StratPlay.bplo).alias('sum_bplo'),
fn.SUM(StratPlay.wpa).alias('sum_wpa'),
fn.COUNT(StratPlay.on_first_final).filter(
StratPlay.on_first_final.is_null(False) & (StratPlay.on_first_final != 4)).alias('count_lo1'),
fn.COUNT(StratPlay.on_second_final).filter(
StratPlay.on_second_final.is_null(False) & (StratPlay.on_second_final != 4)).alias('count_lo2'),
fn.COUNT(StratPlay.on_third_final).filter(
StratPlay.on_third_final.is_null(False) & (StratPlay.on_third_final != 4)).alias('count_lo3'),
fn.COUNT(StratPlay.on_first).filter(StratPlay.on_first.is_null(False)).alias('count_runner1'),
fn.COUNT(StratPlay.on_second).filter(StratPlay.on_second.is_null(False)).alias('count_runner2'),
fn.COUNT(StratPlay.on_third).filter(StratPlay.on_third.is_null(False)).alias('count_runner3'),
fn.COUNT(StratPlay.on_first_final).filter(
StratPlay.on_first_final.is_null(False) & (StratPlay.on_first_final != 4) &
(StratPlay.starting_outs + StratPlay.outs == 3)).alias('count_lo1_3out'),
fn.COUNT(StratPlay.on_second_final).filter(
StratPlay.on_second_final.is_null(False) & (StratPlay.on_second_final != 4) &
(StratPlay.starting_outs + StratPlay.outs == 3)).alias('count_lo2_3out'),
fn.COUNT(StratPlay.on_third_final).filter(
StratPlay.on_third_final.is_null(False) & (StratPlay.on_third_final != 4) &
(StratPlay.starting_outs + StratPlay.outs == 3)).alias('count_lo3_3out')
# fn.COUNT(StratPlay.on_first).filter(StratPlay.on_first.is_null(False) &
# (StratPlay.starting_outs + StratPlay.outs == 3)).alias('count_runner1_3out'),
# fn.COUNT(StratPlay.on_second).filter(StratPlay.on_second.is_null(False) &
# (StratPlay.starting_outs + StratPlay.outs == 3)).alias('count_runner2_3out'),
# fn.COUNT(StratPlay.on_third).filter(StratPlay.on_third.is_null(False) &
# (StratPlay.starting_outs + StratPlay.outs == 3)).alias('count_runner3_3out')
)
.where((StratPlay.game << season_games) & (StratPlay.batter.is_null(False)))
.having(fn.SUM(StratPlay.pa) >= min_pa)
)
run_plays = (
StratPlay
.select(StratPlay.runner, StratPlay.runner_team, fn.SUM(StratPlay.sb).alias('sum_sb'),
fn.SUM(StratPlay.cs).alias('sum_cs'), fn.SUM(StratPlay.pick_off).alias('sum_pick'),
fn.SUM(StratPlay.wpa).alias('sum_wpa'))
.where((StratPlay.game << season_games) & (StratPlay.runner.is_null(False)))
)
if player_id is not None:
all_players = Player.select().where(Player.id << player_id)
bat_plays = bat_plays.where(StratPlay.batter << all_players)
run_plays = run_plays.where(StratPlay.runner << all_players)
if team_id is not None:
all_teams = Team.select().where(Team.id << team_id)
bat_plays = bat_plays.where(StratPlay.batter_team << all_teams)
run_plays = run_plays.where(StratPlay.runner_team << all_teams)
if position is not None:
bat_plays = bat_plays.where(StratPlay.batter_pos << position)
if obc is not None:
bat_plays = bat_plays.where(StratPlay.on_base_code << obc)
if risp is not None:
bat_plays = bat_plays.where(StratPlay.on_base_code << ['100', '101', '110', '111', '010', '011'])
if inning is not None:
bat_plays = bat_plays.where(StratPlay.inning_num << inning)
if game_type is not None:
all_types = [x.lower() for x in game_type]
all_games = StratGame.select().where(fn.Lower(StratGame.game_type) << all_types)
bat_plays = bat_plays.where(StratPlay.game << all_games)
run_plays = run_plays.where(StratPlay.game << all_games)
if group_by is not None:
if group_by == 'player':
bat_plays = bat_plays.group_by(StratPlay.batter)
run_plays = run_plays.group_by(StratPlay.runner)
elif group_by == 'team':
bat_plays = bat_plays.group_by(StratPlay.batter_team)
run_plays = run_plays.group_by(StratPlay.runner_team)
elif group_by == 'playerteam':
bat_plays = bat_plays.group_by(StratPlay.batter, StratPlay.batter_team)
run_plays = run_plays.group_by(StratPlay.runner, StratPlay.runner_team)
elif group_by == 'playergame':
bat_plays = bat_plays.group_by(StratPlay.batter, StratPlay.game)
run_plays = run_plays.group_by(StratPlay.runner, StratPlay.game)
elif group_by == 'teamgame':
bat_plays = bat_plays.group_by(StratPlay.batter_team, StratPlay.game)
run_plays = run_plays.group_by(StratPlay.runner_team, StratPlay.game)
elif group_by == 'league':
bat_plays = bat_plays.join(StratGame)
bat_plays = bat_plays.group_by(StratPlay.game.season)
run_plays = run_plays.join(StratGame)
run_plays = run_plays.group_by(StratPlay.game.season)
elif group_by == 'gametype':
bat_plays = bat_plays.join(StratGame)
bat_plays = bat_plays.group_by(StratPlay.game.game_type)
run_plays = run_plays.join(StratGame)
run_plays = run_plays.group_by(StratPlay.game.game_type)
elif group_by == 'playerteamgametype':
bat_plays = bat_plays.join(StratGame)
bat_plays = bat_plays.group_by(StratPlay.batter, StratPlay.batter_team, StratPlay.game.game_type)
run_plays = run_plays.join(StratGame)
run_plays = run_plays.group_by(StratPlay.runner, StratPlay.runner_team, StratPlay.game.game_type)
if sort is not None:
if sort == 'player':
bat_plays = bat_plays.order_by(StratPlay.batter)
run_plays = run_plays.order_by(StratPlay.runner)
elif sort == 'team':
bat_plays = bat_plays.order_by(StratPlay.batter_team)
run_plays = run_plays.order_by(StratPlay.runner_team)
elif sort == 'wpa-desc':
bat_plays = bat_plays.order_by(SQL('sum_wpa').desc())
elif sort == 'wpa-asc':
bat_plays = bat_plays.order_by(SQL('sum_wpa').asc())
elif sort == 'pa-desc':
bat_plays = bat_plays.order_by(SQL('sum_pa').desc())
elif sort == 'pa-asc':
bat_plays = bat_plays.order_by(SQL('sum_pa').asc())
elif sort == 'newest':
bat_plays = bat_plays.order_by(StratPlay.game_id.desc(), StratPlay.play_num.desc())
run_plays = run_plays.order_by(StratPlay.game_id.desc(), StratPlay.play_num.desc())
elif sort == 'oldest':
bat_plays = bat_plays.order_by(StratPlay.game_id, StratPlay.play_num)
run_plays = run_plays.order_by(StratPlay.game_id, StratPlay.play_num)
if limit < 1:
limit = 1
elif limit > 500:
limit = 500
bat_plays = bat_plays.paginate(page_num, limit)
logging.info(f'bat_plays query: {bat_plays}')
logging.info(f'run_plays query: {run_plays}')
return_stats = {
'count': bat_plays.count(),
'stats': []
}
for x in bat_plays:
this_run = run_plays.order_by(StratPlay.id)
if 'player' in group_by:
this_run = this_run.where(StratPlay.runner == x.batter)
if 'game' in group_by:
this_run = this_run.where(StratPlay.game == x.game)
if this_run.count() > 0:
sum_sb = this_run[0].sum_sb
sum_cs = this_run[0].sum_cs
run_wpa = this_run[0].sum_wpa
else:
sum_sb = 0
sum_cs = 0
run_wpa = 0
this_wpa = bat_plays.where(
(StratPlay.wpa >= min_wpa) & (StratPlay.wpa <= max_wpa) & (StratPlay.batter == x.batter)
)
if this_wpa.count() > 0:
sum_wpa = this_wpa[0].sum_wpa
else:
sum_wpa = 0
tot_ab = x.sum_ab if x.sum_ab > 0 else 1
obp = (x.sum_hit + x.sum_bb + x.sum_hbp + x.sum_ibb) / x.sum_pa
slg = (x.sum_hr * 4 + x.sum_triple * 3 + x.sum_double * 2 +
(x.sum_hit - x.sum_double - x.sum_triple - x.sum_hr)) / tot_ab
this_game = 'TOT'
if group_by in ['playergame', 'teamgame']:
this_game = x.game_id if short_output else model_to_dict(x.game, recurse=False)
lob_all_rate, lob_2outs_rate, rbi_rate = 0, 0, 0
if x.count_runner1 + x.count_runner2 + x.count_runner3 > 0:
lob_all_rate = (x.count_lo1 + x.count_lo2 + x.count_lo3) / \
(x.count_runner1 + x.count_runner2 + x.count_runner3)
rbi_rate = (x.sum_rbi - x.sum_hr) / (x.count_runner1 + x.count_runner2 + x.count_runner3)
return_stats['stats'].append({
'player': x.batter_id if short_output else model_to_dict(x.batter, recurse=True, max_depth=1),
'team': x.batter_team_id if short_output else model_to_dict(x.batter_team, recurse=True, max_depth=1),
'pa': x.sum_pa,
'ab': x.sum_ab,
'run': x.sum_run,
'hit': x.sum_hit,
'rbi': x.sum_rbi,
'double': x.sum_double,
'triple': x.sum_triple,
'hr': x.sum_hr,
'bb': x.sum_bb,
'so': x.sum_so,
'hbp': x.sum_hbp,
'sac': x.sum_sac,
'ibb': x.sum_ibb,
'gidp': x.sum_gidp,
'sb': sum_sb,
'cs': sum_cs,
'bphr': x.sum_bphr,
'bpfo': x.sum_bpfo,
'bp1b': x.sum_bp1b,
'bplo': x.sum_bplo,
'wpa': sum_wpa + run_wpa,
'avg': x.sum_hit / tot_ab,
'obp': obp,
'slg': slg,
'ops': obp + slg,
'woba': (.69 * x.sum_bb + .72 * x.sum_hbp + .89 * (x.sum_hit - x.sum_double - x.sum_triple - x.sum_hr) +
1.27 * x.sum_double + 1.62 * x.sum_triple + 2.1 * x.sum_hr) / max(x.sum_pa - x.sum_ibb, 1),
'game': this_game,
'lob_all': x.count_lo1 + x.count_lo2 + x.count_lo3,
'lob_all_rate': lob_all_rate,
'lob_2outs': x.count_lo1_3out + x.count_lo2_3out + x.count_lo3_3out,
'rbi%': rbi_rate
})
if csv:
return_vals = return_stats['stats']
if len(return_vals) == 0:
return Response(content=pd.DataFrame().to_csv(index=False), media_type='text/csv')
for x in return_vals:
x['player_id'] = x['player']['player_id']
x['player_name'] = x['player']['p_name']
x['player_cardset'] = x['player']['cardset']['name']
x['team_id'] = x['team']['id']
x['team_abbrev'] = x['team']['abbrev']
del x['player'], x['team']
output = pd.DataFrame(return_vals)
first = ['player_id', 'player_name', 'player_cardset', 'team_id', 'team_abbrev']
exclude = first + ['lob_all', 'lob_all_rate', 'lob_2outs', 'rbi%']
output = output[first + [col for col in output.columns if col not in exclude]]
db.close()
return Response(content=pd.DataFrame(output).to_csv(index=False), media_type='text/csv')
db.close()
return return_stats
@router.get('/pitching')
async def get_pitching_totals(
season: list = Query(default=None), week: list = Query(default=None),
s_type: Literal['regular', 'post', 'total', None] = None, player_id: list = Query(default=None),
group_by: Literal['team', 'player', 'playerteam', 'playergame', 'teamgame', 'league', 'gametype'] = 'player',
min_pa: Optional[int] = 1, team_id: list = Query(default=None), manager_id: list = Query(default=None),
obc: list = Query(default=None), risp: Optional[bool] = None, inning: list = Query(default=None),
page_num: Optional[int] = 1, game_type: list = Query(default=None), sort: Optional[str] = None,
limit: Optional[int] = 500, short_output: Optional[bool] = False, csv: Optional[bool] = False):
season_games = StratGame.select()
if season is not None:
season_games = season_games.where(StratGame.season << season)
if week is not None and s_type is not None:
raise HTTPException(status_code=400, detail=f'Week and s_type parameters cannot be used in the same query')
if week is not None:
season_games = season_games.where(StratGame.week << week)
if s_type is not None:
if s_type == 'regular':
season_games = season_games.where(StratGame.week <= 18)
elif s_type == 'post':
season_games = season_games.where(StratGame.week > 18)
if manager_id is not None:
season_games = season_games.where(
(StratGame.away_manager_id << manager_id) | (StratGame.home_manager_id << manager_id)
)
pit_plays = (
StratPlay
.select(StratPlay.pitcher, StratPlay.pitcher_team, StratPlay.game, fn.SUM(StratPlay.pa).alias('sum_pa'),
fn.SUM(StratPlay.ab).alias('sum_ab'), fn.SUM(StratPlay.run).alias('sum_run'),
fn.SUM(StratPlay.hit).alias('sum_hit'), fn.SUM(StratPlay.rbi).alias('sum_rbi'),
fn.SUM(StratPlay.double).alias('sum_double'), fn.SUM(StratPlay.triple).alias('sum_triple'),
fn.SUM(StratPlay.homerun).alias('sum_hr'), fn.SUM(StratPlay.bb).alias('sum_bb'),
fn.SUM(StratPlay.so).alias('sum_so'), fn.SUM(StratPlay.wpa).alias('sum_wpa'),
fn.SUM(StratPlay.hbp).alias('sum_hbp'), fn.SUM(StratPlay.sac).alias('sum_sac'),
fn.SUM(StratPlay.ibb).alias('sum_ibb'), fn.SUM(StratPlay.gidp).alias('sum_gidp'),
fn.SUM(StratPlay.sb).alias('sum_sb'), fn.SUM(StratPlay.cs).alias('sum_cs'),
fn.SUM(StratPlay.bphr).alias('sum_bphr'), fn.SUM(StratPlay.bpfo).alias('sum_bpfo'),
fn.SUM(StratPlay.bp1b).alias('sum_bp1b'), fn.SUM(StratPlay.bplo).alias('sum_bplo'),
fn.SUM(StratPlay.wild_pitch).alias('sum_wp'), fn.SUM(StratPlay.balk).alias('sum_balk'),
fn.SUM(StratPlay.outs).alias('sum_outs'), fn.SUM(StratPlay.e_run).alias('sum_erun'),
fn.SUM(StratPlay.re24).alias('sum_re24'),
fn.COUNT(StratPlay.on_first_final).filter(
StratPlay.on_first_final.is_null(False) & (StratPlay.on_first_final != 4)).alias('count_lo1'),
fn.COUNT(StratPlay.on_second_final).filter(
StratPlay.on_second_final.is_null(False) & (StratPlay.on_second_final != 4)).alias('count_lo2'),
fn.COUNT(StratPlay.on_third_final).filter(
StratPlay.on_third_final.is_null(False) & (StratPlay.on_third_final != 4)).alias('count_lo3'),
fn.COUNT(StratPlay.on_first).filter(StratPlay.on_first.is_null(False)).alias('count_runner1'),
fn.COUNT(StratPlay.on_second).filter(StratPlay.on_second.is_null(False)).alias('count_runner2'),
fn.COUNT(StratPlay.on_third).filter(StratPlay.on_third.is_null(False)).alias('count_runner3'),
fn.COUNT(StratPlay.on_first_final).filter(
StratPlay.on_first_final.is_null(False) & (StratPlay.on_first_final != 4) &
(StratPlay.starting_outs + StratPlay.outs == 3)).alias('count_lo1_3out'),
fn.COUNT(StratPlay.on_second_final).filter(
StratPlay.on_second_final.is_null(False) & (StratPlay.on_second_final != 4) &
(StratPlay.starting_outs + StratPlay.outs == 3)).alias('count_lo2_3out'),
fn.COUNT(StratPlay.on_third_final).filter(
StratPlay.on_third_final.is_null(False) & (StratPlay.on_third_final != 4) &
(StratPlay.starting_outs + StratPlay.outs == 3)).alias('count_lo3_3out'))
.where((StratPlay.game << season_games) & (StratPlay.pitcher.is_null(False)))
.having(fn.SUM(StratPlay.pa) >= min_pa)
)
all_dec = (
Decision
.select(Decision.pitcher, fn.SUM(Decision.win).alias('sum_win'), fn.SUM(Decision.loss).alias('sum_loss'),
fn.SUM(Decision.hold).alias('sum_hold'), fn.SUM(Decision.is_save).alias('sum_save'),
fn.SUM(Decision.b_save).alias('sum_b_save'), fn.SUM(Decision.irunners).alias('sum_irunners'),
fn.SUM(Decision.irunners_scored).alias('sum_irun_scored'),
fn.SUM(Decision.is_start).alias('sum_gs'), fn.COUNT(Decision.game).alias('sum_game'))
.where(Decision.game << season_games)
)
if player_id is not None:
all_players = Player.select().where(Player.id << player_id)
pit_plays = pit_plays.where(StratPlay.pitcher << all_players)
if team_id is not None:
all_teams = Team.select().where(Team.id << team_id)
pit_plays = pit_plays.where(StratPlay.pitcher_team << all_teams)
if obc is not None:
pit_plays = pit_plays.where(StratPlay.on_base_code << obc)
if risp is not None:
pit_plays = pit_plays.where(StratPlay.on_base_code << ['100', '101', '110', '111', '010', '011'])
if inning is not None:
pit_plays = pit_plays.where(StratPlay.inning_num << inning)
if game_type is not None:
all_types = [x.lower() for x in game_type]
all_games = StratGame.select().where(fn.Lower(StratGame.game_type) << all_types)
pit_plays = pit_plays.where(StratPlay.game << all_games)
if group_by is not None:
if group_by == 'player':
pit_plays = pit_plays.group_by(StratPlay.pitcher)
elif group_by == 'team':
pit_plays = pit_plays.group_by(StratPlay.pitcher_team)
elif group_by == 'playerteam':
pit_plays = pit_plays.group_by(StratPlay.pitcher, StratPlay.pitcher_team)
elif group_by == 'playergame':
pit_plays = pit_plays.group_by(StratPlay.pitcher, StratPlay.game)
elif group_by == 'teamgame':
pit_plays = pit_plays.group_by(StratPlay.pitcher_team, StratPlay.game)
elif group_by == 'league':
pit_plays = pit_plays.join(StratGame)
pit_plays = pit_plays.group_by(StratPlay.game.season)
elif group_by == 'gametype':
pit_plays = pit_plays.join(StratGame)
pit_plays = pit_plays.group_by(StratPlay.game.game_type)
elif group_by == 'playerteamgametype':
pit_plays = pit_plays.join(StratGame)
pit_plays = pit_plays.group_by(StratPlay.pitcher, StratPlay.pitcher_team, StratPlay.game.game_type)
if sort is not None:
if sort == 'player':
pit_plays = pit_plays.order_by(StratPlay.pitcher)
elif sort == 'team':
pit_plays = pit_plays.order_by(StratPlay.pitcher_team)
elif sort == 'wpa-desc':
pit_plays = pit_plays.order_by(SQL('sum_wpa').asc()) # functions seem reversed since pitcher plays negative
elif sort == 'wpa-asc':
pit_plays = pit_plays.order_by(SQL('sum_wpa').desc())
elif sort == 're24-desc':
pit_plays = pit_plays.order_by(SQL('sum_re24').asc()) # functions seem reversed since pitcher plays negative
elif sort == 're24-asc':
pit_plays = pit_plays.order_by(SQL('sum_re24').desc())
elif sort == 'ip-desc':
pit_plays = pit_plays.order_by(SQL('sum_outs').desc())
elif sort == 'ip-asc':
pit_plays = pit_plays.order_by(SQL('sum_outs').asc())
elif sort == 'game-desc':
pit_plays = pit_plays.order_by(SQL('sum_game').desc())
elif sort == 'game-asc':
pit_plays = pit_plays.order_by(SQL('sum_game').asc())
elif sort == 'newest':
pit_plays = pit_plays.order_by(StratPlay.game_id.desc(), StratPlay.play_num.desc())
elif sort == 'oldest':
pit_plays = pit_plays.order_by(StratPlay.game_id, StratPlay.play_num)
if limit < 1:
limit = 1
elif limit > 500:
limit = 500
pit_plays = pit_plays.paginate(page_num, limit)
return_stats = {
'count': pit_plays.count(),
'stats': []
}
for x in pit_plays:
this_dec = all_dec.where(Decision.pitcher == x.pitcher)
tot_outs = x.sum_outs if x.sum_outs > 0 else 1
obp = (x.sum_hit + x.sum_bb + x.sum_hbp + x.sum_ibb) / x.sum_pa
slg = (x.sum_hr * 4 + x.sum_triple * 3 + x.sum_double * 2 +
(x.sum_hit - x.sum_double - x.sum_triple - x.sum_hr)) / max(x.sum_ab, 1)
tot_bb = 0.1 if x.sum_bb == 0 else x.sum_bb
this_game = 'TOT'
if group_by in ['playergame', 'teamgame']:
this_game = x.game_id if short_output else model_to_dict(x.game, recurse=False)
this_dec = all_dec.where((Decision.pitcher == x.pitcher) & (Decision.game == x.game))
lob_all_rate, lob_2outs_rate, rbi_rate = 0, 0, 0
if x.count_runner1 + x.count_runner2 + x.count_runner3 > 0:
lob_all_rate = (x.count_lo1 + x.count_lo2 + x.count_lo3) / \
(x.count_runner1 + x.count_runner2 + x.count_runner3)
rbi_rate = (x.sum_rbi - x.sum_hr) / (x.count_runner1 + x.count_runner2 + x.count_runner3)
return_stats['stats'].append({
'player': x.pitcher_id if short_output else model_to_dict(x.pitcher),
'team': x.pitcher_team_id if short_output else model_to_dict(x.pitcher_team),
'tbf': x.sum_pa,
'outs': x.sum_outs,
'games': this_dec[0].sum_game,
'gs': this_dec[0].sum_gs,
'win': this_dec[0].sum_win,
'loss': this_dec[0].sum_loss,
'hold': this_dec[0].sum_hold,
'save': this_dec[0].sum_save,
'bsave': this_dec[0].sum_b_save,
'ir': this_dec[0].sum_irunners,
'ir_sc': this_dec[0].sum_irun_scored,
'ab': x.sum_ab,
'run': x.sum_run,
'e_run': x.sum_erun,
'hits': x.sum_hit,
'double': x.sum_double,
'triple': x.sum_triple,
'hr': x.sum_hr,
'bb': x.sum_bb,
'so': x.sum_so,
'hbp': x.sum_hbp,
'sac': x.sum_sac,
'ibb': x.sum_ibb,
'gidp': x.sum_gidp,
'sb': x.sum_sb,
'cs': x.sum_cs,
'bphr': x.sum_bphr,
'bpfo': x.sum_bpfo,
'bp1b': x.sum_bp1b,
'bplo': x.sum_bplo,
'wp': x.sum_wp,
'balk': x.sum_balk,
'wpa': x.sum_wpa * -1,
're24': x.sum_re24 * -1,
'era': (x.sum_erun * 27) / tot_outs,
'whip': ((x.sum_bb + x.sum_hit + x.sum_ibb) * 3) / tot_outs,
'avg': x.sum_hit / max(x.sum_ab, 1),
'obp': obp,
'slg': slg,
'ops': obp + slg,
'woba': (.69 * x.sum_bb + .72 * x.sum_hbp + .89 * (x.sum_hit - x.sum_double - x.sum_triple - x.sum_hr) +
1.27 * x.sum_double + 1.62 * x.sum_triple + 2.1 * x.sum_hr) / max(x.sum_pa - x.sum_ibb, 1),
'k/9': x.sum_so * 9 / (tot_outs / 3),
'bb/9': x.sum_bb * 9 / (tot_outs / 3),
'k/bb': x.sum_so / tot_bb,
'game': this_game,
'lob_2outs': x.count_lo1_3out + x.count_lo2_3out + x.count_lo3_3out,
'rbi%': rbi_rate
})
db.close()
if csv:
return_vals = return_stats['stats']
if len(return_vals) == 0:
return Response(content=pd.DataFrame().to_csv(index=False), media_type='text/csv')
for x in return_vals:
x['player_id'] = x['player']['player_id']
x['player_name'] = x['player']['p_name']
x['player_cardset'] = x['player']['cardset']['name']
x['team_id'] = x['team']['id']
x['team_abbrev'] = x['team']['abbrev']
del x['player'], x['team']
output = pd.DataFrame(return_vals)
first = ['player_id', 'player_name', 'player_cardset', 'team_id', 'team_abbrev']
exclude = first + ['lob_2outs', 'rbi%']
output = output[first + [col for col in output.columns if col not in exclude]]
db.close()
return Response(content=pd.DataFrame(output).to_csv(index=False), media_type='text/csv')
return return_stats
@router.get('/{play_id}') @router.get('/{play_id}')
async def get_one_play(play_id: int): async def get_one_play(play_id: int):
if StratPlay.get_or_none(StratPlay.id == play_id) is None: if StratPlay.get_or_none(StratPlay.id == play_id) is None:

View File

@ -208,6 +208,7 @@ async def get_team_lineup(team_id: int, difficulty_name: str, pitcher_name: str,
vr_ops = vr_ratings.obp + vr_ratings.slg vr_ops = vr_ratings.obp + vr_ratings.slg
return model_to_dict(vl_ratings), model_to_dict(vr_ratings), (vl_ops + vr_ops + min(vl_ops, vr_ops)) / 3 return model_to_dict(vl_ratings), model_to_dict(vr_ratings), (vl_ops + vr_ops + min(vl_ops, vr_ops)) / 3
# IDEA: Rank guys by their bat per-position and take the best one that meets a threshold of defensive ability
for position in starting_nine.keys(): for position in starting_nine.keys():
if position == 'DH': if position == 'DH':
# all_bcards = BattingCard.select().where(BattingCard.player << legal_players) # all_bcards = BattingCard.select().where(BattingCard.player << legal_players)