Spaces:
Running
Running
Commit
·
0e26e9f
1
Parent(s):
6be2b70
Add Ball%
Browse files- pitch_leaderboard.py +3 -3
- player_team_leaderboard.py +3 -3
- stats.py +8 -5
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%', 'GB%', 'FB%', 'LD%', 'Zone%', 'Arm%', 'Glove%', 'High%', 'Low%', 'MM%']
|
| 14 |
-
PCT_STATS = ['Usage', 'Swing%', 'Z-Swing%', 'Chase%', 'Contact%', 'Z-Contact%', 'O-Contact%', 'SwStr%', 'Whiff%', 'CSW%', 'GB%', 'FB%', 'LD%', 'Zone%', 'Arm%', 'Glove%', 'High%', 'Low%', 'MM%']
|
| 15 |
-
STATS_WITH_PCTLS = ['Swing%', 'Z-Swing%', 'Chase%', 'Contact%', 'Z-Contact%', 'O-Contact%', 'SwStr%', 'Whiff%', 'CSW%', '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%', 'Ball%', 'GB%', 'FB%', 'LD%', 'Zone%', 'Arm%', 'Glove%', 'High%', 'Low%', 'MM%']
|
| 14 |
+
PCT_STATS = ['Usage', 'Swing%', 'Z-Swing%', 'Chase%', 'Contact%', 'Z-Contact%', 'O-Contact%', 'SwStr%', 'Whiff%', 'CSW%', 'Ball%', 'GB%', 'FB%', 'LD%', 'Zone%', 'Arm%', 'Glove%', 'High%', 'Low%', 'MM%']
|
| 15 |
+
STATS_WITH_PCTLS = ['Swing%', 'Z-Swing%', 'Chase%', 'Contact%', 'Z-Contact%', 'O-Contact%', 'SwStr%', 'Whiff%', 'CSW%', 'Ball%', '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 != '-']
|
player_team_leaderboard.py
CHANGED
|
@@ -57,9 +57,9 @@ 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%', 'GB%', 'FB%', 'LD%', 'Zone%', 'Arm%', 'Glove%', 'High%', 'Low%', 'MM%']
|
| 61 |
-
stats_with_pctls = ['FB Velo', 'K%', 'BB%', 'Swing%', 'Z-Swing%', 'Chase%', 'Contact%', 'Z-Contact%', 'O-Contact%', 'SwStr%', 'Whiff%', 'CSW%', 'GB%', 'FB%', 'LD%', 'Zone%']
|
| 62 |
-
cols = ['Pitcher', 'Team', 'Throws', 'IP', 'TBF', 'FB Velo', 'K%', 'BB%', 'Swing%', 'Z-Swing%', 'Chase%', 'Contact%', 'Z-Contact%', 'O-Contact%', 'SwStr%', 'Whiff%', 'CSW%', 'GB%', 'FB%', 'LD%', 'Zone%', 'Arm%', 'Glove%', 'High%', 'Low%', 'MM%']
|
| 63 |
if team:
|
| 64 |
cols = [col for col in cols if col not in ('Pitcher', 'Throws')]
|
| 65 |
else:
|
|
|
|
| 57 |
|
| 58 |
# stats
|
| 59 |
if pitching:
|
| 60 |
+
pct_stats = ['K%', 'BB%', 'Swing%', 'Z-Swing%', 'Chase%', 'Contact%', 'Z-Contact%', 'O-Contact%', 'SwStr%', 'Whiff%', 'CSW%', 'Ball%', 'GB%', 'FB%', 'LD%', 'Zone%', 'Arm%', 'Glove%', 'High%', 'Low%', 'MM%']
|
| 61 |
+
stats_with_pctls = ['FB Velo', 'K%', 'BB%', 'Swing%', 'Z-Swing%', 'Chase%', 'Contact%', 'Z-Contact%', 'O-Contact%', 'SwStr%', 'Whiff%', 'CSW%', 'Ball%', 'GB%', 'FB%', 'LD%', 'Zone%']
|
| 62 |
+
cols = ['Pitcher', 'Team', 'Throws', 'IP', 'TBF', 'FB Velo', 'K%', 'BB%', 'Swing%', 'Z-Swing%', 'Chase%', 'Contact%', 'Z-Contact%', 'O-Contact%', 'SwStr%', 'Whiff%', 'CSW%', 'Ball%', 'GB%', 'FB%', 'LD%', 'Zone%', 'Arm%', 'Glove%', 'High%', 'Low%', 'MM%']
|
| 63 |
if team:
|
| 64 |
cols = [col for col in cols if col not in ('Pitcher', 'Throws')]
|
| 65 |
else:
|
stats.py
CHANGED
|
@@ -17,6 +17,7 @@ o_con = ((~pl.col('zone') & pl.col('swing') & ~pl.col('whiff')).sum()/(~pl.col('
|
|
| 17 |
whiff = (pl.col('whiff').sum() / pl.col('swing').sum()).alias('Whiff%')
|
| 18 |
swstr = (pl.col('whiff').sum() / pl.col('pitch').sum()).alias('SwStr%')
|
| 19 |
csw = (pl.col('csw').sum() / pl.col('pitch').sum()).alias('CSW%')
|
|
|
|
| 20 |
zone = (pl.col('zone').sum() / pl.col('pitch').sum()).alias('Zone%')
|
| 21 |
glove = (pl.when(pl.col('pitLR') == 'r').then(pl.col('x') < 0).otherwise(pl.col('x') > 0)).mean().alias('Glove%')
|
| 22 |
arm = (pl.when(pl.col('pitLR') == 'r').then(pl.col('x') >= 0).otherwise(pl.col('x') <= 0)).mean().alias('Arm%')
|
|
@@ -138,6 +139,7 @@ def compute_pitch_stats(data, player_type, pitch_class_type, min_pitches=1, pitc
|
|
| 138 |
whiff,
|
| 139 |
swstr,
|
| 140 |
csw,
|
|
|
|
| 141 |
zone,
|
| 142 |
glove,
|
| 143 |
arm,
|
|
@@ -160,8 +162,8 @@ def compute_pitch_stats(data, player_type, pitch_class_type, min_pitches=1, pitc
|
|
| 160 |
)
|
| 161 |
.drop('G', 'F', 'B', 'P', 'L', 'null')
|
| 162 |
.with_columns(
|
| 163 |
-
(pl.when(pl.col('qualified')).then(pl.col(stat)).rank(descending=((stat in ['FB%', 'LD%'] or 'Contact%' in stat)))/pl.when(pl.col('qualified')).then(pl.col(stat)).count()).alias(f'{stat}_pctl')
|
| 164 |
-
for stat in ['Avg KPH', 'Max KPH', 'Avg MPH', 'Max MPH', 'Swing%', 'Z-Swing%', 'Chase%', 'Contact%', 'Z-Contact%', 'O-Contact%', 'SwStr%', 'Whiff%', 'CSW%', 'GB%', 'FB%', 'LD%', 'Zone%']
|
| 165 |
)
|
| 166 |
.rename({pitch_col: 'ballKind_code', pitch_name_col: 'ballKind'} if pitch_class_type == 'general' else {})
|
| 167 |
.sort(id_cols[0], 'count', descending=[False, True])
|
|
@@ -222,9 +224,9 @@ def compute_player_stats(data, player_type, qual='qualified', pitcher_lr='both',
|
|
| 222 |
|
| 223 |
# percentile ascending/descending
|
| 224 |
if pitching:
|
| 225 |
-
stat_descending_pctl = lambda stat: stat in ['BB%', 'FB%', 'LD%', 'Z-Swing%', 'OBP'] or 'Contact%' in stat
|
| 226 |
else:
|
| 227 |
-
stat_descending_pctl = lambda stat: not (stat in ['BB%', 'FB%', 'LD%', 'Swing%', 'Z-Swing%', 'OBP'] or 'Contact%' in stat)
|
| 228 |
|
| 229 |
# col names
|
| 230 |
match player_type:
|
|
@@ -271,6 +273,7 @@ def compute_player_stats(data, player_type, qual='qualified', pitcher_lr='both',
|
|
| 271 |
whiff,
|
| 272 |
swstr,
|
| 273 |
csw,
|
|
|
|
| 274 |
zone,
|
| 275 |
glove,
|
| 276 |
arm,
|
|
@@ -297,7 +300,7 @@ def compute_player_stats(data, player_type, qual='qualified', pitcher_lr='both',
|
|
| 297 |
.drop('G', 'F', 'B', 'P', 'L')
|
| 298 |
.with_columns(
|
| 299 |
(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')
|
| 300 |
-
for stat in ['FB Velo', 'K%', 'BB%', 'Swing%', 'Z-Swing%', 'Chase%', 'Contact%', 'Z-Contact%', 'O-Contact%', 'SwStr%', 'Whiff%', 'CSW%', 'GB%', 'FB%', 'LD%', 'Zone%', 'OBP']
|
| 301 |
)
|
| 302 |
.sort(qual_col, descending=True)
|
| 303 |
)
|
|
|
|
| 17 |
whiff = (pl.col('whiff').sum() / pl.col('swing').sum()).alias('Whiff%')
|
| 18 |
swstr = (pl.col('whiff').sum() / pl.col('pitch').sum()).alias('SwStr%')
|
| 19 |
csw = (pl.col('csw').sum() / pl.col('pitch').sum()).alias('CSW%')
|
| 20 |
+
ball = ((pl.col('presult') == 'Ball').sum() / pl.col('pitch').sum()).alias('Ball%')
|
| 21 |
zone = (pl.col('zone').sum() / pl.col('pitch').sum()).alias('Zone%')
|
| 22 |
glove = (pl.when(pl.col('pitLR') == 'r').then(pl.col('x') < 0).otherwise(pl.col('x') > 0)).mean().alias('Glove%')
|
| 23 |
arm = (pl.when(pl.col('pitLR') == 'r').then(pl.col('x') >= 0).otherwise(pl.col('x') <= 0)).mean().alias('Arm%')
|
|
|
|
| 139 |
whiff,
|
| 140 |
swstr,
|
| 141 |
csw,
|
| 142 |
+
ball,
|
| 143 |
zone,
|
| 144 |
glove,
|
| 145 |
arm,
|
|
|
|
| 162 |
)
|
| 163 |
.drop('G', 'F', 'B', 'P', 'L', 'null')
|
| 164 |
.with_columns(
|
| 165 |
+
(pl.when(pl.col('qualified')).then(pl.col(stat)).rank(descending=((stat in ['FB%', 'LD%', 'Ball%'] or 'Contact%' in stat)))/pl.when(pl.col('qualified')).then(pl.col(stat)).count()).alias(f'{stat}_pctl')
|
| 166 |
+
for stat in ['Avg KPH', 'Max KPH', 'Avg MPH', 'Max MPH', 'Swing%', 'Z-Swing%', 'Chase%', 'Contact%', 'Z-Contact%', 'O-Contact%', 'SwStr%', 'Whiff%', 'CSW%', 'Ball%', 'GB%', 'FB%', 'LD%', 'Zone%']
|
| 167 |
)
|
| 168 |
.rename({pitch_col: 'ballKind_code', pitch_name_col: 'ballKind'} if pitch_class_type == 'general' else {})
|
| 169 |
.sort(id_cols[0], 'count', descending=[False, True])
|
|
|
|
| 224 |
|
| 225 |
# percentile ascending/descending
|
| 226 |
if pitching:
|
| 227 |
+
stat_descending_pctl = lambda stat: stat in ['BB%', 'Ball%', 'FB%', 'LD%', 'Z-Swing%', 'OBP'] or 'Contact%' in stat
|
| 228 |
else:
|
| 229 |
+
stat_descending_pctl = lambda stat: not (stat in ['BB%', 'Ball%', 'FB%', 'LD%', 'Swing%', 'Z-Swing%', 'OBP'] or 'Contact%' in stat)
|
| 230 |
|
| 231 |
# col names
|
| 232 |
match player_type:
|
|
|
|
| 273 |
whiff,
|
| 274 |
swstr,
|
| 275 |
csw,
|
| 276 |
+
ball,
|
| 277 |
zone,
|
| 278 |
glove,
|
| 279 |
arm,
|
|
|
|
| 300 |
.drop('G', 'F', 'B', 'P', 'L')
|
| 301 |
.with_columns(
|
| 302 |
(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')
|
| 303 |
+
for stat in ['FB Velo', 'K%', 'BB%', 'Swing%', 'Z-Swing%', 'Chase%', 'Contact%', 'Z-Contact%', 'O-Contact%', 'SwStr%', 'Whiff%', 'CSW%', 'Ball%', 'GB%', 'FB%', 'LD%', 'Zone%', 'OBP']
|
| 304 |
)
|
| 305 |
.sort(qual_col, descending=True)
|
| 306 |
)
|