wsba-hockey 0.1.2__tar.gz → 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. {wsba_hockey-0.1.2/src/wsba_hockey.egg-info → wsba_hockey-1.0.0}/PKG-INFO +42 -11
  2. {wsba_hockey-0.1.2 → wsba_hockey-1.0.0}/README.md +41 -10
  3. {wsba_hockey-0.1.2 → wsba_hockey-1.0.0}/pyproject.toml +1 -1
  4. wsba_hockey-1.0.0/src/wsba_hockey/__init__.py +1 -0
  5. wsba_hockey-1.0.0/src/wsba_hockey/stats/calculate_viz/shot_impact.py +2 -0
  6. wsba_hockey-1.0.0/src/wsba_hockey/tools/__init__.py +0 -0
  7. wsba_hockey-1.0.0/src/wsba_hockey/tools/agg.py +185 -0
  8. wsba_hockey-1.0.0/src/wsba_hockey/tools/archive/old_scraping.py +1104 -0
  9. wsba_hockey-1.0.0/src/wsba_hockey/tools/plotting.py +113 -0
  10. wsba_hockey-1.0.0/src/wsba_hockey/tools/scraping.py +1106 -0
  11. wsba_hockey-1.0.0/src/wsba_hockey/tools/utils/__init__.py +1 -0
  12. wsba_hockey-1.0.0/src/wsba_hockey/tools/utils/config.py +14 -0
  13. wsba_hockey-1.0.0/src/wsba_hockey/tools/utils/save_pages.py +133 -0
  14. wsba_hockey-1.0.0/src/wsba_hockey/tools/utils/shared.py +450 -0
  15. wsba_hockey-1.0.0/src/wsba_hockey/tools/xg_model.py +374 -0
  16. wsba_hockey-1.0.0/src/wsba_hockey/wsba_main.py +884 -0
  17. {wsba_hockey-0.1.2 → wsba_hockey-1.0.0/src/wsba_hockey.egg-info}/PKG-INFO +42 -11
  18. wsba_hockey-1.0.0/src/wsba_hockey.egg-info/SOURCES.txt +20 -0
  19. wsba_hockey-0.1.2/src/wsba_hockey/__init__.py +0 -1
  20. wsba_hockey-0.1.2/src/wsba_hockey/tools/scraping.py +0 -639
  21. wsba_hockey-0.1.2/src/wsba_hockey/tools/xg_model.py +0 -146
  22. wsba_hockey-0.1.2/src/wsba_hockey/wsba_main.py +0 -317
  23. wsba_hockey-0.1.2/src/wsba_hockey.egg-info/SOURCES.txt +0 -11
  24. {wsba_hockey-0.1.2 → wsba_hockey-1.0.0}/LICENSE +0 -0
  25. {wsba_hockey-0.1.2 → wsba_hockey-1.0.0}/setup.cfg +0 -0
  26. {wsba_hockey-0.1.2 → wsba_hockey-1.0.0}/src/wsba_hockey.egg-info/dependency_links.txt +0 -0
  27. {wsba_hockey-0.1.2 → wsba_hockey-1.0.0}/src/wsba_hockey.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wsba_hockey
3
- Version: 0.1.2
3
+ Version: 1.0.0
4
4
  Summary: WeakSide Breakout's complete Python package of access to hockey data, primairly including the scraping of National Hockey League schedule, play-by-play, and shifts information.
5
5
  Author-email: Owen Singh <owenbksingh@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/owensingh38/wsba_hockey/
@@ -44,36 +44,67 @@ wsba.nhl_scrape_season('20242025',split_shifts=False,remove=['game-end'],local=T
44
44
 
45
45
  ```python
46
46
  wsba.nhl_scrape_schedule('20242025')
47
- wsba.nhl_scrape_seasons_info(seasons=['20212022','20222023','20232024','20242025])
47
+ wsba.nhl_scrape_seasons_info(seasons=['20212022','20222023','20232024','20242025'])
48
48
  wsba.nhl_scrape_standings(arg = '2024-03-20')
49
49
  ```
50
50
 
51
51
  ### NHL Rosters and Player Information
52
52
 
53
53
  ```python
54
- wsba.nhl_scrape_player_info(wsba.nhl_scrape_roster('20242025'))
54
+ wsba.nhl_scrape_roster('20242025')
55
+ wsba.nhl_scrape_team_info()
55
56
  ```
56
57
 
58
+ ### NHL Draft Rankings and Prospects
59
+
60
+ ```python
61
+ wsba.nhl_scrape_draft_rankings()
62
+ wsba.nhl_scrape_prospects('BOS')
63
+ ```
64
+
65
+
57
66
  ## DATA ANALYTICS
58
- ### Expected Goals (WeakSide Breakout and MoneyPuck models)*
59
- ### Goal Impacts and Shot Analysis*
60
- ### Stat Aggregation*
61
- ### Shot Plotting (Plots, Heatmaps, etc.)*
67
+ ### Expected Goals (WeakSide Breakout and MoneyPuck models)
68
+ ### Goal Impacts and Shot Analysis
69
+ ### Stat Aggregation
70
+ ```python
71
+ pbp = wsba.nhl_scrape_season('20232024',remove=[], local = True)
72
+ wsba.nhl_calculate_stats(pbp,'skater',[2],['5v5','4v4','3v3'],xg='moneypuck',shot_impact = True)
73
+ ```
74
+ ### Shot Plotting (Plots, Heatmaps, etc.)
75
+ ```python
76
+ skater_dict = {
77
+ 'Patrice Bergeron':['20212022','BOS']
78
+ }
79
+ pbp = wsba.nhl_scrape_season('20212022',remove=[], local = True)
80
+
81
+ wsba.nhl_plot_skater_shots(pbp,skater_dict,['5v5'],legend=True)
82
+ wsba.nhl_plot_games(pbp,legend=True)
83
+ ```
62
84
 
63
85
  ## REPOSITORY
64
- ### Past Season Play-by-Play*
86
+ ### Past Season Play-by-Play
87
+ ```python
88
+ wsba.repo_load_pbp(seasons=['20212022','20222023','20232024','20242025'])
89
+ ```
65
90
  ### Team Information
66
91
  ```python
67
92
  wsba.repo_load_teaminfo()
68
- wsba.repo_load_rosters(seasons=['20212022','20222023','20232024','20242025])
93
+ wsba.repo_load_rosters(seasons=['20212022','20222023','20232024','20242025'])
69
94
  ```
70
95
  ### Schedule
71
96
  ```python
72
- wsba.repo_load_schedule(seasons=['20212022','20222023','20232024','20242025])
97
+ wsba.repo_load_schedule(seasons=['20212022','20222023','20232024','20242025'])
73
98
  ```
74
99
 
75
100
  ## ACKNOWLEDGEMENTS AND CREDITS
76
101
  ### Huge thanks to the following:
77
- Harry Shomer - Creator of the hockey_scraper package, which contains select utils functions utilized in this package and otherwise inspires the creation of this package.
102
+ Harry Shomer - Creator of the hockey_scraper package, which contains select utils functions within this package and otherwise inspires the creation of this package.
78
103
 
79
104
  Dan Morse - Creator of the hockeyR package; another important inspiration and model for developing an NHL scraper.
105
+
106
+ Patrick Bacon - Creator of TopDownHockey package
107
+
108
+ MoneyPuck - Source of available xG data in the package
109
+
110
+ Anyone in the NHL Public Analytics community who has stuck around and supported WeakSide Breakout Analysis hockey.
@@ -29,36 +29,67 @@ wsba.nhl_scrape_season('20242025',split_shifts=False,remove=['game-end'],local=T
29
29
 
30
30
  ```python
31
31
  wsba.nhl_scrape_schedule('20242025')
32
- wsba.nhl_scrape_seasons_info(seasons=['20212022','20222023','20232024','20242025])
32
+ wsba.nhl_scrape_seasons_info(seasons=['20212022','20222023','20232024','20242025'])
33
33
  wsba.nhl_scrape_standings(arg = '2024-03-20')
34
34
  ```
35
35
 
36
36
  ### NHL Rosters and Player Information
37
37
 
38
38
  ```python
39
- wsba.nhl_scrape_player_info(wsba.nhl_scrape_roster('20242025'))
39
+ wsba.nhl_scrape_roster('20242025')
40
+ wsba.nhl_scrape_team_info()
40
41
  ```
41
42
 
43
+ ### NHL Draft Rankings and Prospects
44
+
45
+ ```python
46
+ wsba.nhl_scrape_draft_rankings()
47
+ wsba.nhl_scrape_prospects('BOS')
48
+ ```
49
+
50
+
42
51
  ## DATA ANALYTICS
43
- ### Expected Goals (WeakSide Breakout and MoneyPuck models)*
44
- ### Goal Impacts and Shot Analysis*
45
- ### Stat Aggregation*
46
- ### Shot Plotting (Plots, Heatmaps, etc.)*
52
+ ### Expected Goals (WeakSide Breakout and MoneyPuck models)
53
+ ### Goal Impacts and Shot Analysis
54
+ ### Stat Aggregation
55
+ ```python
56
+ pbp = wsba.nhl_scrape_season('20232024',remove=[], local = True)
57
+ wsba.nhl_calculate_stats(pbp,'skater',[2],['5v5','4v4','3v3'],xg='moneypuck',shot_impact = True)
58
+ ```
59
+ ### Shot Plotting (Plots, Heatmaps, etc.)
60
+ ```python
61
+ skater_dict = {
62
+ 'Patrice Bergeron':['20212022','BOS']
63
+ }
64
+ pbp = wsba.nhl_scrape_season('20212022',remove=[], local = True)
65
+
66
+ wsba.nhl_plot_skater_shots(pbp,skater_dict,['5v5'],legend=True)
67
+ wsba.nhl_plot_games(pbp,legend=True)
68
+ ```
47
69
 
48
70
  ## REPOSITORY
49
- ### Past Season Play-by-Play*
71
+ ### Past Season Play-by-Play
72
+ ```python
73
+ wsba.repo_load_pbp(seasons=['20212022','20222023','20232024','20242025'])
74
+ ```
50
75
  ### Team Information
51
76
  ```python
52
77
  wsba.repo_load_teaminfo()
53
- wsba.repo_load_rosters(seasons=['20212022','20222023','20232024','20242025])
78
+ wsba.repo_load_rosters(seasons=['20212022','20222023','20232024','20242025'])
54
79
  ```
55
80
  ### Schedule
56
81
  ```python
57
- wsba.repo_load_schedule(seasons=['20212022','20222023','20232024','20242025])
82
+ wsba.repo_load_schedule(seasons=['20212022','20222023','20232024','20242025'])
58
83
  ```
59
84
 
60
85
  ## ACKNOWLEDGEMENTS AND CREDITS
61
86
  ### Huge thanks to the following:
62
- Harry Shomer - Creator of the hockey_scraper package, which contains select utils functions utilized in this package and otherwise inspires the creation of this package.
87
+ Harry Shomer - Creator of the hockey_scraper package, which contains select utils functions within this package and otherwise inspires the creation of this package.
63
88
 
64
89
  Dan Morse - Creator of the hockeyR package; another important inspiration and model for developing an NHL scraper.
90
+
91
+ Patrick Bacon - Creator of TopDownHockey package
92
+
93
+ MoneyPuck - Source of available xG data in the package
94
+
95
+ Anyone in the NHL Public Analytics community who has stuck around and supported WeakSide Breakout Analysis hockey.
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "wsba_hockey"
3
- version = "0.1.2"
3
+ version = "1.0.0"
4
4
  authors = [
5
5
  { name="Owen Singh", email="owenbksingh@gmail.com" },
6
6
  ]
@@ -0,0 +1 @@
1
+ from .wsba_main import nhl_scrape_game,nhl_scrape_schedule,nhl_scrape_season,nhl_scrape_seasons_info,nhl_scrape_standings,nhl_scrape_roster,nhl_scrape_draft_rankings,nhl_scrape_prospects,nhl_calculate_stats,nhl_shooting_impacts,nhl_plot_skaters_shots,nhl_plot_games,repo_load_rosters,repo_load_schedule,repo_load_teaminfo,repo_load_pbp,repo_load_seasons
@@ -0,0 +1,2 @@
1
+ import pandas as pd
2
+ import numpy as np
File without changes
@@ -0,0 +1,185 @@
1
+ import pandas as pd
2
+ import numpy as np
3
+ from .xg_model import *
4
+
5
+ ## AGGREGATE FUNCTIONS ##
6
+
7
+ ## GLOBAL VARIABLES ##
8
+ shot_types = ['wrist','deflected','tip-in','slap','backhand','snap','wrap-around','poke','bat','cradle','between-legs']
9
+ fenwick_events = ['missed-shot','shot-on-goal','goal']
10
+
11
+ def calc_indv(pbp):
12
+ indv = (
13
+ pbp.loc[pbp['event_type'].isin(["goal", "shot-on-goal", "missed-shot"])].groupby(['event_player_1_id','event_team_abbr','season']).agg(
14
+ Gi=('event_type', lambda x: (x == "goal").sum()),
15
+ Fi=('event_type', lambda x: (x != "blocked-shot").sum()),
16
+ xGi=('xG', 'sum'),
17
+ Rush=('rush_mod',lambda x: (x > 0).sum())
18
+ ).reset_index().rename(columns={'event_player_1_id': 'ID', 'event_team_abbr': 'Team', 'season': 'Season'})
19
+ )
20
+
21
+ rush_xg = (
22
+ pbp.loc[(pbp['event_type'].isin(["goal", "shot-on-goal", "missed-shot"]))&(pbp['rush_mod']>0)].groupby(['event_player_1_id','event_team_abbr','season']).agg(
23
+ Rush_G=('event_type', lambda x:(x == 'goal').sum()),
24
+ Rush_xG=('xG','sum')
25
+ ).reset_index().rename(columns={'event_player_1_id': 'ID', 'event_team_abbr': 'Team', 'season': 'Season', 'Rush_G':'Rush G','Rush_xG':'Rush xG'})
26
+ )
27
+
28
+ a1 = (
29
+ pbp.loc[pbp['event_type'].isin(["goal"])].groupby(['event_player_2_id', 'event_team_abbr','season']).agg(
30
+ A1=('event_type','count')
31
+ ).reset_index().rename(columns={'event_player_2_id': 'ID', 'event_team_abbr': 'Team', 'season': 'Season'})
32
+ )
33
+
34
+ a2 = (
35
+ pbp.loc[pbp['event_type'].isin(["goal"])].groupby(['event_player_3_id', 'event_team_abbr', 'season']).agg(
36
+ A2=('event_type','count')
37
+ ).reset_index().rename(columns={'event_player_3_id': 'ID', 'event_team_abbr': 'Team', 'season': 'Season'})
38
+ )
39
+ indv = pd.merge(indv,rush_xg,how='outer',on=['ID','Team','Season'])
40
+ indv = pd.merge(indv,a1,how='outer',on=['ID','Team','Season'])
41
+ indv = pd.merge(indv,a2,how='outer',on=['ID','Team','Season'])
42
+
43
+ #Shot Types
44
+ for type in shot_types:
45
+ shot = (
46
+ pbp.loc[(pbp['event_type'].isin(["goal", "shot-on-goal", "missed-shot"])&(pbp['shot_type']==type))].groupby(['event_player_1_id', 'event_team_abbr', 'season']).agg(
47
+ Gi=('event_type', lambda x: (x == "goal").sum()),
48
+ Fi=('event_type', lambda x: (x != "blocked-shot").sum()),
49
+ xGi=('xG', 'sum'),
50
+ ).reset_index().rename(columns={'event_player_1_id': 'ID', 'event_team_abbr': 'Team', 'season': 'Season'})
51
+ )
52
+
53
+ shot = shot.rename(columns={
54
+ 'Gi':f'{type.capitalize()}Gi',
55
+ 'Fi':f'{type.capitalize()}Fi',
56
+ 'xGi':f'{type.capitalize()}xGi',
57
+ })
58
+ indv = pd.merge(indv,shot,how='outer',on=['ID','Team','Season'])
59
+
60
+ indv[['Gi','A1','A2']] = indv[['Gi','A1','A2']].fillna(0)
61
+
62
+ indv['P1'] = indv['Gi']+indv['A1']
63
+ indv['P'] = indv['P1']+indv['A2']
64
+ indv['xGi/Fi'] = indv['xGi']/indv['Fi']
65
+ indv['Gi/xGi'] = indv['Gi']/indv['xGi']
66
+ indv['Fshi%'] = indv['Gi']/indv['Fi']
67
+
68
+ return indv
69
+
70
+ def calc_onice(pbp):
71
+ # Convert player on-ice columns to vectors
72
+ pbp['home_on_ice'] = pbp['home_on_1_id'].astype(str) + ";" + pbp['home_on_2_id'].astype(str) + ";" + pbp['home_on_3_id'].astype(str) + ";" + pbp['home_on_4_id'].astype(str) + ";" + pbp['home_on_5_id'].astype(str) + ";" + pbp['home_on_6_id'].astype(str)
73
+ pbp['away_on_ice'] = pbp['away_on_1_id'].astype(str) + ";" + pbp['away_on_2_id'].astype(str) + ";" + pbp['away_on_3_id'].astype(str) + ";" + pbp['away_on_4_id'].astype(str) + ";" + pbp['away_on_5_id'].astype(str) + ";" + pbp['away_on_6_id'].astype(str)
74
+
75
+ # Remove NA players
76
+ pbp['home_on_ice'] = pbp['home_on_ice'].str.replace(';nan', '', regex=True)
77
+ pbp['away_on_ice'] = pbp['away_on_ice'].str.replace(';nan', '', regex=True)
78
+
79
+ def process_team_stats(df, on_ice_col, team_col, opp_col):
80
+ df = df[['season','game_id', 'event_num', team_col, opp_col, 'event_type', 'event_team_abbr', on_ice_col,'event_length','xG']].copy()
81
+ df[on_ice_col] = df[on_ice_col].str.split(';')
82
+ df = df.explode(on_ice_col)
83
+ df = df.rename(columns={on_ice_col: 'ID', 'season': 'Season'})
84
+ df['xGF'] = np.where(df['event_team_abbr'] == df[team_col], df['xG'], 0)
85
+ df['xGA'] = np.where(df['event_team_abbr'] == df[opp_col], df['xG'], 0)
86
+ df['GF'] = np.where((df['event_type'] == "goal") & (df['event_team_abbr'] == df[team_col]), 1, 0)
87
+ df['GA'] = np.where((df['event_type'] == "goal") & (df['event_team_abbr'] == df[opp_col]), 1, 0)
88
+ df['FF'] = np.where((df['event_type'].isin(fenwick_events)) & (df['event_team_abbr'] == df[team_col]), 1, 0)
89
+ df['FA'] = np.where((df['event_type'].isin(fenwick_events)) & (df['event_team_abbr'] == df[opp_col]), 1, 0)
90
+
91
+ stats = df.groupby(['ID',team_col,'Season']).agg(
92
+ GP=('game_id','nunique'),
93
+ TOI=('event_length','sum'),
94
+ FF=('FF', 'sum'),
95
+ FA=('FA', 'sum'),
96
+ GF=('GF', 'sum'),
97
+ GA=('GA', 'sum'),
98
+ xGF=('xGF', 'sum'),
99
+ xGA=('xGA', 'sum')
100
+ ).reset_index()
101
+
102
+ return stats.rename(columns={team_col:"Team"})
103
+
104
+ home_stats = process_team_stats(pbp, 'home_on_ice', 'home_team_abbr', 'away_team_abbr')
105
+ away_stats = process_team_stats(pbp, 'away_on_ice', 'away_team_abbr', 'home_team_abbr')
106
+
107
+ onice_stats = pd.concat([home_stats,away_stats]).groupby(['ID','Team','Season']).agg(
108
+ GP=('GP','sum'),
109
+ TOI=('TOI','sum'),
110
+ FF=('FF', 'sum'),
111
+ FA=('FA', 'sum'),
112
+ GF=('GF', 'sum'),
113
+ GA=('GA', 'sum'),
114
+ xGF=('xGF', 'sum'),
115
+ xGA=('xGA', 'sum')
116
+ ).reset_index()
117
+
118
+ onice_stats['xGF/FF'] = onice_stats['xGF']/onice_stats['FF']
119
+ onice_stats['GF/xGF'] = onice_stats['GF']/onice_stats['xGF']
120
+ onice_stats['FshF%'] = onice_stats['GF']/onice_stats['FF']
121
+ onice_stats['xGA/FA'] = onice_stats['xGA']/onice_stats['FA']
122
+ onice_stats['GA/xGA'] = onice_stats['GA']/onice_stats['xGA']
123
+ onice_stats['FshA%'] = onice_stats['GA']/onice_stats['FA']
124
+
125
+ return onice_stats
126
+
127
+ def calc_team(pbp):
128
+ teams = []
129
+ for team in [('away','home'),('home','away')]:
130
+ pbp['xGF'] = np.where(pbp['event_team_abbr'] == pbp[f'{team[0]}_team_abbr'], pbp['xG'], 0)
131
+ pbp['xGA'] = np.where(pbp['event_team_abbr'] == pbp[f'{team[1]}_team_abbr'], pbp['xG'], 0)
132
+ pbp['GF'] = np.where((pbp['event_type'] == "goal") & (pbp['event_team_abbr'] == pbp[f'{team[0]}_team_abbr']), 1, 0)
133
+ pbp['GA'] = np.where((pbp['event_type'] == "goal") & (pbp['event_team_abbr'] == pbp[f'{team[1]}_team_abbr']), 1, 0)
134
+ pbp['FF'] = np.where((pbp['event_type'].isin(fenwick_events)) & (pbp['event_team_abbr'] == pbp[f'{team[0]}_team_abbr']), 1, 0)
135
+ pbp['FA'] = np.where((pbp['event_type'].isin(fenwick_events)) & (pbp['event_team_abbr'] == pbp[f'{team[1]}_team_abbr']), 1, 0)
136
+ pbp['RushF'] = np.where((pbp['event_team_abbr'] == pbp[f'{team[0]}_team_abbr'])&(pbp['rush_mod']>0), 1, 0)
137
+ pbp['RushA'] = np.where((pbp['event_team_abbr'] == pbp[f'{team[1]}_team_abbr'])&(pbp['rush_mod']>0), 1, 0)
138
+ pbp['RushFxG'] = np.where((pbp['event_team_abbr'] == pbp[f'{team[0]}_team_abbr'])&(pbp['rush_mod']>0), pbp['xG'], 0)
139
+ pbp['RushAxG'] = np.where((pbp['event_team_abbr'] == pbp[f'{team[1]}_team_abbr'])&(pbp['rush_mod']>0), pbp['xG'], 0)
140
+ pbp['RushFG'] = np.where((pbp['event_type'] == "goal") & (pbp['event_team_abbr'] == pbp[f'{team[0]}_team_abbr'])&(pbp['rush_mod']>0), 1, 0)
141
+ pbp['RushAG'] = np.where((pbp['event_type'] == "goal") & (pbp['event_team_abbr'] == pbp[f'{team[1]}_team_abbr'])&(pbp['rush_mod']>0), 1, 0)
142
+
143
+ stats = pbp.groupby([f'{team[0]}_team_abbr','season']).agg(
144
+ GP=('game_id','nunique'),
145
+ TOI=('event_length','sum'),
146
+ FF=('FF', 'sum'),
147
+ FA=('FA', 'sum'),
148
+ GF=('GF', 'sum'),
149
+ GA=('GA', 'sum'),
150
+ xGF=('xGF', 'sum'),
151
+ xGA=('xGA', 'sum'),
152
+ RushF=('RushF','sum'),
153
+ RushA=('RushA','sum'),
154
+ RushFxG=('RushFxG','sum'),
155
+ RushAxG=('RushAxG','sum'),
156
+ RushFG=('RushFG','sum'),
157
+ RushAG=('RushAG','sum'),
158
+ ).reset_index().rename(columns={f'{team[0]}_team_abbr':"Team",'season':"Season"})
159
+ teams.append(stats)
160
+
161
+ onice_stats = pd.concat(teams).groupby(['Team','Season']).agg(
162
+ GP=('GP','sum'),
163
+ TOI=('TOI','sum'),
164
+ FF=('FF', 'sum'),
165
+ FA=('FA', 'sum'),
166
+ GF=('GF', 'sum'),
167
+ GA=('GA', 'sum'),
168
+ xGF=('xGF', 'sum'),
169
+ xGA=('xGA', 'sum'),
170
+ RushF=('RushF','sum'),
171
+ RushA=('RushA','sum'),
172
+ RushFxG=('RushFxG','sum'),
173
+ RushAxG=('RushAxG','sum'),
174
+ RushFG=('RushFG','sum'),
175
+ RushAG=('RushAG','sum'),
176
+ ).reset_index()
177
+
178
+ onice_stats['xGF/FF'] = onice_stats['xGF']/onice_stats['FF']
179
+ onice_stats['GF/xGF'] = onice_stats['GF']/onice_stats['xGF']
180
+ onice_stats['FshF%'] = onice_stats['GF']/onice_stats['FF']
181
+ onice_stats['xGA/FA'] = onice_stats['xGA']/onice_stats['FA']
182
+ onice_stats['GA/xGA'] = onice_stats['GA']/onice_stats['xGA']
183
+ onice_stats['FshA%'] = onice_stats['GA']/onice_stats['FA']
184
+
185
+ return onice_stats