Spaces:
Sleeping
Sleeping
Rename models/pitch_model.txt to models/pitch_model.py
Browse files- models/pitch_model.py +59 -0
- models/pitch_model.txt +0 -0
models/pitch_model.py
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import annotations
|
| 2 |
+
|
| 3 |
+
from typing import Any
|
| 4 |
+
|
| 5 |
+
import numpy as np
|
| 6 |
+
import pandas as pd
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
def predict_pitch_outcome(
|
| 10 |
+
release_speed: float,
|
| 11 |
+
release_spin_rate: float,
|
| 12 |
+
pfx_x: float,
|
| 13 |
+
pfx_z: float,
|
| 14 |
+
batter_ev90: float,
|
| 15 |
+
batter_xwoba: float,
|
| 16 |
+
) -> dict[str, float]:
|
| 17 |
+
"""
|
| 18 |
+
Research baseline model.
|
| 19 |
+
This is deterministic and explainable, and can later be swapped
|
| 20 |
+
with a trained neural net without changing the app interface.
|
| 21 |
+
"""
|
| 22 |
+
speed = 0.45 + max(0.0, (release_speed - 90.0)) * 0.012
|
| 23 |
+
spin = 0.18 + max(0.0, (release_spin_rate - 2100.0)) * 0.00008
|
| 24 |
+
movement = 0.10 + (abs(pfx_x) + abs(pfx_z)) * 0.01
|
| 25 |
+
hitter_damage = max(0.0, ((batter_ev90 - 92.0) * 0.01) + ((batter_xwoba - 0.320) * 0.8))
|
| 26 |
+
|
| 27 |
+
strike_prob = min(0.85, speed + (movement * 0.25))
|
| 28 |
+
whiff_prob = min(0.70, spin + (movement * 0.20) - (hitter_damage * 0.10))
|
| 29 |
+
damage_prob = min(0.75, 0.08 + hitter_damage - (speed * 0.10))
|
| 30 |
+
|
| 31 |
+
strike_prob = max(0.05, strike_prob)
|
| 32 |
+
whiff_prob = max(0.02, whiff_prob)
|
| 33 |
+
damage_prob = max(0.01, damage_prob)
|
| 34 |
+
|
| 35 |
+
ball_in_play_prob = max(0.01, 1.0 - whiff_prob - (strike_prob * 0.10))
|
| 36 |
+
|
| 37 |
+
return {
|
| 38 |
+
"strike_prob": float(min(1.0, strike_prob)),
|
| 39 |
+
"whiff_prob": float(min(1.0, whiff_prob)),
|
| 40 |
+
"damage_prob": float(min(1.0, damage_prob)),
|
| 41 |
+
"ball_in_play_prob": float(min(1.0, ball_in_play_prob)),
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
def pitcher_baseline_from_events(df: pd.DataFrame) -> dict[str, float]:
|
| 46 |
+
if df.empty:
|
| 47 |
+
return {
|
| 48 |
+
"release_speed": 94.0,
|
| 49 |
+
"release_spin_rate": 2250.0,
|
| 50 |
+
"pfx_x": 0.0,
|
| 51 |
+
"pfx_z": 12.0,
|
| 52 |
+
}
|
| 53 |
+
|
| 54 |
+
return {
|
| 55 |
+
"release_speed": float(pd.to_numeric(df.get("release_speed"), errors="coerce").mean()),
|
| 56 |
+
"release_spin_rate": float(pd.to_numeric(df.get("release_spin_rate"), errors="coerce").mean()),
|
| 57 |
+
"pfx_x": float(pd.to_numeric(df.get("pfx_x"), errors="coerce").mean()),
|
| 58 |
+
"pfx_z": float(pd.to_numeric(df.get("pfx_z"), errors="coerce").mean()),
|
| 59 |
+
}
|
models/pitch_model.txt
DELETED
|
File without changes
|