Spaces:
Running
Running
Commit
·
a504793
1
Parent(s):
3eaff33
Add OFFB%, IFFB%, and AIR%
Browse files- pitch_leaderboard.py +3 -3
- player_team_leaderboard.py +6 -6
- stats.py +12 -6
pitch_leaderboard.py
CHANGED
|
@@ -10,9 +10,9 @@ from stats import compute_pitch_stats, filter_data_by_date_and_game_kind
|
|
| 10 |
from convert import ball_kind, ball_kind_to_color, get_text_color_from_color, team_names_short_to_color, get_text_color_from_team
|
| 11 |
from plotting import stat_cmap
|
| 12 |
|
| 13 |
-
STATS = ['Count', 'Usage', 'Avg Velo', 'Max Velo', 'Swing%', 'Z-Swing%', 'Chase%', 'Contact%', 'Z-Contact%', 'O-Contact%', 'SwStr%', 'Whiff%', 'CSW%', 'Strike%', 'Ball%', 'F-Str%', 'PAR%', 'GB%', 'FB%', 'LD%', 'Zone%', 'Arm%', 'Glove%', 'High%', 'Low%', 'MM%', 'Behind%']
|
| 14 |
-
PCT_STATS = ['Usage', 'Swing%', 'Z-Swing%', 'Chase%', 'Contact%', 'Z-Contact%', 'O-Contact%', 'SwStr%', 'Whiff%', 'CSW%', 'Strike%', 'Ball%', 'F-Str%', 'PAR%', 'GB%', 'FB%', 'LD%', 'Zone%', 'Arm%', 'Glove%', 'High%', 'Low%', 'MM%', 'Behind%']
|
| 15 |
-
STATS_WITH_PCTLS = ['Swing%', 'Z-Swing%', 'Chase%', 'Contact%', 'Z-Contact%', 'O-Contact%', 'SwStr%', 'Whiff%', 'CSW%', 'Strike%', 'Ball%', 'F-Str%', 'PAR%', 'GB%', 'FB%', 'LD%', 'Zone%']
|
| 16 |
COLUMNS = ['Pitcher', 'Team', 'Throws', 'Pitch', 'Pitch (General)'] + STATS
|
| 17 |
|
| 18 |
PITCH_TYPES = [pitch_type for pitch_type in ball_kind.values() if pitch_type != '-']
|
|
|
|
| 10 |
from convert import ball_kind, ball_kind_to_color, get_text_color_from_color, team_names_short_to_color, get_text_color_from_team
|
| 11 |
from plotting import stat_cmap
|
| 12 |
|
| 13 |
+
STATS = ['Count', 'Usage', 'Avg Velo', 'Max Velo', 'Swing%', 'Z-Swing%', 'Chase%', 'Contact%', 'Z-Contact%', 'O-Contact%', 'SwStr%', 'Whiff%', 'CSW%', 'Strike%', 'Ball%', 'F-Str%', 'PAR%', 'GB%', 'FB%', 'LD%', 'OFFB%', 'IFFB%', 'AIR%', 'Zone%', 'Arm%', 'Glove%', 'High%', 'Low%', 'MM%', 'Behind%']
|
| 14 |
+
PCT_STATS = ['Usage', 'Swing%', 'Z-Swing%', 'Chase%', 'Contact%', 'Z-Contact%', 'O-Contact%', 'SwStr%', 'Whiff%', 'CSW%', 'Strike%', 'Ball%', 'F-Str%', 'PAR%', 'GB%', 'FB%', 'LD%', 'OFFB%', 'IFFB%', 'AIR%', 'Zone%', 'Arm%', 'Glove%', 'High%', 'Low%', 'MM%', 'Behind%']
|
| 15 |
+
STATS_WITH_PCTLS = ['Swing%', 'Z-Swing%', 'Chase%', 'Contact%', 'Z-Contact%', 'O-Contact%', 'SwStr%', 'Whiff%', 'CSW%', 'Strike%', 'Ball%', 'F-Str%', 'PAR%', 'GB%', 'FB%', 'LD%', 'OFFB%', 'IFFB%', 'AIR%', 'Zone%']
|
| 16 |
COLUMNS = ['Pitcher', 'Team', 'Throws', 'Pitch', 'Pitch (General)'] + STATS
|
| 17 |
|
| 18 |
PITCH_TYPES = [pitch_type for pitch_type in ball_kind.values() if pitch_type != '-']
|
player_team_leaderboard.py
CHANGED
|
@@ -57,15 +57,15 @@ def create_player_team_leaderboard_app(player_team_type):
|
|
| 57 |
|
| 58 |
# stats
|
| 59 |
if pitching:
|
| 60 |
-
pct_stats = ['K%', 'BB%', 'Swing%', 'Z-Swing%', 'Chase%', 'Contact%', 'Z-Contact%', 'O-Contact%', 'SwStr%', 'Whiff%', 'CSW%', 'Strike%', 'Ball%', 'F-Str%', 'PAR%', 'GB%', 'FB%', 'LD%', 'Zone%', 'Arm%', 'Glove%', 'High%', 'Low%', 'MM%', 'Behind%']
|
| 61 |
-
stats_with_pctls = ['FB Velo', 'K%', 'BB%', 'Swing%', 'Z-Swing%', 'Chase%', 'Contact%', 'Z-Contact%', 'O-Contact%', 'SwStr%', 'Whiff%', 'CSW%', 'Strike%', 'F-Str%', 'PAR%', 'Ball%', 'GB%', 'FB%', 'LD%', 'Zone%', 'Behind%']
|
| 62 |
-
cols = ['Pitcher', 'Team', 'Throws', 'IP', 'TBF', 'FB Velo', 'K%', 'BB%', 'Swing%', 'Z-Swing%', 'Chase%', 'Contact%', 'Z-Contact%', 'O-Contact%', 'SwStr%', 'Whiff%', 'CSW%', 'Strike%', 'Ball%', 'F-Str%', 'PAR%', 'GB%', 'FB%', 'LD%', 'Zone%', 'Arm%', 'Glove%', 'High%', 'Low%', 'MM%', 'Behind%']
|
| 63 |
if team:
|
| 64 |
cols = [col for col in cols if col not in ('Pitcher', 'Throws')]
|
| 65 |
else:
|
| 66 |
-
pct_stats = ['K%', 'BB%', 'Swing%', 'Z-Swing%', 'Chase%', 'Contact%', 'Z-Contact%', 'O-Contact%', 'SwStr%', 'Whiff%', 'CSW%', 'GB%', 'FB%', 'LD%', 'Zone%', 'Arm%', 'Glove%', 'High%', 'Low%', 'MM%']
|
| 67 |
-
stats_with_pctls = ['K%', 'BB%', 'Swing%', 'Z-Swing%', 'Chase%', 'Contact%', 'Z-Contact%', 'O-Contact%', 'SwStr%', 'Whiff%', 'CSW%', 'GB%', 'FB%', 'LD%', 'Zone%'] # , 'OBP']
|
| 68 |
-
cols = ['Batter', 'Team', 'Bats', 'PA', 'K%', 'BB%', 'Swing%', 'Z-Swing%', 'Chase%', 'Contact%', 'Z-Contact%', 'O-Contact%', 'SwStr%', 'Whiff%', 'CSW%', 'GB%', 'FB%', 'LD%']#, 'AB', 'H', 'BB', 'HBP', 'SF', 'OBP']
|
| 69 |
if team:
|
| 70 |
cols = [col for col in cols if col not in ('Batter', 'Bats')]
|
| 71 |
|
|
|
|
| 57 |
|
| 58 |
# stats
|
| 59 |
if pitching:
|
| 60 |
+
pct_stats = ['K%', 'BB%', 'Swing%', 'Z-Swing%', 'Chase%', 'Contact%', 'Z-Contact%', 'O-Contact%', 'SwStr%', 'Whiff%', 'CSW%', 'Strike%', 'Ball%', 'F-Str%', 'PAR%', 'GB%', 'FB%', 'LD%', 'OFFB%', 'IFFB%', 'AIR%', 'Zone%', 'Arm%', 'Glove%', 'High%', 'Low%', 'MM%', 'Behind%']
|
| 61 |
+
stats_with_pctls = ['FB Velo', 'K%', 'BB%', 'Swing%', 'Z-Swing%', 'Chase%', 'Contact%', 'Z-Contact%', 'O-Contact%', 'SwStr%', 'Whiff%', 'CSW%', 'Strike%', 'F-Str%', 'PAR%', 'Ball%', 'GB%', 'FB%', 'LD%', 'OFFB%', 'IFFB%', 'AIR%', 'Zone%', 'Behind%']
|
| 62 |
+
cols = ['Pitcher', 'Team', 'Throws', 'IP', 'TBF', 'FB Velo', 'K%', 'BB%', 'Swing%', 'Z-Swing%', 'Chase%', 'Contact%', 'Z-Contact%', 'O-Contact%', 'SwStr%', 'Whiff%', 'CSW%', 'Strike%', 'Ball%', 'F-Str%', 'PAR%', 'GB%', 'FB%', 'LD%', 'OFFB%', 'IFFB%', 'AIR%', 'Zone%', 'Arm%', 'Glove%', 'High%', 'Low%', 'MM%', 'Behind%']
|
| 63 |
if team:
|
| 64 |
cols = [col for col in cols if col not in ('Pitcher', 'Throws')]
|
| 65 |
else:
|
| 66 |
+
pct_stats = ['K%', 'BB%', 'Swing%', 'Z-Swing%', 'Chase%', 'Contact%', 'Z-Contact%', 'O-Contact%', 'SwStr%', 'Whiff%', 'CSW%', 'GB%', 'FB%', 'LD%', 'OFFB%', 'IFFB%', 'AIR%', 'Zone%', 'Arm%', 'Glove%', 'High%', 'Low%', 'MM%']
|
| 67 |
+
stats_with_pctls = ['K%', 'BB%', 'Swing%', 'Z-Swing%', 'Chase%', 'Contact%', 'Z-Contact%', 'O-Contact%', 'SwStr%', 'Whiff%', 'CSW%', 'GB%', 'FB%', 'LD%', 'OFFB%', 'IFFB%', 'AIR%', 'Zone%'] # , 'OBP']
|
| 68 |
+
cols = ['Batter', 'Team', 'Bats', 'PA', 'K%', 'BB%', 'Swing%', 'Z-Swing%', 'Chase%', 'Contact%', 'Z-Contact%', 'O-Contact%', 'SwStr%', 'Whiff%', 'CSW%', 'GB%', 'FB%', 'LD%', 'OFFB%', 'IFFB%', 'AIR%']#, 'AB', 'H', 'BB', 'HBP', 'SF', 'OBP']
|
| 69 |
if team:
|
| 70 |
cols = [col for col in cols if col not in ('Batter', 'Bats')]
|
| 71 |
|
stats.py
CHANGED
|
@@ -170,12 +170,15 @@ def compute_pitch_stats(data, player_type, pitch_class_type, min_pitches=1, pitc
|
|
| 170 |
.with_columns(
|
| 171 |
(pl.col('G') + pl.col('B')).alias('GB%'),
|
| 172 |
(pl.col('F') + pl.col('P')).alias('FB%'),
|
| 173 |
-
pl.col('L').alias('LD%')
|
|
|
|
|
|
|
|
|
|
| 174 |
)
|
| 175 |
.drop('G', 'F', 'B', 'P', 'L', 'null')
|
| 176 |
.with_columns(
|
| 177 |
-
(pl.when(pl.col('qualified')).then(pl.col(stat)).rank(descending=((stat in ['FB%', 'LD%', 'Ball%', 'Behind%'] or 'Contact%' in stat)))/pl.when(pl.col('qualified')).then(pl.col(stat)).count()).alias(f'{stat}_pctl')
|
| 178 |
-
for stat in ['Avg KPH', 'Max KPH', 'Avg MPH', 'Max MPH', 'Swing%', 'Z-Swing%', 'Chase%', 'Contact%', 'Z-Contact%', 'O-Contact%', 'SwStr%', 'Whiff%', 'CSW%', 'Strike%', 'Ball%', 'F-Str%', 'PAR%', 'GB%', 'FB%', 'LD%', 'Zone%', 'Behind%']
|
| 179 |
)
|
| 180 |
.rename({pitch_col: 'ballKind_code', pitch_name_col: 'ballKind'} if pitch_class_type == 'general' else {})
|
| 181 |
.sort(id_cols[0], 'count', descending=[False, True])
|
|
@@ -236,9 +239,9 @@ def compute_player_stats(data, player_type, qual='qualified', pitcher_lr='both',
|
|
| 236 |
|
| 237 |
# percentile ascending/descending
|
| 238 |
if pitching:
|
| 239 |
-
stat_descending_pctl = lambda stat: stat in ['BB%', 'Ball%', 'FB%', 'LD%', 'Z-Swing%', 'Behind%', 'OBP'] or 'Contact%' in stat
|
| 240 |
else:
|
| 241 |
-
stat_descending_pctl = lambda stat: not (stat in ['BB%', 'Ball%', 'FB%', 'LD%', 'Swing%', 'Z-Swing%', 'Behind%', 'OBP'] or 'Contact%' in stat)
|
| 242 |
|
| 243 |
# col names
|
| 244 |
match player_type:
|
|
@@ -312,11 +315,14 @@ def compute_player_stats(data, player_type, qual='qualified', pitcher_lr='both',
|
|
| 312 |
(pl.col('G') + pl.col('B')).alias('GB%'),
|
| 313 |
(pl.col('F') + pl.col('P')).alias('FB%'),
|
| 314 |
pl.col('L').alias('LD%'),
|
|
|
|
|
|
|
|
|
|
| 315 |
)
|
| 316 |
.drop('G', 'F', 'B', 'P', 'L')
|
| 317 |
.with_columns(
|
| 318 |
(pl.when(pl.col('qualified')).then(pl.col(stat)).rank(descending=stat_descending_pctl(stat))/pl.when(pl.col('qualified')).then(pl.col(stat)).count()).alias(f'{stat}_pctl')
|
| 319 |
-
for stat in ['FB Velo', 'K%', 'BB%', 'Swing%', 'Z-Swing%', 'Chase%', 'Contact%', 'Z-Contact%', 'O-Contact%', 'SwStr%', 'Whiff%', 'CSW%', 'Strike%', 'Ball%', 'F-Str%', 'PAR%', 'GB%', 'FB%', 'LD%', 'Zone%', 'Behind%', 'OBP']
|
| 320 |
)
|
| 321 |
.sort(qual_col, descending=True)
|
| 322 |
)
|
|
|
|
| 170 |
.with_columns(
|
| 171 |
(pl.col('G') + pl.col('B')).alias('GB%'),
|
| 172 |
(pl.col('F') + pl.col('P')).alias('FB%'),
|
| 173 |
+
pl.col('L').alias('LD%'),
|
| 174 |
+
pl.col('P').alias('IFFB%'),
|
| 175 |
+
pl.col('F').alias('OFFB%'),
|
| 176 |
+
(pl.col('F') + pl.col('P') + pl.col('L')).alias('AIR%')
|
| 177 |
)
|
| 178 |
.drop('G', 'F', 'B', 'P', 'L', 'null')
|
| 179 |
.with_columns(
|
| 180 |
+
(pl.when(pl.col('qualified')).then(pl.col(stat)).rank(descending=((stat in ['FB%', 'LD%', 'OFFB%', 'AIR%', 'Ball%', 'Behind%'] or 'Contact%' in stat)))/pl.when(pl.col('qualified')).then(pl.col(stat)).count()).alias(f'{stat}_pctl')
|
| 181 |
+
for stat in ['Avg KPH', 'Max KPH', 'Avg MPH', 'Max MPH', 'Swing%', 'Z-Swing%', 'Chase%', 'Contact%', 'Z-Contact%', 'O-Contact%', 'SwStr%', 'Whiff%', 'CSW%', 'Strike%', 'Ball%', 'F-Str%', 'PAR%', 'GB%', 'FB%', 'LD%', 'OFFB%', 'IFFB%', 'AIR%', 'Zone%', 'Behind%']
|
| 182 |
)
|
| 183 |
.rename({pitch_col: 'ballKind_code', pitch_name_col: 'ballKind'} if pitch_class_type == 'general' else {})
|
| 184 |
.sort(id_cols[0], 'count', descending=[False, True])
|
|
|
|
| 239 |
|
| 240 |
# percentile ascending/descending
|
| 241 |
if pitching:
|
| 242 |
+
stat_descending_pctl = lambda stat: stat in ['BB%', 'Ball%', 'FB%', 'LD%', 'OFFB%', 'AIR%', 'Z-Swing%', 'Behind%', 'OBP'] or 'Contact%' in stat
|
| 243 |
else:
|
| 244 |
+
stat_descending_pctl = lambda stat: not (stat in ['BB%', 'Ball%', 'FB%', 'LD%', 'OFFB%', 'AIR%' 'Swing%', 'Z-Swing%', 'Behind%', 'OBP'] or 'Contact%' in stat)
|
| 245 |
|
| 246 |
# col names
|
| 247 |
match player_type:
|
|
|
|
| 315 |
(pl.col('G') + pl.col('B')).alias('GB%'),
|
| 316 |
(pl.col('F') + pl.col('P')).alias('FB%'),
|
| 317 |
pl.col('L').alias('LD%'),
|
| 318 |
+
pl.col('P').alias('IFFB%'),
|
| 319 |
+
pl.col('F').alias('OFFB%'),
|
| 320 |
+
(pl.col('F') + pl.col('P') + pl.col('L')).alias('AIR%')
|
| 321 |
)
|
| 322 |
.drop('G', 'F', 'B', 'P', 'L')
|
| 323 |
.with_columns(
|
| 324 |
(pl.when(pl.col('qualified')).then(pl.col(stat)).rank(descending=stat_descending_pctl(stat))/pl.when(pl.col('qualified')).then(pl.col(stat)).count()).alias(f'{stat}_pctl')
|
| 325 |
+
for stat in ['FB Velo', 'K%', 'BB%', 'Swing%', 'Z-Swing%', 'Chase%', 'Contact%', 'Z-Contact%', 'O-Contact%', 'SwStr%', 'Whiff%', 'CSW%', 'Strike%', 'Ball%', 'F-Str%', 'PAR%', 'GB%', 'FB%', 'LD%', 'OFFB%', 'IFFB%', 'AIR%', 'Zone%', 'Behind%', 'OBP']
|
| 326 |
)
|
| 327 |
.sort(qual_col, descending=True)
|
| 328 |
)
|