Spaces:
Sleeping
Sleeping
File size: 1,804 Bytes
6b0d9f1 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | from __future__ import annotations
import pandas as pd
def _safe_quantile(series: pd.Series, q: float) -> float:
valid = pd.to_numeric(series, errors="coerce").dropna()
if valid.empty:
return 0.0
return float(valid.quantile(q))
def batter_summary(df: pd.DataFrame) -> pd.DataFrame:
if df.empty or "player_name" not in df.columns:
return pd.DataFrame()
rows: list[dict] = []
for player_name, group in df.groupby("player_name"):
launch_speed = pd.to_numeric(group["launch_speed"], errors="coerce") if "launch_speed" in group.columns else pd.Series(dtype=float)
launch_angle = pd.to_numeric(group["launch_angle"], errors="coerce") if "launch_angle" in group.columns else pd.Series(dtype=float)
xwoba = pd.to_numeric(group["xwoba"], errors="coerce") if "xwoba" in group.columns else pd.Series(dtype=float)
hard_hit_rate = float((launch_speed >= 95).mean()) if len(launch_speed.dropna()) else 0.0
barrel_like_rate = float(((launch_speed >= 98) & (launch_angle.between(26, 30))).mean()) if len(launch_speed.dropna()) else 0.0
rows.append(
{
"player_name": player_name,
"events": int(len(group)),
"ev_avg": float(launch_speed.mean()) if len(launch_speed.dropna()) else 0.0,
"ev90": _safe_quantile(launch_speed, 0.90),
"la_avg": float(launch_angle.mean()) if len(launch_angle.dropna()) else 0.0,
"hard_hit_rate": hard_hit_rate,
"barrel_like_rate": barrel_like_rate,
"xwoba_avg": float(xwoba.mean()) if len(xwoba.dropna()) else 0.0,
}
)
out = pd.DataFrame(rows)
return out.sort_values(["ev90", "xwoba_avg"], ascending=False).reset_index(drop=True) |