hockey-blast-common-lib 0.1.38__py3-none-any.whl → 0.1.40__py3-none-any.whl
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.
- hockey_blast_common_lib/aggregate_goalie_stats.py +25 -22
- hockey_blast_common_lib/aggregate_human_stats.py +67 -62
- hockey_blast_common_lib/aggregate_referee_stats.py +27 -20
- hockey_blast_common_lib/aggregate_skater_stats.py +39 -30
- hockey_blast_common_lib/hockey_blast_sample_backup.sql.gz +0 -0
- hockey_blast_common_lib/stats_models.py +2 -0
- hockey_blast_common_lib/stats_utils.py +6 -0
- {hockey_blast_common_lib-0.1.38.dist-info → hockey_blast_common_lib-0.1.40.dist-info}/METADATA +1 -1
- {hockey_blast_common_lib-0.1.38.dist-info → hockey_blast_common_lib-0.1.40.dist-info}/RECORD +11 -11
- {hockey_blast_common_lib-0.1.38.dist-info → hockey_blast_common_lib-0.1.40.dist-info}/WHEEL +0 -0
- {hockey_blast_common_lib-0.1.38.dist-info → hockey_blast_common_lib-0.1.40.dist-info}/top_level.txt +0 -0
@@ -15,22 +15,20 @@ from hockey_blast_common_lib.utils import get_org_id_from_alias, get_human_ids_b
|
|
15
15
|
from hockey_blast_common_lib.utils import assign_ranks
|
16
16
|
from sqlalchemy import func, case, and_
|
17
17
|
from collections import defaultdict
|
18
|
+
from hockey_blast_common_lib.stats_utils import ALL_ORGS_ID
|
18
19
|
|
19
20
|
def aggregate_goalie_stats(session, aggregation_type, aggregation_id, names_to_filter_out, debug_human_id=None, aggregation_window=None):
|
20
21
|
human_ids_to_filter = get_human_ids_by_names(session, names_to_filter_out)
|
21
22
|
|
22
23
|
# Get the name of the aggregation, for debug purposes
|
23
24
|
if aggregation_type == 'org':
|
24
|
-
|
25
|
+
if aggregation_id == ALL_ORGS_ID:
|
26
|
+
aggregation_name = "All Orgs"
|
27
|
+
filter_condition = sqlalchemy.true() # No filter for organization
|
28
|
+
else:
|
29
|
+
aggregation_name = session.query(Organization).filter(Organization.id == aggregation_id).first().organization_name
|
30
|
+
filter_condition = Game.org_id == aggregation_id
|
25
31
|
print(f"Aggregating goalie stats for {aggregation_name} with window {aggregation_window}...")
|
26
|
-
elif aggregation_type == 'division':
|
27
|
-
aggregation_name = session.query(Division).filter(Division.id == aggregation_id).first().level
|
28
|
-
elif aggregation_type == 'level':
|
29
|
-
aggregation_name = session.query(Level).filter(Level.id == aggregation_id).first().level_name
|
30
|
-
else:
|
31
|
-
aggregation_name = "Unknown"
|
32
|
-
|
33
|
-
if aggregation_type == 'org':
|
34
32
|
if aggregation_window == 'Daily':
|
35
33
|
StatsModel = OrgStatsDailyGoalie
|
36
34
|
elif aggregation_window == 'Weekly':
|
@@ -38,7 +36,6 @@ def aggregate_goalie_stats(session, aggregation_type, aggregation_id, names_to_f
|
|
38
36
|
else:
|
39
37
|
StatsModel = OrgStatsGoalie
|
40
38
|
min_games = MIN_GAMES_FOR_ORG_STATS
|
41
|
-
filter_condition = Game.org_id == aggregation_id
|
42
39
|
elif aggregation_type == 'division':
|
43
40
|
if aggregation_window == 'Daily':
|
44
41
|
StatsModel = DivisionStatsDailyGoalie
|
@@ -91,18 +88,24 @@ def aggregate_goalie_stats(session, aggregation_type, aggregation_id, names_to_f
|
|
91
88
|
if stat.human_id in human_ids_to_filter:
|
92
89
|
continue
|
93
90
|
key = (aggregation_id, stat.human_id)
|
94
|
-
if
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
91
|
+
if key not in stats_dict:
|
92
|
+
stats_dict[key] = {
|
93
|
+
'games_played': 0,
|
94
|
+
'goals_allowed': 0,
|
95
|
+
'shots_faced': 0,
|
96
|
+
'goals_allowed_per_game': 0.0,
|
97
|
+
'save_percentage': 0.0,
|
98
|
+
'game_ids': [],
|
99
|
+
'first_game_id': None,
|
100
|
+
'last_game_id': None
|
101
|
+
}
|
102
|
+
stats_dict[key]['games_played'] += stat.games_played
|
103
|
+
stats_dict[key]['goals_allowed'] += stat.goals_allowed if stat.goals_allowed is not None else 0
|
104
|
+
stats_dict[key]['shots_faced'] += stat.shots_faced if stat.shots_faced is not None else 0
|
105
|
+
stats_dict[key]['game_ids'].extend(stat.game_ids)
|
106
|
+
|
107
|
+
# Filter out entries with games_played less than min_games
|
108
|
+
stats_dict = {key: value for key, value in stats_dict.items() if value['games_played'] >= min_games}
|
106
109
|
|
107
110
|
# Calculate per game stats
|
108
111
|
for key, stat in stats_dict.items():
|
@@ -14,13 +14,19 @@ from hockey_blast_common_lib.options import parse_args, MIN_GAMES_FOR_ORG_STATS,
|
|
14
14
|
from hockey_blast_common_lib.utils import get_fake_human_for_stats, get_org_id_from_alias, get_human_ids_by_names, get_division_ids_for_last_season_in_all_leagues, get_all_division_ids_for_org
|
15
15
|
from hockey_blast_common_lib.utils import assign_ranks
|
16
16
|
from hockey_blast_common_lib.utils import get_start_datetime
|
17
|
+
from hockey_blast_common_lib.stats_utils import ALL_ORGS_ID
|
17
18
|
|
18
19
|
def aggregate_human_stats(session, aggregation_type, aggregation_id, names_to_filter_out, human_id_filter=None, aggregation_window=None):
|
19
20
|
human_ids_to_filter = get_human_ids_by_names(session, names_to_filter_out)
|
20
21
|
|
21
22
|
if aggregation_type == 'org':
|
22
|
-
|
23
|
-
|
23
|
+
if aggregation_id == ALL_ORGS_ID:
|
24
|
+
aggregation_name = "All Orgs"
|
25
|
+
filter_condition = sqlalchemy.true() # No filter for organization
|
26
|
+
else:
|
27
|
+
aggregation_name = session.query(Organization).filter(Organization.id == aggregation_id).first().organization_name
|
28
|
+
filter_condition = Game.org_id == aggregation_id
|
29
|
+
print(f"Aggregating human stats for {aggregation_name} with window {aggregation_window}...")
|
24
30
|
if aggregation_window == 'Daily':
|
25
31
|
StatsModel = OrgStatsDailyHuman
|
26
32
|
elif aggregation_window == 'Weekly':
|
@@ -28,7 +34,6 @@ def aggregate_human_stats(session, aggregation_type, aggregation_id, names_to_fi
|
|
28
34
|
else:
|
29
35
|
StatsModel = OrgStatsHuman
|
30
36
|
min_games = MIN_GAMES_FOR_ORG_STATS
|
31
|
-
filter_condition = Game.org_id == aggregation_id
|
32
37
|
elif aggregation_type == 'division':
|
33
38
|
if aggregation_window == 'Daily':
|
34
39
|
StatsModel = DivisionStatsDailyHuman
|
@@ -108,25 +113,29 @@ def aggregate_human_stats(session, aggregation_type, aggregation_id, names_to_fi
|
|
108
113
|
if stat.human_id in human_ids_to_filter:
|
109
114
|
continue
|
110
115
|
key = (aggregation_id, stat.human_id)
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
116
|
+
if key not in stats_dict:
|
117
|
+
stats_dict[key] = {
|
118
|
+
'games_total': 0,
|
119
|
+
'games_skater': 0,
|
120
|
+
'games_goalie': 0,
|
121
|
+
'games_referee': 0,
|
122
|
+
'games_scorekeeper': 0,
|
123
|
+
'skater_game_ids': [],
|
124
|
+
'goalie_game_ids': [],
|
125
|
+
'referee_game_ids': [],
|
126
|
+
'scorekeeper_game_ids': [],
|
127
|
+
'first_game_id_skater': None,
|
128
|
+
'last_game_id_skater': None,
|
129
|
+
'first_game_id_goalie': None,
|
130
|
+
'last_game_id_goalie': None,
|
131
|
+
'first_game_id_referee': None,
|
132
|
+
'last_game_id_referee': None,
|
133
|
+
'first_game_id_scorekeeper': None,
|
134
|
+
'last_game_id_scorekeeper': None
|
135
|
+
}
|
136
|
+
stats_dict[key]['games_total'] += stat.games_skater
|
137
|
+
stats_dict[key]['games_skater'] += stat.games_skater
|
138
|
+
stats_dict[key]['skater_game_ids'].extend(stat.skater_game_ids)
|
130
139
|
|
131
140
|
for stat in goalie_stats:
|
132
141
|
if stat.human_id in human_ids_to_filter:
|
@@ -134,13 +143,13 @@ def aggregate_human_stats(session, aggregation_type, aggregation_id, names_to_fi
|
|
134
143
|
key = (aggregation_id, stat.human_id)
|
135
144
|
if key not in stats_dict:
|
136
145
|
stats_dict[key] = {
|
137
|
-
'games_total':
|
146
|
+
'games_total': 0,
|
138
147
|
'games_skater': 0,
|
139
|
-
'games_goalie':
|
148
|
+
'games_goalie': 0,
|
140
149
|
'games_referee': 0,
|
141
150
|
'games_scorekeeper': 0,
|
142
151
|
'skater_game_ids': [],
|
143
|
-
'goalie_game_ids':
|
152
|
+
'goalie_game_ids': [],
|
144
153
|
'referee_game_ids': [],
|
145
154
|
'scorekeeper_game_ids': [],
|
146
155
|
'first_game_id_skater': None,
|
@@ -152,10 +161,9 @@ def aggregate_human_stats(session, aggregation_type, aggregation_id, names_to_fi
|
|
152
161
|
'first_game_id_scorekeeper': None,
|
153
162
|
'last_game_id_scorekeeper': None
|
154
163
|
}
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
stats_dict[key]['goalie_game_ids'] += stat.goalie_game_ids
|
164
|
+
stats_dict[key]['games_total'] += stat.games_goalie
|
165
|
+
stats_dict[key]['games_goalie'] += stat.games_goalie
|
166
|
+
stats_dict[key]['goalie_game_ids'].extend(stat.goalie_game_ids)
|
159
167
|
|
160
168
|
for stat in referee_stats:
|
161
169
|
if stat.human_id in human_ids_to_filter:
|
@@ -163,14 +171,14 @@ def aggregate_human_stats(session, aggregation_type, aggregation_id, names_to_fi
|
|
163
171
|
key = (aggregation_id, stat.human_id)
|
164
172
|
if key not in stats_dict:
|
165
173
|
stats_dict[key] = {
|
166
|
-
'games_total':
|
174
|
+
'games_total': 0,
|
167
175
|
'games_skater': 0,
|
168
176
|
'games_goalie': 0,
|
169
|
-
'games_referee':
|
177
|
+
'games_referee': 0,
|
170
178
|
'games_scorekeeper': 0,
|
171
179
|
'skater_game_ids': [],
|
172
180
|
'goalie_game_ids': [],
|
173
|
-
'referee_game_ids':
|
181
|
+
'referee_game_ids': [],
|
174
182
|
'scorekeeper_game_ids': [],
|
175
183
|
'first_game_id_skater': None,
|
176
184
|
'last_game_id_skater': None,
|
@@ -181,10 +189,9 @@ def aggregate_human_stats(session, aggregation_type, aggregation_id, names_to_fi
|
|
181
189
|
'first_game_id_scorekeeper': None,
|
182
190
|
'last_game_id_scorekeeper': None
|
183
191
|
}
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
stats_dict[key]['referee_game_ids'] += stat.referee_game_ids
|
192
|
+
stats_dict[key]['games_total'] += stat.games_referee
|
193
|
+
stats_dict[key]['games_referee'] += stat.games_referee
|
194
|
+
stats_dict[key]['referee_game_ids'].extend(stat.referee_game_ids)
|
188
195
|
|
189
196
|
for stat in referee_stats_2:
|
190
197
|
if stat.human_id in human_ids_to_filter:
|
@@ -192,14 +199,14 @@ def aggregate_human_stats(session, aggregation_type, aggregation_id, names_to_fi
|
|
192
199
|
key = (aggregation_id, stat.human_id)
|
193
200
|
if key not in stats_dict:
|
194
201
|
stats_dict[key] = {
|
195
|
-
'games_total':
|
202
|
+
'games_total': 0,
|
196
203
|
'games_skater': 0,
|
197
204
|
'games_goalie': 0,
|
198
|
-
'games_referee':
|
205
|
+
'games_referee': 0,
|
199
206
|
'games_scorekeeper': 0,
|
200
207
|
'skater_game_ids': [],
|
201
208
|
'goalie_game_ids': [],
|
202
|
-
'referee_game_ids':
|
209
|
+
'referee_game_ids': [],
|
203
210
|
'scorekeeper_game_ids': [],
|
204
211
|
'first_game_id_skater': None,
|
205
212
|
'last_game_id_skater': None,
|
@@ -210,10 +217,9 @@ def aggregate_human_stats(session, aggregation_type, aggregation_id, names_to_fi
|
|
210
217
|
'first_game_id_scorekeeper': None,
|
211
218
|
'last_game_id_scorekeeper': None
|
212
219
|
}
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
stats_dict[key]['referee_game_ids'] += stat.referee_game_ids
|
220
|
+
stats_dict[key]['games_total'] += stat.games_referee
|
221
|
+
stats_dict[key]['games_referee'] += stat.games_referee
|
222
|
+
stats_dict[key]['referee_game_ids'].extend(stat.referee_game_ids)
|
217
223
|
|
218
224
|
for stat in scorekeeper_stats:
|
219
225
|
if stat.human_id in human_ids_to_filter:
|
@@ -221,15 +227,15 @@ def aggregate_human_stats(session, aggregation_type, aggregation_id, names_to_fi
|
|
221
227
|
key = (aggregation_id, stat.human_id)
|
222
228
|
if key not in stats_dict:
|
223
229
|
stats_dict[key] = {
|
224
|
-
'games_total':
|
230
|
+
'games_total': 0,
|
225
231
|
'games_skater': 0,
|
226
232
|
'games_goalie': 0,
|
227
233
|
'games_referee': 0,
|
228
|
-
'games_scorekeeper':
|
234
|
+
'games_scorekeeper': 0,
|
229
235
|
'skater_game_ids': [],
|
230
236
|
'goalie_game_ids': [],
|
231
237
|
'referee_game_ids': [],
|
232
|
-
'scorekeeper_game_ids':
|
238
|
+
'scorekeeper_game_ids': [],
|
233
239
|
'first_game_id_skater': None,
|
234
240
|
'last_game_id_skater': None,
|
235
241
|
'first_game_id_goalie': None,
|
@@ -239,10 +245,9 @@ def aggregate_human_stats(session, aggregation_type, aggregation_id, names_to_fi
|
|
239
245
|
'first_game_id_scorekeeper': None,
|
240
246
|
'last_game_id_scorekeeper': None
|
241
247
|
}
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
stats_dict[key]['scorekeeper_game_ids'] += stat.scorekeeper_game_ids
|
248
|
+
stats_dict[key]['games_total'] += stat.games_scorekeeper
|
249
|
+
stats_dict[key]['games_scorekeeper'] += stat.games_scorekeeper
|
250
|
+
stats_dict[key]['scorekeeper_game_ids'].extend(stat.scorekeeper_game_ids)
|
246
251
|
|
247
252
|
# Ensure all keys have valid human_id values
|
248
253
|
stats_dict = {key: value for key, value in stats_dict.items() if key[1] is not None}
|
@@ -417,7 +422,7 @@ def run_aggregate_human_stats():
|
|
417
422
|
org_ids = session.query(Organization.id).all()
|
418
423
|
org_ids = [org_id[0] for org_id in org_ids]
|
419
424
|
|
420
|
-
for org_id in org_ids:
|
425
|
+
for org_id in [-1]:#org_ids:
|
421
426
|
division_ids = get_all_division_ids_for_org(session, org_id)
|
422
427
|
print(f"Aggregating human stats for {len(division_ids)} divisions in org_id {org_id}...")
|
423
428
|
total_divisions = len(division_ids)
|
@@ -435,17 +440,17 @@ def run_aggregate_human_stats():
|
|
435
440
|
aggregate_human_stats(session, aggregation_type='org', aggregation_id=org_id, names_to_filter_out=not_human_names, human_id_filter=human_id_to_debug, aggregation_window='Daily')
|
436
441
|
|
437
442
|
# Aggregate by level
|
438
|
-
level_ids = session.query(Division.level_id).distinct().all()
|
439
|
-
level_ids = [level_id[0] for level_id in level_ids]
|
440
|
-
total_levels = len(level_ids)
|
441
|
-
processed_levels = 0
|
442
|
-
for level_id in level_ids:
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
443
|
+
# level_ids = session.query(Division.level_id).distinct().all()
|
444
|
+
# level_ids = [level_id[0] for level_id in level_ids]
|
445
|
+
# total_levels = len(level_ids)
|
446
|
+
# processed_levels = 0
|
447
|
+
# for level_id in level_ids:
|
448
|
+
# if level_id is None:
|
449
|
+
# continue
|
450
|
+
# if human_id_to_debug is None:
|
451
|
+
# print(f"\rProcessed {processed_levels}/{total_levels} levels ({(processed_levels/total_levels)*100:.2f}%)", end="")
|
452
|
+
# processed_levels += 1
|
453
|
+
# aggregate_human_stats(session, aggregation_type='level', aggregation_id=level_id, names_to_filter_out=not_human_names, human_id_filter=human_id_to_debug)
|
449
454
|
|
450
455
|
if __name__ == "__main__":
|
451
456
|
run_aggregate_human_stats()
|
@@ -14,12 +14,18 @@ from hockey_blast_common_lib.options import parse_args, MIN_GAMES_FOR_ORG_STATS,
|
|
14
14
|
from hockey_blast_common_lib.utils import get_org_id_from_alias, get_human_ids_by_names, get_division_ids_for_last_season_in_all_leagues, get_all_division_ids_for_org
|
15
15
|
from hockey_blast_common_lib.utils import assign_ranks
|
16
16
|
from hockey_blast_common_lib.utils import get_start_datetime
|
17
|
+
from hockey_blast_common_lib.stats_utils import ALL_ORGS_ID
|
17
18
|
|
18
19
|
def aggregate_referee_stats(session, aggregation_type, aggregation_id, names_to_filter_out, aggregation_window=None):
|
19
20
|
human_ids_to_filter = get_human_ids_by_names(session, names_to_filter_out)
|
20
21
|
|
21
22
|
if aggregation_type == 'org':
|
22
|
-
|
23
|
+
if aggregation_id == ALL_ORGS_ID:
|
24
|
+
aggregation_name = "All Orgs"
|
25
|
+
filter_condition = sqlalchemy.true() # No filter for organization
|
26
|
+
else:
|
27
|
+
aggregation_name = session.query(Organization).filter(Organization.id == aggregation_id).first().organization_name
|
28
|
+
filter_condition = Game.org_id == aggregation_id
|
23
29
|
print(f"Aggregating referee stats for {aggregation_name} with window {aggregation_window}...")
|
24
30
|
if aggregation_window == 'Daily':
|
25
31
|
StatsModel = OrgStatsDailyReferee
|
@@ -28,7 +34,6 @@ def aggregate_referee_stats(session, aggregation_type, aggregation_id, names_to_
|
|
28
34
|
else:
|
29
35
|
StatsModel = OrgStatsReferee
|
30
36
|
min_games = MIN_GAMES_FOR_ORG_STATS
|
31
|
-
filter_condition = Game.org_id == aggregation_id
|
32
37
|
elif aggregation_type == 'division':
|
33
38
|
if aggregation_window == 'Daily':
|
34
39
|
StatsModel = DivisionStatsDailyReferee
|
@@ -89,16 +94,19 @@ def aggregate_referee_stats(session, aggregation_type, aggregation_id, names_to_
|
|
89
94
|
if stat.human_id in human_ids_to_filter:
|
90
95
|
continue
|
91
96
|
key = (aggregation_id, stat.human_id)
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
97
|
+
if key not in stats_dict:
|
98
|
+
stats_dict[key] = {
|
99
|
+
'games_reffed': 0,
|
100
|
+
'penalties_given': 0,
|
101
|
+
'gm_given': 0,
|
102
|
+
'penalties_per_game': 0.0,
|
103
|
+
'gm_per_game': 0.0,
|
104
|
+
'game_ids': [],
|
105
|
+
'first_game_id': None,
|
106
|
+
'last_game_id': None
|
107
|
+
}
|
108
|
+
stats_dict[key]['games_reffed'] += stat.games_reffed
|
109
|
+
stats_dict[key]['game_ids'].extend(stat.game_ids)
|
102
110
|
|
103
111
|
for stat in games_reffed_stats_2:
|
104
112
|
if stat.human_id in human_ids_to_filter:
|
@@ -106,18 +114,20 @@ def aggregate_referee_stats(session, aggregation_type, aggregation_id, names_to_
|
|
106
114
|
key = (aggregation_id, stat.human_id)
|
107
115
|
if key not in stats_dict:
|
108
116
|
stats_dict[key] = {
|
109
|
-
'games_reffed':
|
117
|
+
'games_reffed': 0,
|
110
118
|
'penalties_given': 0,
|
111
119
|
'gm_given': 0,
|
112
120
|
'penalties_per_game': 0.0,
|
113
121
|
'gm_per_game': 0.0,
|
114
|
-
'game_ids':
|
122
|
+
'game_ids': [],
|
115
123
|
'first_game_id': None,
|
116
124
|
'last_game_id': None
|
117
125
|
}
|
118
|
-
|
119
|
-
|
120
|
-
|
126
|
+
stats_dict[key]['games_reffed'] += stat.games_reffed
|
127
|
+
stats_dict[key]['game_ids'].extend(stat.game_ids)
|
128
|
+
|
129
|
+
# Filter out entries with games_reffed less than min_games
|
130
|
+
stats_dict = {key: value for key, value in stats_dict.items() if value['games_reffed'] >= min_games}
|
121
131
|
|
122
132
|
for stat in penalties_given_stats:
|
123
133
|
if stat.referee_1_id and stat.referee_1_id not in human_ids_to_filter:
|
@@ -143,9 +153,6 @@ def aggregate_referee_stats(session, aggregation_type, aggregation_id, names_to_
|
|
143
153
|
# Ensure all keys have valid human_id values
|
144
154
|
stats_dict = {key: value for key, value in stats_dict.items() if key[1] is not None}
|
145
155
|
|
146
|
-
# Filter out referees with less than min_games
|
147
|
-
stats_dict = {key: value for key, value in stats_dict.items() if value['games_reffed'] >= min_games}
|
148
|
-
|
149
156
|
# Populate first_game_id and last_game_id
|
150
157
|
for key, stat in stats_dict.items():
|
151
158
|
all_game_ids = stat['game_ids']
|
@@ -15,16 +15,21 @@ from hockey_blast_common_lib.utils import get_org_id_from_alias, get_human_ids_b
|
|
15
15
|
from hockey_blast_common_lib.utils import get_start_datetime
|
16
16
|
from sqlalchemy import func, case, and_
|
17
17
|
from collections import defaultdict
|
18
|
+
from hockey_blast_common_lib.stats_utils import ALL_ORGS_ID
|
18
19
|
|
19
20
|
def aggregate_skater_stats(session, aggregation_type, aggregation_id, names_to_filter_out, debug_human_id=None, aggregation_window=None):
|
20
21
|
human_ids_to_filter = get_human_ids_by_names(session, names_to_filter_out)
|
21
22
|
|
22
23
|
# Get the name of the aggregation, for debug purposes
|
23
24
|
if aggregation_type == 'org':
|
24
|
-
|
25
|
+
if aggregation_id == ALL_ORGS_ID:
|
26
|
+
aggregation_name = "All Orgs"
|
27
|
+
filter_condition = sqlalchemy.true() # No filter for organization
|
28
|
+
else:
|
29
|
+
aggregation_name = session.query(Organization).filter(Organization.id == aggregation_id).first().organization_name
|
30
|
+
filter_condition = Game.org_id == aggregation_id
|
25
31
|
print(f"Aggregating skater stats for {aggregation_name} with window {aggregation_window}...")
|
26
32
|
|
27
|
-
aggregation_name = session.query(Organization).filter(Organization.id == aggregation_id).first().organization_name
|
28
33
|
elif aggregation_type == 'division':
|
29
34
|
aggregation_name = session.query(Division).filter(Division.id == aggregation_id).first().level
|
30
35
|
elif aggregation_type == 'level':
|
@@ -40,7 +45,6 @@ def aggregate_skater_stats(session, aggregation_type, aggregation_id, names_to_f
|
|
40
45
|
else:
|
41
46
|
StatsModel = OrgStatsSkater
|
42
47
|
min_games = MIN_GAMES_FOR_ORG_STATS
|
43
|
-
filter_condition = Game.org_id == aggregation_id
|
44
48
|
elif aggregation_type == 'division':
|
45
49
|
if aggregation_window == 'Daily':
|
46
50
|
StatsModel = DivisionStatsDailySkater
|
@@ -80,42 +84,38 @@ def aggregate_skater_stats(session, aggregation_type, aggregation_id, names_to_f
|
|
80
84
|
|
81
85
|
# Aggregate games played for each human in each division, excluding goalies
|
82
86
|
games_played_stats = session.query(
|
83
|
-
Game.org_id,
|
84
87
|
GameRoster.human_id,
|
85
88
|
func.count(Game.id).label('games_played'),
|
86
89
|
func.array_agg(Game.id).label('game_ids')
|
87
|
-
).join(
|
90
|
+
).join(Game, Game.id == GameRoster.game_id).join(Division, Game.division_id == Division.id).filter(filter_condition, ~GameRoster.role.ilike('g'), *human_filter).group_by(GameRoster.human_id).all()
|
88
91
|
|
89
92
|
# Aggregate goals for each human in each division, excluding goalies
|
90
93
|
goals_stats = session.query(
|
91
|
-
Game.org_id,
|
92
94
|
Goal.goal_scorer_id.label('human_id'),
|
93
95
|
func.count(Goal.id).label('goals'),
|
94
96
|
func.array_agg(Goal.game_id).label('goal_game_ids')
|
95
|
-
).join(Game, Game.id == Goal.game_id).join(GameRoster, and_(Game.id == GameRoster.game_id, Goal.goal_scorer_id == GameRoster.human_id)).join(Division, Game.division_id == Division.id).filter(filter_condition, ~GameRoster.role.ilike('g'), *human_filter).group_by(
|
97
|
+
).join(Game, Game.id == Goal.game_id).join(GameRoster, and_(Game.id == GameRoster.game_id, Goal.goal_scorer_id == GameRoster.human_id)).join(Division, Game.division_id == Division.id).filter(filter_condition, ~GameRoster.role.ilike('g'), *human_filter).group_by(Goal.goal_scorer_id).all()
|
96
98
|
|
97
99
|
# Aggregate assists for each human in each division, excluding goalies
|
98
100
|
assists_stats = session.query(
|
99
|
-
Game.org_id,
|
100
101
|
Goal.assist_1_id.label('human_id'),
|
101
102
|
func.count(Goal.id).label('assists'),
|
102
103
|
func.array_agg(Goal.game_id).label('assist_game_ids')
|
103
|
-
).join(Game, Game.id == Goal.game_id).join(GameRoster, and_(Game.id == GameRoster.game_id, Goal.assist_1_id == GameRoster.human_id)).join(Division, Game.division_id == Division.id).filter(filter_condition, ~GameRoster.role.ilike('g'), *human_filter).group_by(
|
104
|
+
).join(Game, Game.id == Goal.game_id).join(GameRoster, and_(Game.id == GameRoster.game_id, Goal.assist_1_id == GameRoster.human_id)).join(Division, Game.division_id == Division.id).filter(filter_condition, ~GameRoster.role.ilike('g'), *human_filter).group_by(Goal.assist_1_id).all()
|
104
105
|
|
105
106
|
assists_stats_2 = session.query(
|
106
|
-
Game.org_id,
|
107
107
|
Goal.assist_2_id.label('human_id'),
|
108
108
|
func.count(Goal.id).label('assists'),
|
109
109
|
func.array_agg(Goal.game_id).label('assist_2_game_ids')
|
110
|
-
).join(Game, Game.id == Goal.game_id).join(GameRoster, and_(Game.id == GameRoster.game_id, Goal.assist_2_id == GameRoster.human_id)).join(Division, Game.division_id == Division.id).filter(filter_condition, ~GameRoster.role.ilike('g'), *human_filter).group_by(
|
110
|
+
).join(Game, Game.id == Goal.game_id).join(GameRoster, and_(Game.id == GameRoster.game_id, Goal.assist_2_id == GameRoster.human_id)).join(Division, Game.division_id == Division.id).filter(filter_condition, ~GameRoster.role.ilike('g'), *human_filter).group_by(Goal.assist_2_id).all()
|
111
111
|
|
112
112
|
# Aggregate penalties for each human in each division, excluding goalies
|
113
113
|
penalties_stats = session.query(
|
114
|
-
Game.org_id,
|
115
114
|
Penalty.penalized_player_id.label('human_id'),
|
116
115
|
func.count(Penalty.id).label('penalties'),
|
116
|
+
func.sum(case((Penalty.penalty_minutes == 'GM', 1), else_=0)).label('gm_penalties'), # New aggregation for GM penalties
|
117
117
|
func.array_agg(Penalty.game_id).label('penalty_game_ids')
|
118
|
-
).join(Game, Game.id == Penalty.game_id).join(GameRoster, and_(Game.id == GameRoster.game_id, Penalty.penalized_player_id == GameRoster.human_id)).join(Division, Game.division_id == Division.id).filter(filter_condition, ~GameRoster.role.ilike('g'), *human_filter).group_by(
|
118
|
+
).join(Game, Game.id == Penalty.game_id).join(GameRoster, and_(Game.id == GameRoster.game_id, Penalty.penalized_player_id == GameRoster.human_id)).join(Division, Game.division_id == Division.id).filter(filter_condition, ~GameRoster.role.ilike('g'), *human_filter).group_by(Penalty.penalized_player_id).all()
|
119
119
|
|
120
120
|
# Combine the results
|
121
121
|
stats_dict = {}
|
@@ -123,22 +123,27 @@ def aggregate_skater_stats(session, aggregation_type, aggregation_id, names_to_f
|
|
123
123
|
if stat.human_id in human_ids_to_filter:
|
124
124
|
continue
|
125
125
|
key = (aggregation_id, stat.human_id)
|
126
|
-
if
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
126
|
+
if key not in stats_dict:
|
127
|
+
stats_dict[key] = {
|
128
|
+
'games_played': 0,
|
129
|
+
'goals': 0,
|
130
|
+
'assists': 0,
|
131
|
+
'penalties': 0,
|
132
|
+
'gm_penalties': 0, # Initialize GM penalties
|
133
|
+
'points': 0, # Initialize points
|
134
|
+
'goals_per_game': 0.0,
|
135
|
+
'points_per_game': 0.0,
|
136
|
+
'assists_per_game': 0.0,
|
137
|
+
'penalties_per_game': 0.0,
|
138
|
+
'game_ids': [],
|
139
|
+
'first_game_id': None,
|
140
|
+
'last_game_id': None
|
141
|
+
}
|
142
|
+
stats_dict[key]['games_played'] += stat.games_played
|
143
|
+
stats_dict[key]['game_ids'].extend(stat.game_ids)
|
144
|
+
|
145
|
+
# Filter out entries with games_played less than min_games
|
146
|
+
stats_dict = {key: value for key, value in stats_dict.items() if value['games_played'] >= min_games}
|
142
147
|
|
143
148
|
for stat in goals_stats:
|
144
149
|
key = (aggregation_id, stat.human_id)
|
@@ -162,6 +167,7 @@ def aggregate_skater_stats(session, aggregation_type, aggregation_id, names_to_f
|
|
162
167
|
key = (aggregation_id, stat.human_id)
|
163
168
|
if key in stats_dict:
|
164
169
|
stats_dict[key]['penalties'] += stat.penalties
|
170
|
+
stats_dict[key]['gm_penalties'] += stat.gm_penalties # Update GM penalties
|
165
171
|
|
166
172
|
# Calculate per game stats
|
167
173
|
for key, stat in stats_dict.items():
|
@@ -197,6 +203,7 @@ def aggregate_skater_stats(session, aggregation_type, aggregation_id, names_to_f
|
|
197
203
|
assign_ranks(stats_dict, 'assists')
|
198
204
|
assign_ranks(stats_dict, 'points')
|
199
205
|
assign_ranks(stats_dict, 'penalties')
|
206
|
+
assign_ranks(stats_dict, 'gm_penalties') # Assign ranks for GM penalties
|
200
207
|
assign_ranks(stats_dict, 'goals_per_game')
|
201
208
|
assign_ranks(stats_dict, 'points_per_game')
|
202
209
|
assign_ranks(stats_dict, 'assists_per_game')
|
@@ -230,6 +237,7 @@ def aggregate_skater_stats(session, aggregation_type, aggregation_id, names_to_f
|
|
230
237
|
assists=stat['assists'],
|
231
238
|
points=stat['goals'] + stat['assists'],
|
232
239
|
penalties=stat['penalties'],
|
240
|
+
gm_penalties=stat['gm_penalties'], # Include GM penalties
|
233
241
|
goals_per_game=goals_per_game,
|
234
242
|
points_per_game=points_per_game,
|
235
243
|
assists_per_game=assists_per_game,
|
@@ -239,6 +247,7 @@ def aggregate_skater_stats(session, aggregation_type, aggregation_id, names_to_f
|
|
239
247
|
assists_rank=stat['assists_rank'],
|
240
248
|
points_rank=stat['points_rank'],
|
241
249
|
penalties_rank=stat['penalties_rank'],
|
250
|
+
gm_penalties_rank=stat['gm_penalties_rank'], # Include GM penalties rank
|
242
251
|
goals_per_game_rank=stat['goals_per_game_rank'],
|
243
252
|
points_per_game_rank=stat['points_per_game_rank'],
|
244
253
|
assists_per_game_rank=stat['assists_per_game_rank'],
|
@@ -278,7 +287,7 @@ def run_aggregate_skater_stats():
|
|
278
287
|
aggregate_skater_stats(session, aggregation_type='org', aggregation_id=org_id, names_to_filter_out=not_human_names, debug_human_id=human_id_to_debug, aggregation_window='Weekly')
|
279
288
|
aggregate_skater_stats(session, aggregation_type='org', aggregation_id=org_id, names_to_filter_out=not_human_names, debug_human_id=human_id_to_debug, aggregation_window='Daily')
|
280
289
|
|
281
|
-
|
290
|
+
# Aggregate by level
|
282
291
|
level_ids = session.query(Division.level_id).distinct().all()
|
283
292
|
level_ids = [level_id[0] for level_id in level_ids]
|
284
293
|
total_levels = len(level_ids)
|
Binary file
|
@@ -62,6 +62,8 @@ class BaseStatsSkater(db.Model):
|
|
62
62
|
points_rank = db.Column(db.Integer, default=0)
|
63
63
|
penalties = db.Column(db.Integer, default=0)
|
64
64
|
penalties_rank = db.Column(db.Integer, default=0)
|
65
|
+
gm_penalties = db.Column(db.Integer, default=0) # New field for GM penalties
|
66
|
+
gm_penalties_rank = db.Column(db.Integer, default=0) # New field for GM penalties rank
|
65
67
|
goals_per_game = db.Column(db.Float, default=0.0)
|
66
68
|
goals_per_game_rank = db.Column(db.Integer, default=0)
|
67
69
|
points_per_game = db.Column(db.Float, default=0.0)
|
@@ -0,0 +1,6 @@
|
|
1
|
+
def assign_ranks(stats_dict, field, reverse_rank=False):
|
2
|
+
sorted_stats = sorted(stats_dict.items(), key=lambda x: x[1][field], reverse=not reverse_rank)
|
3
|
+
for rank, (key, stat) in enumerate(sorted_stats, start=1):
|
4
|
+
stats_dict[key][f'{field}_rank'] = rank
|
5
|
+
|
6
|
+
ALL_ORGS_ID = -1
|
{hockey_blast_common_lib-0.1.38.dist-info → hockey_blast_common_lib-0.1.40.dist-info}/RECORD
RENAMED
@@ -1,23 +1,23 @@
|
|
1
1
|
hockey_blast_common_lib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
2
|
hockey_blast_common_lib/aggregate_all_stats.py,sha256=MUjT23mdOMfCTx-kRSY-LGrLHZ9HNlR6OMqv5KLdzR4,1056
|
3
|
-
hockey_blast_common_lib/aggregate_goalie_stats.py,sha256=
|
4
|
-
hockey_blast_common_lib/aggregate_human_stats.py,sha256=
|
5
|
-
hockey_blast_common_lib/aggregate_referee_stats.py,sha256=
|
6
|
-
hockey_blast_common_lib/aggregate_skater_stats.py,sha256=
|
3
|
+
hockey_blast_common_lib/aggregate_goalie_stats.py,sha256=FcYL40NP0-sPY7UI7F8Ny_RaPKz3mfkmhQnPVbeRtOc,12178
|
4
|
+
hockey_blast_common_lib/aggregate_human_stats.py,sha256=6cDoiJ0xZ3aQ4wjEAP_Jgu2aNEicnuU-a22BncSFtRo,23920
|
5
|
+
hockey_blast_common_lib/aggregate_referee_stats.py,sha256=FszWLTygddDQNcUgbmevQ-eGPrW8Y0nXpRvUluPRKnU,11920
|
6
|
+
hockey_blast_common_lib/aggregate_skater_stats.py,sha256=JK_JnmsNHecpMOng3pV_cf03tjIsUS-uGt0G9MPCrbM,16547
|
7
7
|
hockey_blast_common_lib/assign_skater_skill.py,sha256=p-0fbodGpM8BCjKHDpxNb7BH2FcIlBsJwON844KNrUY,1817
|
8
8
|
hockey_blast_common_lib/db_connection.py,sha256=HvPxDvOj7j5H85RfslGvHVNevfg7mKCd0syJ6NX21mU,1890
|
9
9
|
hockey_blast_common_lib/dump_sample_db.sh,sha256=MHPA-Ciod7wsvAlMbRtXFiyajgnEqU1xR59sJQ9UWR0,738
|
10
|
-
hockey_blast_common_lib/hockey_blast_sample_backup.sql.gz,sha256=
|
10
|
+
hockey_blast_common_lib/hockey_blast_sample_backup.sql.gz,sha256=uU1QOjEWNMji7TP5YhILFKZptRoR-1HcjBBw7mX4kI4,51
|
11
11
|
hockey_blast_common_lib/models.py,sha256=xne38KwdBDcWvzdLyU6toozqkuatB9wiQhyiQ4xvAgU,16413
|
12
12
|
hockey_blast_common_lib/options.py,sha256=6na8fo-5A2RBPpd_h-7dsqetOLSLoNEJg1QMYgl4jNs,792
|
13
13
|
hockey_blast_common_lib/restore_sample_db.sh,sha256=u2zKazC6vNMULkpYzI64nlneCWaGUtDHPBAU-gWgRbw,1861
|
14
14
|
hockey_blast_common_lib/skills_in_divisions.py,sha256=m-UEwMwn1KM7wOYvDstgsOEeH57M9V6yrkBoghzGYKE,7005
|
15
15
|
hockey_blast_common_lib/skills_propagation.py,sha256=x6yy7fJ6IX3YiHqiP_v7-p_S2Expb8JJ-mWuajEFBdY,16388
|
16
|
-
hockey_blast_common_lib/stats_models.py,sha256=
|
17
|
-
hockey_blast_common_lib/stats_utils.py,sha256=
|
16
|
+
hockey_blast_common_lib/stats_models.py,sha256=__BtG0LtSZ2yWHU_fCh7-RVyjO0EhDNMctOW2cAzjnk,25294
|
17
|
+
hockey_blast_common_lib/stats_utils.py,sha256=DXsPO4jw8XsdRUN46TGF_IiBAfz3GCIVBswCGp5ELDk,284
|
18
18
|
hockey_blast_common_lib/utils.py,sha256=Sy5Pk40Tk3gsMrhMsUMlBD7i7jiVZmWLUBc94qI3zOA,5235
|
19
19
|
hockey_blast_common_lib/wsgi.py,sha256=7LGUzioigviJp-EUhSEaQcd4jBae0mxbkyBscQfZhlc,730
|
20
|
-
hockey_blast_common_lib-0.1.
|
21
|
-
hockey_blast_common_lib-0.1.
|
22
|
-
hockey_blast_common_lib-0.1.
|
23
|
-
hockey_blast_common_lib-0.1.
|
20
|
+
hockey_blast_common_lib-0.1.40.dist-info/METADATA,sha256=c1tQbNlrUW8MNh2f0Z7MVmwolW4HMgmGvH6v7YHicaI,318
|
21
|
+
hockey_blast_common_lib-0.1.40.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
|
22
|
+
hockey_blast_common_lib-0.1.40.dist-info/top_level.txt,sha256=wIR4LIkE40npoA2QlOdfCYlgFeGbsHR8Z6r0h46Vtgc,24
|
23
|
+
hockey_blast_common_lib-0.1.40.dist-info/RECORD,,
|
File without changes
|
{hockey_blast_common_lib-0.1.38.dist-info → hockey_blast_common_lib-0.1.40.dist-info}/top_level.txt
RENAMED
File without changes
|