hockey-blast-common-lib 0.1.7__py3-none-any.whl → 0.1.9__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 +165 -0
- hockey_blast_common_lib/aggregate_human_stats.py +296 -0
- hockey_blast_common_lib/aggregate_referee_stats.py +234 -0
- hockey_blast_common_lib/aggregate_skater_stats.py +327 -0
- hockey_blast_common_lib/db_connection.py +9 -0
- hockey_blast_common_lib/db_utils.py +1 -1
- hockey_blast_common_lib/options.py +22 -0
- hockey_blast_common_lib/stats_models.py +32 -1
- hockey_blast_common_lib/utils.py +65 -0
- {hockey_blast_common_lib-0.1.7.dist-info → hockey_blast_common_lib-0.1.9.dist-info}/METADATA +1 -1
- hockey_blast_common_lib-0.1.9.dist-info/RECORD +16 -0
- hockey_blast_common_lib-0.1.7.dist-info/RECORD +0 -10
- {hockey_blast_common_lib-0.1.7.dist-info → hockey_blast_common_lib-0.1.9.dist-info}/WHEEL +0 -0
- {hockey_blast_common_lib-0.1.7.dist-info → hockey_blast_common_lib-0.1.9.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,234 @@
|
|
1
|
+
import sys, os
|
2
|
+
|
3
|
+
# Add the package directory to the Python path
|
4
|
+
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
5
|
+
|
6
|
+
|
7
|
+
from datetime import datetime, timedelta
|
8
|
+
import sqlalchemy
|
9
|
+
from hockey_blast_common_lib.models import Game, Penalty
|
10
|
+
from stats_models import OrgStatsReferee, DivisionStatsReferee,OrgStatsWeeklyReferee, OrgStatsDailyReferee, DivisionStatsWeeklyReferee, DivisionStatsDailyReferee
|
11
|
+
from db_connection import create_session
|
12
|
+
from sqlalchemy.sql import func, case
|
13
|
+
from options import parse_args, MIN_GAMES_FOR_ORG_STATS, MIN_GAMES_FOR_DIVISION_STATS, not_human_names
|
14
|
+
from utils import get_org_id_from_alias, get_human_ids_by_names, get_division_ids_for_last_season_in_all_leagues
|
15
|
+
|
16
|
+
def aggregate_referee_stats(session, aggregation_type, aggregation_id, names_to_filter_out, aggregation_window=None):
|
17
|
+
human_ids_to_filter = get_human_ids_by_names(session, names_to_filter_out)
|
18
|
+
|
19
|
+
if aggregation_type == 'org':
|
20
|
+
if aggregation_window == 'Daily':
|
21
|
+
StatsModel = OrgStatsDailyReferee
|
22
|
+
elif aggregation_window == 'Weekly':
|
23
|
+
StatsModel = OrgStatsWeeklyReferee
|
24
|
+
else:
|
25
|
+
StatsModel = OrgStatsReferee
|
26
|
+
min_games = MIN_GAMES_FOR_ORG_STATS
|
27
|
+
filter_condition = Game.org_id == aggregation_id
|
28
|
+
elif aggregation_type == 'division':
|
29
|
+
if aggregation_window == 'Daily':
|
30
|
+
StatsModel = DivisionStatsDailyReferee
|
31
|
+
elif aggregation_window == 'Weekly':
|
32
|
+
StatsModel = DivisionStatsWeeklyReferee
|
33
|
+
else:
|
34
|
+
StatsModel = DivisionStatsReferee
|
35
|
+
min_games = MIN_GAMES_FOR_DIVISION_STATS
|
36
|
+
filter_condition = Game.division_id == aggregation_id
|
37
|
+
else:
|
38
|
+
raise ValueError("Invalid aggregation type")
|
39
|
+
|
40
|
+
# Apply aggregation window filter
|
41
|
+
if aggregation_window:
|
42
|
+
last_game_datetime = session.query(func.max(func.concat(Game.date, ' ', Game.time))).filter(filter_condition, Game.status.like('Final%')).scalar()
|
43
|
+
if last_game_datetime:
|
44
|
+
last_game_datetime = datetime.strptime(last_game_datetime, '%Y-%m-%d %H:%M:%S')
|
45
|
+
if aggregation_window == 'Daily':
|
46
|
+
start_datetime = last_game_datetime - timedelta(days=1)
|
47
|
+
elif aggregation_window == 'Weekly':
|
48
|
+
start_datetime = last_game_datetime - timedelta(weeks=1)
|
49
|
+
else:
|
50
|
+
start_datetime = None
|
51
|
+
if start_datetime:
|
52
|
+
game_window_filter = func.cast(func.concat(Game.date, ' ', Game.time), sqlalchemy.types.TIMESTAMP).between(start_datetime, last_game_datetime)
|
53
|
+
filter_condition = filter_condition & game_window_filter
|
54
|
+
|
55
|
+
# Delete existing items from the stats table
|
56
|
+
session.query(StatsModel).filter(StatsModel.aggregation_id == aggregation_id).delete()
|
57
|
+
session.commit()
|
58
|
+
|
59
|
+
# Aggregate games reffed for each referee
|
60
|
+
games_reffed_stats = session.query(
|
61
|
+
Game.referee_1_id.label('human_id'),
|
62
|
+
func.count(Game.id).label('games_reffed'),
|
63
|
+
func.array_agg(Game.id).label('game_ids')
|
64
|
+
).filter(filter_condition).group_by(Game.referee_1_id).all()
|
65
|
+
|
66
|
+
games_reffed_stats_2 = session.query(
|
67
|
+
Game.referee_2_id.label('human_id'),
|
68
|
+
func.count(Game.id).label('games_reffed'),
|
69
|
+
func.array_agg(Game.id).label('game_ids')
|
70
|
+
).filter(filter_condition).group_by(Game.referee_2_id).all()
|
71
|
+
|
72
|
+
# Aggregate penalties given for each referee
|
73
|
+
penalties_given_stats = session.query(
|
74
|
+
Game.id.label('game_id'),
|
75
|
+
Game.referee_1_id,
|
76
|
+
Game.referee_2_id,
|
77
|
+
func.count(Penalty.id).label('penalties_given'),
|
78
|
+
func.sum(case((func.lower(Penalty.penalty_minutes) == 'gm', 1), else_=0)).label('gm_given')
|
79
|
+
).join(Game, Game.id == Penalty.game_id).filter(filter_condition).group_by(Game.id, Game.referee_1_id, Game.referee_2_id).all()
|
80
|
+
|
81
|
+
# Combine the results
|
82
|
+
stats_dict = {}
|
83
|
+
for stat in games_reffed_stats:
|
84
|
+
if stat.human_id in human_ids_to_filter:
|
85
|
+
continue
|
86
|
+
key = (aggregation_id, stat.human_id)
|
87
|
+
stats_dict[key] = {
|
88
|
+
'games_reffed': stat.games_reffed,
|
89
|
+
'penalties_given': 0,
|
90
|
+
'gm_given': 0,
|
91
|
+
'penalties_per_game': 0.0,
|
92
|
+
'gm_per_game': 0.0,
|
93
|
+
'game_ids': stat.game_ids,
|
94
|
+
'first_game_id': None,
|
95
|
+
'last_game_id': None
|
96
|
+
}
|
97
|
+
|
98
|
+
for stat in games_reffed_stats_2:
|
99
|
+
if stat.human_id in human_ids_to_filter:
|
100
|
+
continue
|
101
|
+
key = (aggregation_id, stat.human_id)
|
102
|
+
if key not in stats_dict:
|
103
|
+
stats_dict[key] = {
|
104
|
+
'games_reffed': stat.games_reffed,
|
105
|
+
'penalties_given': 0,
|
106
|
+
'gm_given': 0,
|
107
|
+
'penalties_per_game': 0.0,
|
108
|
+
'gm_per_game': 0.0,
|
109
|
+
'game_ids': stat.game_ids,
|
110
|
+
'first_game_id': None,
|
111
|
+
'last_game_id': None
|
112
|
+
}
|
113
|
+
else:
|
114
|
+
stats_dict[key]['games_reffed'] += stat.games_reffed
|
115
|
+
stats_dict[key]['game_ids'].extend(stat.game_ids)
|
116
|
+
|
117
|
+
for stat in penalties_given_stats:
|
118
|
+
if stat.referee_1_id and stat.referee_1_id not in human_ids_to_filter:
|
119
|
+
key = (aggregation_id, stat.referee_1_id)
|
120
|
+
if key not in stats_dict:
|
121
|
+
stats_dict[key] = {
|
122
|
+
'games_reffed': 0,
|
123
|
+
'penalties_given': stat.penalties_given / 2,
|
124
|
+
'gm_given': stat.gm_given / 2,
|
125
|
+
'penalties_per_game': 0.0,
|
126
|
+
'gm_per_game': 0.0,
|
127
|
+
'game_ids': [stat.game_id],
|
128
|
+
'first_game_id': None,
|
129
|
+
'last_game_id': None
|
130
|
+
}
|
131
|
+
else:
|
132
|
+
stats_dict[key]['penalties_given'] += stat.penalties_given / 2
|
133
|
+
stats_dict[key]['gm_given'] += stat.gm_given / 2
|
134
|
+
stats_dict[key]['game_ids'].append(stat.game_id)
|
135
|
+
|
136
|
+
if stat.referee_2_id and stat.referee_2_id not in human_ids_to_filter:
|
137
|
+
key = (aggregation_id, stat.referee_2_id)
|
138
|
+
if key not in stats_dict:
|
139
|
+
stats_dict[key] = {
|
140
|
+
'games_reffed': 0,
|
141
|
+
'penalties_given': stat.penalties_given / 2,
|
142
|
+
'gm_given': stat.gm_given / 2,
|
143
|
+
'penalties_per_game': 0.0,
|
144
|
+
'gm_per_game': 0.0,
|
145
|
+
'game_ids': [stat.game_id],
|
146
|
+
'first_game_id': None,
|
147
|
+
'last_game_id': None
|
148
|
+
}
|
149
|
+
else:
|
150
|
+
stats_dict[key]['penalties_given'] += stat.penalties_given / 2
|
151
|
+
stats_dict[key]['gm_given'] += stat.gm_given / 2
|
152
|
+
stats_dict[key]['game_ids'].append(stat.game_id)
|
153
|
+
|
154
|
+
# Calculate per game stats
|
155
|
+
for key, stat in stats_dict.items():
|
156
|
+
if stat['games_reffed'] > 0:
|
157
|
+
stat['penalties_per_game'] = stat['penalties_given'] / stat['games_reffed']
|
158
|
+
stat['gm_per_game'] = stat['gm_given'] / stat['games_reffed']
|
159
|
+
|
160
|
+
# Ensure all keys have valid human_id values
|
161
|
+
stats_dict = {key: value for key, value in stats_dict.items() if key[1] is not None}
|
162
|
+
|
163
|
+
# Populate first_game_id and last_game_id
|
164
|
+
for key, stat in stats_dict.items():
|
165
|
+
all_game_ids = stat['game_ids']
|
166
|
+
if all_game_ids:
|
167
|
+
first_game = session.query(Game).filter(Game.id.in_(all_game_ids)).order_by(Game.date, Game.time).first()
|
168
|
+
last_game = session.query(Game).filter(Game.id.in_(all_game_ids)).order_by(Game.date.desc(), Game.time.desc()).first()
|
169
|
+
stat['first_game_id'] = first_game.id if first_game else None
|
170
|
+
stat['last_game_id'] = last_game.id if last_game else None
|
171
|
+
|
172
|
+
# Calculate total_in_rank
|
173
|
+
total_in_rank = len(stats_dict)
|
174
|
+
|
175
|
+
# Assign ranks
|
176
|
+
def assign_ranks(stats_dict, field):
|
177
|
+
sorted_stats = sorted(stats_dict.items(), key=lambda x: x[1][field], reverse=True)
|
178
|
+
for rank, (key, stat) in enumerate(sorted_stats, start=1):
|
179
|
+
stats_dict[key][f'{field}_rank'] = rank
|
180
|
+
|
181
|
+
assign_ranks(stats_dict, 'games_reffed')
|
182
|
+
assign_ranks(stats_dict, 'penalties_given')
|
183
|
+
assign_ranks(stats_dict, 'penalties_per_game')
|
184
|
+
assign_ranks(stats_dict, 'gm_given')
|
185
|
+
assign_ranks(stats_dict, 'gm_per_game')
|
186
|
+
|
187
|
+
# Insert aggregated stats into the appropriate table with progress output
|
188
|
+
total_items = len(stats_dict)
|
189
|
+
batch_size = 1000
|
190
|
+
for i, (key, stat) in enumerate(stats_dict.items(), 1):
|
191
|
+
aggregation_id, human_id = key
|
192
|
+
if stat['games_reffed'] < min_games:
|
193
|
+
continue
|
194
|
+
referee_stat = StatsModel(
|
195
|
+
aggregation_id=aggregation_id,
|
196
|
+
human_id=human_id,
|
197
|
+
games_reffed=stat['games_reffed'],
|
198
|
+
penalties_given=stat['penalties_given'],
|
199
|
+
penalties_per_game=stat['penalties_per_game'],
|
200
|
+
gm_given=stat['gm_given'],
|
201
|
+
gm_per_game=stat['gm_per_game'],
|
202
|
+
games_reffed_rank=stat['games_reffed_rank'],
|
203
|
+
penalties_given_rank=stat['penalties_given_rank'],
|
204
|
+
penalties_per_game_rank=stat['penalties_per_game_rank'],
|
205
|
+
gm_given_rank=stat['gm_given_rank'],
|
206
|
+
gm_per_game_rank=stat['gm_per_game_rank'],
|
207
|
+
total_in_rank=total_in_rank,
|
208
|
+
first_game_id=stat['first_game_id'],
|
209
|
+
last_game_id=stat['last_game_id']
|
210
|
+
)
|
211
|
+
session.add(referee_stat)
|
212
|
+
# Commit in batches
|
213
|
+
if i % batch_size == 0:
|
214
|
+
session.commit()
|
215
|
+
print(f"\r{i}/{total_items} ({(i/total_items)*100:.2f}%)", end="")
|
216
|
+
session.commit()
|
217
|
+
print(f"\r{total_items}/{total_items} (100.00%)")
|
218
|
+
print("\nDone.")
|
219
|
+
|
220
|
+
# Example usage
|
221
|
+
if __name__ == "__main__":
|
222
|
+
args = parse_args()
|
223
|
+
org_alias = args.org
|
224
|
+
session = create_session("boss")
|
225
|
+
org_id = get_org_id_from_alias(session, org_alias)
|
226
|
+
division_ids = get_division_ids_for_last_season_in_all_leagues(session, org_id)
|
227
|
+
print(f"Aggregating referee stats for {len(division_ids)} divisions in {org_alias}...")
|
228
|
+
for division_id in division_ids:
|
229
|
+
aggregate_referee_stats(session, aggregation_type='division', aggregation_id=division_id, names_to_filter_out=not_human_names)
|
230
|
+
aggregate_referee_stats(session, aggregation_type='division', aggregation_id=division_id, names_to_filter_out=not_human_names, aggregation_window='Weekly')
|
231
|
+
aggregate_referee_stats(session, aggregation_type='division', aggregation_id=division_id, names_to_filter_out=not_human_names, aggregation_window='Daily')
|
232
|
+
aggregate_referee_stats(session, aggregation_type='org', aggregation_id=org_id, names_to_filter_out=not_human_names)
|
233
|
+
aggregate_referee_stats(session, aggregation_type='org', aggregation_id=org_id, names_to_filter_out=not_human_names, aggregation_window='Weekly')
|
234
|
+
aggregate_referee_stats(session, aggregation_type='org', aggregation_id=org_id, names_to_filter_out=not_human_names, aggregation_window='Daily')
|
@@ -0,0 +1,327 @@
|
|
1
|
+
import sys, os
|
2
|
+
|
3
|
+
# Add the package directory to the Python path
|
4
|
+
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
5
|
+
|
6
|
+
from datetime import datetime, timedelta
|
7
|
+
import sqlalchemy
|
8
|
+
from options import not_human_names
|
9
|
+
|
10
|
+
from hockey_blast_common_lib.models import Game, Goal, Penalty, GameRoster
|
11
|
+
from stats_models import OrgStatsSkater, DivisionStatsSkater, OrgStatsWeeklySkater, OrgStatsDailySkater, DivisionStatsWeeklySkater, DivisionStatsDailySkater
|
12
|
+
from db_connection import create_session
|
13
|
+
from sqlalchemy.sql import func, case
|
14
|
+
from options import parse_args, MIN_GAMES_FOR_ORG_STATS, MIN_GAMES_FOR_DIVISION_STATS
|
15
|
+
from utils import get_org_id_from_alias, get_human_ids_by_names, get_division_ids_for_last_season_in_all_leagues
|
16
|
+
from sqlalchemy import func, case, and_
|
17
|
+
|
18
|
+
def aggregate_skater_stats(session, aggregation_type, aggregation_id, names_to_filter_out, filter_human_id=None, aggregation_window=None):
|
19
|
+
human_ids_to_filter = get_human_ids_by_names(session, names_to_filter_out)
|
20
|
+
|
21
|
+
if aggregation_type == 'org':
|
22
|
+
if aggregation_window == 'Daily':
|
23
|
+
StatsModel = OrgStatsDailySkater
|
24
|
+
elif aggregation_window == 'Weekly':
|
25
|
+
StatsModel = OrgStatsWeeklySkater
|
26
|
+
else:
|
27
|
+
StatsModel = OrgStatsSkater
|
28
|
+
min_games = MIN_GAMES_FOR_ORG_STATS
|
29
|
+
filter_condition = Game.org_id == aggregation_id
|
30
|
+
elif aggregation_type == 'division':
|
31
|
+
if aggregation_window == 'Daily':
|
32
|
+
StatsModel = DivisionStatsDailySkater
|
33
|
+
elif aggregation_window == 'Weekly':
|
34
|
+
StatsModel = DivisionStatsWeeklySkater
|
35
|
+
else:
|
36
|
+
StatsModel = DivisionStatsSkater
|
37
|
+
min_games = MIN_GAMES_FOR_DIVISION_STATS
|
38
|
+
filter_condition = Game.division_id == aggregation_id
|
39
|
+
else:
|
40
|
+
raise ValueError("Invalid aggregation type")
|
41
|
+
|
42
|
+
# Apply aggregation window filter
|
43
|
+
if aggregation_window:
|
44
|
+
last_game_datetime = session.query(func.max(func.concat(Game.date, ' ', Game.time))).filter(filter_condition, Game.status.like('Final%')).scalar()
|
45
|
+
if last_game_datetime:
|
46
|
+
last_game_datetime = datetime.strptime(last_game_datetime, '%Y-%m-%d %H:%M:%S')
|
47
|
+
if aggregation_window == 'Daily':
|
48
|
+
start_datetime = last_game_datetime - timedelta(days=1)
|
49
|
+
elif aggregation_window == 'Weekly':
|
50
|
+
start_datetime = last_game_datetime - timedelta(weeks=1)
|
51
|
+
else:
|
52
|
+
start_datetime = None
|
53
|
+
if start_datetime:
|
54
|
+
game_window_filter = func.cast(func.concat(Game.date, ' ', Game.time), sqlalchemy.types.TIMESTAMP).between(start_datetime, last_game_datetime)
|
55
|
+
filter_condition = filter_condition & game_window_filter
|
56
|
+
|
57
|
+
# Delete existing items from the stats table
|
58
|
+
session.query(StatsModel).filter(StatsModel.aggregation_id == aggregation_id).delete()
|
59
|
+
session.commit()
|
60
|
+
|
61
|
+
# Filter for specific human_id if provided
|
62
|
+
human_filter = []
|
63
|
+
if filter_human_id:
|
64
|
+
human_filter = [GameRoster.human_id == filter_human_id]
|
65
|
+
|
66
|
+
# Aggregate games played for each human in each division, excluding goalies
|
67
|
+
games_played_stats = session.query(
|
68
|
+
Game.org_id,
|
69
|
+
GameRoster.human_id,
|
70
|
+
func.count(Game.id).label('games_played'),
|
71
|
+
func.array_agg(Game.id).label('game_ids')
|
72
|
+
).join(GameRoster, Game.id == GameRoster.game_id).filter(filter_condition, ~GameRoster.role.ilike('g'), *human_filter).group_by(Game.org_id, GameRoster.human_id).all()
|
73
|
+
|
74
|
+
# Aggregate goals for each human in each division, excluding goalies
|
75
|
+
goals_stats = session.query(
|
76
|
+
Game.org_id,
|
77
|
+
Goal.goal_scorer_id.label('human_id'),
|
78
|
+
func.count(Goal.id).label('goals'),
|
79
|
+
func.array_agg(Goal.game_id).label('goal_game_ids')
|
80
|
+
).join(Game, Game.id == Goal.game_id).join(GameRoster, and_(Game.id == GameRoster.game_id, Goal.goal_scorer_id == GameRoster.human_id)).filter(filter_condition, ~GameRoster.role.ilike('g'), *human_filter).group_by(Game.org_id, Goal.goal_scorer_id).all()
|
81
|
+
|
82
|
+
# Aggregate assists for each human in each division, excluding goalies
|
83
|
+
assists_stats = session.query(
|
84
|
+
Game.org_id,
|
85
|
+
Goal.assist_1_id.label('human_id'),
|
86
|
+
func.count(Goal.id).label('assists'),
|
87
|
+
func.array_agg(Goal.game_id).label('assist_game_ids')
|
88
|
+
).join(Game, Game.id == Goal.game_id).join(GameRoster, and_(Game.id == GameRoster.game_id, Goal.assist_1_id == GameRoster.human_id)).filter(filter_condition, ~GameRoster.role.ilike('g'), *human_filter).group_by(Game.org_id, Goal.assist_1_id).all()
|
89
|
+
|
90
|
+
assists_stats_2 = session.query(
|
91
|
+
Game.org_id,
|
92
|
+
Goal.assist_2_id.label('human_id'),
|
93
|
+
func.count(Goal.id).label('assists'),
|
94
|
+
func.array_agg(Goal.game_id).label('assist_2_game_ids')
|
95
|
+
).join(Game, Game.id == Goal.game_id).join(GameRoster, and_(Game.id == GameRoster.game_id, Goal.assist_2_id == GameRoster.human_id)).filter(filter_condition, ~GameRoster.role.ilike('g'), *human_filter).group_by(Game.org_id, Goal.assist_2_id).all()
|
96
|
+
|
97
|
+
# Aggregate penalties for each human in each division, excluding goalies
|
98
|
+
penalties_stats = session.query(
|
99
|
+
Game.org_id,
|
100
|
+
Penalty.penalized_player_id.label('human_id'),
|
101
|
+
func.count(Penalty.id).label('penalties'),
|
102
|
+
func.array_agg(Penalty.game_id).label('penalty_game_ids')
|
103
|
+
).join(Game, Game.id == Penalty.game_id).join(GameRoster, and_(Game.id == GameRoster.game_id, Penalty.penalized_player_id == GameRoster.human_id)).filter(filter_condition, ~GameRoster.role.ilike('g'), *human_filter).group_by(Game.org_id, Penalty.penalized_player_id).all()
|
104
|
+
|
105
|
+
# Combine the results
|
106
|
+
stats_dict = {}
|
107
|
+
for stat in games_played_stats:
|
108
|
+
if stat.human_id in human_ids_to_filter:
|
109
|
+
continue
|
110
|
+
key = (aggregation_id, stat.human_id)
|
111
|
+
stats_dict[key] = {
|
112
|
+
'games_played': stat.games_played,
|
113
|
+
'goals': 0,
|
114
|
+
'assists': 0,
|
115
|
+
'penalties': 0,
|
116
|
+
'points': 0, # Initialize points
|
117
|
+
'goals_per_game': 0.0,
|
118
|
+
'points_per_game': 0.0,
|
119
|
+
'assists_per_game': 0.0,
|
120
|
+
'penalties_per_game': 0.0,
|
121
|
+
'game_ids': stat.game_ids,
|
122
|
+
'first_game_id': None,
|
123
|
+
'last_game_id': None
|
124
|
+
}
|
125
|
+
|
126
|
+
for stat in goals_stats:
|
127
|
+
if stat.human_id in human_ids_to_filter:
|
128
|
+
continue
|
129
|
+
key = (aggregation_id, stat.human_id)
|
130
|
+
if key not in stats_dict:
|
131
|
+
stats_dict[key] = {
|
132
|
+
'games_played': 0,
|
133
|
+
'goals': stat.goals,
|
134
|
+
'assists': 0,
|
135
|
+
'penalties': 0,
|
136
|
+
'points': stat.goals, # Initialize points with goals
|
137
|
+
'goals_per_game': 0.0,
|
138
|
+
'points_per_game': 0.0,
|
139
|
+
'assists_per_game': 0.0,
|
140
|
+
'penalties_per_game': 0.0,
|
141
|
+
'game_ids': [],
|
142
|
+
'first_game_id': None,
|
143
|
+
'last_game_id': None
|
144
|
+
}
|
145
|
+
else:
|
146
|
+
stats_dict[key]['goals'] += stat.goals
|
147
|
+
stats_dict[key]['points'] += stat.goals # Update points
|
148
|
+
|
149
|
+
for stat in assists_stats:
|
150
|
+
if stat.human_id in human_ids_to_filter:
|
151
|
+
continue
|
152
|
+
key = (aggregation_id, stat.human_id)
|
153
|
+
if key not in stats_dict:
|
154
|
+
stats_dict[key] = {
|
155
|
+
'games_played': 0,
|
156
|
+
'goals': 0,
|
157
|
+
'assists': stat.assists,
|
158
|
+
'penalties': 0,
|
159
|
+
'points': stat.assists, # Initialize points with assists
|
160
|
+
'goals_per_game': 0.0,
|
161
|
+
'points_per_game': 0.0,
|
162
|
+
'assists_per_game': 0.0,
|
163
|
+
'penalties_per_game': 0.0,
|
164
|
+
'game_ids': [],
|
165
|
+
'first_game_id': None,
|
166
|
+
'last_game_id': None
|
167
|
+
}
|
168
|
+
else:
|
169
|
+
stats_dict[key]['assists'] += stat.assists
|
170
|
+
stats_dict[key]['points'] += stat.assists # Update points
|
171
|
+
|
172
|
+
for stat in assists_stats_2:
|
173
|
+
if stat.human_id in human_ids_to_filter:
|
174
|
+
continue
|
175
|
+
key = (aggregation_id, stat.human_id)
|
176
|
+
if key not in stats_dict:
|
177
|
+
stats_dict[key] = {
|
178
|
+
'games_played': 0,
|
179
|
+
'goals': 0,
|
180
|
+
'assists': stat.assists,
|
181
|
+
'penalties': 0,
|
182
|
+
'points': stat.assists, # Initialize points with assists
|
183
|
+
'goals_per_game': 0.0,
|
184
|
+
'points_per_game': 0.0,
|
185
|
+
'assists_per_game': 0.0,
|
186
|
+
'penalties_per_game': 0.0,
|
187
|
+
'game_ids': [],
|
188
|
+
'first_game_id': None,
|
189
|
+
'last_game_id': None
|
190
|
+
}
|
191
|
+
else:
|
192
|
+
stats_dict[key]['assists'] += stat.assists
|
193
|
+
stats_dict[key]['points'] += stat.assists # Update points
|
194
|
+
|
195
|
+
for stat in penalties_stats:
|
196
|
+
if stat.human_id in human_ids_to_filter:
|
197
|
+
continue
|
198
|
+
key = (aggregation_id, stat.human_id)
|
199
|
+
if key not in stats_dict:
|
200
|
+
stats_dict[key] = {
|
201
|
+
'games_played': 0,
|
202
|
+
'goals': 0,
|
203
|
+
'assists': 0,
|
204
|
+
'penalties': stat.penalties,
|
205
|
+
'points': 0, # Initialize points
|
206
|
+
'goals_per_game': 0.0,
|
207
|
+
'points_per_game': 0.0,
|
208
|
+
'assists_per_game': 0.0,
|
209
|
+
'penalties_per_game': 0.0,
|
210
|
+
'game_ids': [],
|
211
|
+
'first_game_id': None,
|
212
|
+
'last_game_id': None
|
213
|
+
}
|
214
|
+
else:
|
215
|
+
stats_dict[key]['penalties'] += stat.penalties
|
216
|
+
|
217
|
+
# Calculate per game stats
|
218
|
+
for key, stat in stats_dict.items():
|
219
|
+
if stat['games_played'] > 0:
|
220
|
+
stat['goals_per_game'] = stat['goals'] / stat['games_played']
|
221
|
+
stat['points_per_game'] = stat['points'] / stat['games_played']
|
222
|
+
stat['assists_per_game'] = stat['assists'] / stat['games_played']
|
223
|
+
stat['penalties_per_game'] = stat['penalties'] / stat['games_played']
|
224
|
+
|
225
|
+
# Ensure all keys have valid human_id values
|
226
|
+
stats_dict = {key: value for key, value in stats_dict.items() if key[1] is not None}
|
227
|
+
|
228
|
+
# Populate first_game_id and last_game_id
|
229
|
+
for key, stat in stats_dict.items():
|
230
|
+
all_game_ids = stat['game_ids']
|
231
|
+
if all_game_ids:
|
232
|
+
first_game = session.query(Game).filter(Game.id.in_(all_game_ids)).order_by(Game.date, Game.time).first()
|
233
|
+
last_game = session.query(Game).filter(Game.id.in_(all_game_ids)).order_by(Game.date.desc(), Game.time.desc()).first()
|
234
|
+
stat['first_game_id'] = first_game.id if first_game else None
|
235
|
+
stat['last_game_id'] = last_game.id if last_game else None
|
236
|
+
|
237
|
+
# Debug output for totals if filter_human_id is provided
|
238
|
+
if filter_human_id:
|
239
|
+
for key, stat in stats_dict.items():
|
240
|
+
if key[1] == filter_human_id:
|
241
|
+
print(f"Human ID: {filter_human_id}")
|
242
|
+
print(f"Total Games Played: {stat['games_played']}")
|
243
|
+
print(f"Total Goals: {stat['goals']}")
|
244
|
+
print(f"Total Assists: {stat['assists']}")
|
245
|
+
print(f"Total Penalties: {stat['penalties']}")
|
246
|
+
|
247
|
+
# Calculate total_in_rank
|
248
|
+
total_in_rank = len(stats_dict)
|
249
|
+
|
250
|
+
# Assign ranks
|
251
|
+
def assign_ranks(stats_dict, field):
|
252
|
+
sorted_stats = sorted(stats_dict.items(), key=lambda x: x[1][field], reverse=True)
|
253
|
+
for rank, (key, stat) in enumerate(sorted_stats, start=1):
|
254
|
+
stats_dict[key][f'{field}_rank'] = rank
|
255
|
+
|
256
|
+
assign_ranks(stats_dict, 'games_played')
|
257
|
+
assign_ranks(stats_dict, 'goals')
|
258
|
+
assign_ranks(stats_dict, 'assists')
|
259
|
+
assign_ranks(stats_dict, 'points')
|
260
|
+
assign_ranks(stats_dict, 'penalties')
|
261
|
+
assign_ranks(stats_dict, 'goals_per_game')
|
262
|
+
assign_ranks(stats_dict, 'points_per_game')
|
263
|
+
assign_ranks(stats_dict, 'assists_per_game')
|
264
|
+
assign_ranks(stats_dict, 'penalties_per_game')
|
265
|
+
|
266
|
+
# Insert aggregated stats into the appropriate table with progress output
|
267
|
+
total_items = len(stats_dict)
|
268
|
+
batch_size = 1000
|
269
|
+
for i, (key, stat) in enumerate(stats_dict.items(), 1):
|
270
|
+
aggregation_id, human_id = key
|
271
|
+
if stat['games_played'] < min_games:
|
272
|
+
continue
|
273
|
+
goals_per_game = stat['goals'] / stat['games_played'] if stat['games_played'] > 0 else 0.0
|
274
|
+
points_per_game = (stat['goals'] + stat['assists']) / stat['games_played'] if stat['games_played'] > 0 else 0.0
|
275
|
+
assists_per_game = stat['assists'] / stat['games_played'] if stat['games_played'] > 0 else 0.0
|
276
|
+
penalties_per_game = stat['penalties'] / stat['games_played'] if stat['games_played'] > 0 else 0.0
|
277
|
+
skater_stat = StatsModel(
|
278
|
+
aggregation_id=aggregation_id,
|
279
|
+
human_id=human_id,
|
280
|
+
games_played=stat['games_played'],
|
281
|
+
goals=stat['goals'],
|
282
|
+
assists=stat['assists'],
|
283
|
+
points=stat['goals'] + stat['assists'],
|
284
|
+
penalties=stat['penalties'],
|
285
|
+
goals_per_game=goals_per_game,
|
286
|
+
points_per_game=points_per_game,
|
287
|
+
assists_per_game=assists_per_game,
|
288
|
+
penalties_per_game=penalties_per_game,
|
289
|
+
games_played_rank=stat['games_played_rank'],
|
290
|
+
goals_rank=stat['goals_rank'],
|
291
|
+
assists_rank=stat['assists_rank'],
|
292
|
+
points_rank=stat['points_rank'],
|
293
|
+
penalties_rank=stat['penalties_rank'],
|
294
|
+
goals_per_game_rank=stat['goals_per_game_rank'],
|
295
|
+
points_per_game_rank=stat['points_per_game_rank'],
|
296
|
+
assists_per_game_rank=stat['assists_per_game_rank'],
|
297
|
+
penalties_per_game_rank=stat['penalties_per_game_rank'],
|
298
|
+
total_in_rank=total_in_rank,
|
299
|
+
first_game_id=stat['first_game_id'],
|
300
|
+
last_game_id=stat['last_game_id']
|
301
|
+
)
|
302
|
+
session.add(skater_stat)
|
303
|
+
# Commit in batches
|
304
|
+
if i % batch_size == 0:
|
305
|
+
session.commit()
|
306
|
+
print(f"\r{i}/{total_items} ({(i/total_items)*100:.2f}%)", end="")
|
307
|
+
session.commit()
|
308
|
+
print(f"\r{total_items}/{total_items} (100.00%)")
|
309
|
+
print("\nDone.")
|
310
|
+
|
311
|
+
# Example usage
|
312
|
+
if __name__ == "__main__":
|
313
|
+
args = parse_args()
|
314
|
+
org_alias = args.org
|
315
|
+
session = create_session("boss")
|
316
|
+
org_id = get_org_id_from_alias(session, org_alias)
|
317
|
+
|
318
|
+
division_ids = get_division_ids_for_last_season_in_all_leagues(session, org_id)
|
319
|
+
print(f"Aggregating skater stats for {len(division_ids)} divisions in {org_alias}...")
|
320
|
+
for division_id in division_ids:
|
321
|
+
aggregate_skater_stats(session, aggregation_type='division', aggregation_id=division_id, names_to_filter_out=not_human_names, filter_human_id=None)
|
322
|
+
aggregate_skater_stats(session, aggregation_type='division', aggregation_id=division_id, names_to_filter_out=not_human_names, filter_human_id=None, aggregation_window='Weekly')
|
323
|
+
aggregate_skater_stats(session, aggregation_type='division', aggregation_id=division_id, names_to_filter_out=not_human_names, filter_human_id=None, aggregation_window='Daily')
|
324
|
+
|
325
|
+
aggregate_skater_stats(session, aggregation_type='org', aggregation_id=org_id, names_to_filter_out=not_human_names, filter_human_id=None)
|
326
|
+
aggregate_skater_stats(session, aggregation_type='org', aggregation_id=org_id, names_to_filter_out=not_human_names, filter_human_id=None, aggregation_window='Weekly')
|
327
|
+
aggregate_skater_stats(session, aggregation_type='org', aggregation_id=org_id, names_to_filter_out=not_human_names, filter_human_id=None, aggregation_window='Daily')
|
@@ -11,6 +11,15 @@ DB_PARAMS = {
|
|
11
11
|
"host": "localhost",
|
12
12
|
"port": 5432
|
13
13
|
},
|
14
|
+
|
15
|
+
"boss": {
|
16
|
+
"dbname": "hockey_blast",
|
17
|
+
"user": "boss",
|
18
|
+
"password": "WrongPassword",
|
19
|
+
"host": "localhost",
|
20
|
+
"port": 5432
|
21
|
+
},
|
22
|
+
|
14
23
|
}
|
15
24
|
|
16
25
|
def get_db_params(config_name):
|
@@ -0,0 +1,22 @@
|
|
1
|
+
import argparse
|
2
|
+
|
3
|
+
MAX_HUMAN_SEARCH_RESULTS = 25
|
4
|
+
MAX_TEAM_SEARCH_RESULTS = 25
|
5
|
+
MIN_GAMES_FOR_ORG_STATS = 1
|
6
|
+
MIN_GAMES_FOR_DIVISION_STATS = 1
|
7
|
+
|
8
|
+
orgs = {'caha', 'sharksice', 'tvice'}
|
9
|
+
|
10
|
+
not_human_names = [
|
11
|
+
("Away", None, None),
|
12
|
+
(None, "Unknown", None),
|
13
|
+
("Not", None , None),
|
14
|
+
(None , None, "Goalie")
|
15
|
+
]
|
16
|
+
|
17
|
+
def parse_args():
|
18
|
+
parser = argparse.ArgumentParser(description="Process data for a specific organization.")
|
19
|
+
parser.add_argument("org", choices=orgs, help="The organization to process (e.g., 'caha', 'sharksice', 'tvice').")
|
20
|
+
parser.add_argument("--reprocess", action="store_true", help="Reprocess existing data.")
|
21
|
+
parser.add_argument("--pre_process", action="store_true", help="Pre-Process existing data.")
|
22
|
+
return parser.parse_args()
|