Spaces:
Running on Zero
Running on Zero
Download src/data/archive/statsapi/visualization/evaluation_teamSuccess.py from jjerlee/rinklytics: direct link, hf CLI and curl.
- Browser
- Download file 8.58 kB
-
https://huggingface.co/spaces/jjerlee/rinklytics/resolve/main/src/data/archive/statsapi/visualization/evaluation_teamSuccess.py
- Command line
-
hf download hf://spaces/jjerlee/rinklytics/src/data/archive/statsapi/visualization/evaluation_teamSuccess.py
-
curl -L -o evaluation_teamSuccess.py https://huggingface.co/spaces/jjerlee/rinklytics/resolve/main/src/data/archive/statsapi/visualization/evaluation_teamSuccess.py
8.58 kB
| # Process to evaluate team season succcess, | |
| # over all available play-level data (2011-current) | |
| import numpy as np | |
| import pandas as pd | |
| import matplotlib.pyplot as plt | |
| import matplotlib.pyplot as plt | |
| from matplotlib.ticker import MultipleLocator, FixedFormatter, FixedLocator | |
| plt.rcParams.update({'font.size': 16}) | |
| # Directories - locate your data location from the scraping exercise | |
| # https://github.com/justinjoliver/NHL-Analytics/tree/main/src/data | |
| str_dirc = '__DATA DIR__'; | |
| # import relevant functions and import process data | |
| str_dir_sourceCode = "__SOURE DIR__" | |
| exec(open(str_dir_sourceCode + "/measurement_teamSuccess.py").read()) | |
| # Last year season progress | |
| idx_yr_last = 2022 | |
| list_years = np.arange(2011, idx_yr_last) | |
| for iter_yr in list_years: | |
| # Pull the latest data for process | |
| df_box = pd.read_csv(str_dirc + f"/cleaned/{iter_yr}_02_box.csv", | |
| parse_dates = ['gameDate'], | |
| index_col = 'gameIdx') | |
| # Unpack data | |
| df_box_exnt = df_unpack(df_box) | |
| #df_box_exnt.columns | |
| # Calculate metrics | |
| df_box_exnt = df_metrics(df_box_exnt) | |
| # Aggregate up for team-level statistics | |
| dfteams = df_box_exnt.groupby(['team_tri_for'])\ | |
| .agg( | |
| { | |
| "fenwick_lvl":"sum", | |
| "corsi_lvl":"sum", | |
| "rpe":"last", | |
| "rwin":"last", | |
| "rgame":"last" | |
| } | |
| ) | |
| dfteams.sort_values(by = ["rwin","fenwick_lvl", "corsi_lvl"], inplace = True) | |
| # Join with season-pythagorean expectation | |
| #dfteams = dfteams.join(df_pe_season) | |
| # Normalize KPIs for measurement comparison | |
| dfteams['wp'] = dfteams.rwin / dfteams.rgame | |
| dfteams['kpi_corsi'] = kpinorm(dfteams.corsi_lvl) | |
| dfteams['kpi_fenwick'] = kpinorm(dfteams.fenwick_lvl) | |
| dfteams['kpi_pe'] = kpinorm(dfteams.rpe) | |
| # Coefficient estimates from 2010-2020, calculate fitted win percentage | |
| beta_pyth_old = 0.00809623 * 100 | |
| alpah_pyth_old = 0.042901 | |
| x_starting = 0.3 | |
| x_end = x_starting + 0.45 | |
| y_starting = (x_starting) * beta_pyth_old + alpah_pyth_old | |
| y_end = (x_end) * beta_pyth_old + alpah_pyth_old | |
| dfteams['rwin_fittedPE'] = (dfteams['rpe'] * beta_pyth_old + alpah_pyth_old) * 82 | |
| # drop the first game, | |
| df_box_exnt.loc[df_box_exnt.gameDate_del_against.notnull(), :].head(3) | |
| time_games_all = np.sort(df_box_exnt.gameDate_for.unique()); # by date existing | |
| # Capture the last date. | |
| iter_time = time_games_all[-1]; | |
| # NOTE: while it may be exciting to compute the measure in real time, it takes | |
| # some time to compute it all. I focus on looking at upto the latest available | |
| # data | |
| # Head to head statistics | |
| dff_h2h_com = df_gen_h2h_common(df_box_exnt, iter_time) | |
| # Game pairwise - RPI statistics | |
| dfteams = dfteams.join(pairwise_h2h(df_box_exnt, dff_h2h_com)) | |
| # More head-to-head statistics | |
| dff_h2h_com_win = dff_h2h_com\ | |
| .groupby(['team_tri_for_ow', 'team_tri_for_oow']) \ | |
| .agg( | |
| { | |
| 'game_won_h2h_ow':'sum', | |
| 'game_played_h2h_ow':'sum', | |
| 'game_won_h2h_oow':'sum', | |
| 'game_played_h2h_oow':'sum' | |
| } | |
| ) | |
| # for each opponent, compare who has winning record as common opponent | |
| # I use win ratio | |
| dff_h2h_com_win['h2h_win'] = (\ | |
| (dff_h2h_com_win.game_won_h2h_ow / dff_h2h_com_win.game_played_h2h_ow) > \ | |
| (dff_h2h_com_win.game_won_h2h_oow / dff_h2h_com_win.game_played_h2h_oow) | |
| ) * 1 | |
| # For each team, count how many opponents the team has winning record against | |
| rank_pairwise_win = dff_h2h_com_win.groupby(['team_tri_for_ow']) \ | |
| .agg({'h2h_win':'sum'}) \ | |
| .sort_values(by = 'h2h_win', ascending = False) | |
| rank_pairwise_win.columns = ['pairwise_win'] | |
| # Here the rank can even be more continuous (how much they win instead of count in games) | |
| # Join with the existing team stats | |
| dfteams = dfteams.join(rank_pairwise_win) | |
| # Normalize | |
| dfteams['kpi_pairwise'] = kpinorm(dfteams.pairwise_win) | |
| dfteams['kpi_rpi'] = kpinorm(dfteams.rpi) | |
| dfteams['kpi_wp'] = kpinorm(dfteams.wp) | |
| dfteams['Final'] = dfteams\ | |
| .sort_values(by = 'kpi_wp', ascending = False) \ | |
| .reset_index().index + 1 | |
| dfteams['Final'] = kpinorm(dfteams.Final) | |
| # Data append | |
| # Add season statistics for and against | |
| df_box_exnt = df_box_exnt.merge(dfteams.reset_index(), | |
| on = ['team_tri_for'], suffixes=('', '_for')) \ | |
| .merge(dfteams.reset_index(), | |
| left_on = ['team_tri_against'], | |
| right_on = ['team_tri_for'], | |
| suffixes=('', '_against')) | |
| # Check wins against better opponent | |
| # Is the team-for facing eventual better opponent? | |
| # Using pairwise here - alternatively can use RPI | |
| # ........................................................................... | |
| # Observing win streaks | |
| # Is opponent better than average? | |
| df_box_exnt['idx_OppoGood'] = df_box_exnt.rpi_against > \ | |
| np.quantile(df_box_exnt.rpi_against, 0.75) | |
| # Playing against worse team, thus leading to expected outcome? | |
| df_box_exnt['idx_OppoBetter'] = df_box_exnt.pairwise_win_against < \ | |
| df_box_exnt.pairwise_win | |
| df_box_exnt['idx_OppoBetter'] = df_box_exnt.rpi_against < \ | |
| df_box_exnt.rpi | |
| df_box_exnt['win_for_better'] = df_box_exnt.win_for * df_box_exnt.idx_OppoGood | |
| df_box_exnt['win_for_expected'] = df_box_exnt.win_for * df_box_exnt.idx_OppoBetter | |
| pivot_teamcumwin = df_box_exnt \ | |
| .groupby(['team_tri_for', 'rgame']) \ | |
| .agg( | |
| win = ("win_for", "sum"), | |
| win_better = ("win_for_better", "sum"), | |
| win_expected = ("win_for_expected", "sum") | |
| ) \ | |
| .reset_index() | |
| for iter_lag in np.arange(1,3): | |
| pivot_teamcumwin[f'win_lag{iter_lag}'] = pivot_teamcumwin \ | |
| .groupby(['team_tri_for']).win.shift(iter_lag) | |
| pivot_teamcumwin[f'win_better_lag{iter_lag}'] = pivot_teamcumwin \ | |
| .groupby(['team_tri_for']).win_better.shift(iter_lag) | |
| pivot_teamcumwin[f'win_expected_lag{iter_lag}'] = pivot_teamcumwin \ | |
| .groupby(['team_tri_for']).win_expected.shift(iter_lag) | |
| # Identify all win streak | |
| pivot_teamcumwin['idx_WinStreak'] = 0 | |
| pivot_teamcumwin.loc[(np.sum(pivot_teamcumwin[['win','win_lag1', 'win_lag2']], axis = 1) == 3), 'idx_WinStreak'] = 1 | |
| # Identify win streak with games all expected to win | |
| pivot_teamcumwin['idx_WinStreak_expected'] = 0 | |
| pivot_teamcumwin.loc[\ | |
| (np.sum(pivot_teamcumwin[['win_expected','win_expected_lag1', 'win_expected_lag2']], axis = 1) >= 2) \ | |
| & pivot_teamcumwin['idx_WinStreak'] == 1 \ | |
| , 'idx_WinStreak_expected'] = 1 | |
| # Identify win streak against good team: 75%tile and above RPI | |
| pivot_teamcumwin['idx_HotStreak'] = 0 | |
| pivot_teamcumwin.loc[(pivot_teamcumwin.idx_WinStreak == 1) & \ | |
| (np.sum(pivot_teamcumwin[['win_better', 'win_better_lag1', 'win_better_lag2']], axis = 1) >= 1), \ | |
| 'idx_HotStreak'] = 1 | |
| df_streak = pivot_teamcumwin[['team_tri_for', | |
| 'idx_WinStreak', | |
| 'idx_WinStreak_expected', | |
| 'idx_HotStreak']] \ | |
| .groupby('team_tri_for').sum() | |
| df_streak['ratio'] = df_streak.idx_HotStreak / df_streak.idx_WinStreak | |
| df_streak['ratio_viz'] = np.int0(df_streak['ratio']*100) | |
| df_streak['ratio_viz'] = [str(iter) + '%' for iter in df_streak['ratio_viz']] | |
| # Sort value for future ease of use | |
| # Finally join with data | |
| dfteams = dfteams.join(df_streak) | |
| # =========================================================================== | |
| # Some plotting | |
| exec(open(str_dir_sourceCode + "/evaluation_winStreak_plot.py").read()) | |
| # ........................................................................... | |
| # output data | |
| # (a) game-level stats | |
| df_box_exnt['yr_season'] = iter_yr | |
| df_box_exnt.to_csv(str_dirc + f"/processed/{iter_yr}_02_box.csv") | |
| # (b) team-level stats for each season | |
| dfteams['yr_season'] = iter_yr | |
| dfteams.to_csv(str_dirc + f"/processed/{iter_yr}_02_team.csv") | |
| # (c) team-level head-to-head statistics | |
| dff_h2h_com_win['yr_season'] = iter_yr |