Syntrex commited on
Commit
3abb40a
Β·
verified Β·
1 Parent(s): 4662137

Delete app.py

Browse files
Files changed (1) hide show
  1. app.py +0 -133
app.py DELETED
@@ -1,133 +0,0 @@
1
- import gradio as gr
2
- import pandas as pd
3
- import numpy as np
4
- import xgboost as xgb
5
- import plotly.graph_objects as go
6
- from scipy.stats import gaussian_kde
7
- from pybaseball import pitching_stats, batting_stats, cache
8
-
9
- cache.enable()
10
-
11
- class AdvancedProEngine:
12
- def __init__(self):
13
- # Data Pull
14
- p_raw = pitching_stats(2015, 2025, ind=1)
15
- h_raw = batting_stats(2015, 2025, ind=1)
16
-
17
- self.p_metrics = ["ERA", "SO", "WHIP", "Stuff+"]
18
- self.h_metrics = ["AVG", "HR", "OPS", "wRC+"]
19
- self.p_feats = ['Age', 'IP', 'FIP', 'SwStr%']
20
- self.h_feats = ['Age', 'PA', 'OBP', 'ISO']
21
-
22
- # Safe Data Cleaning
23
- self.p_db = p_raw[self.p_feats + self.p_metrics + ['Name', 'Season']].dropna()
24
- self.h_db = h_raw[self.h_feats + self.h_metrics + ['Name', 'Season']].dropna()
25
-
26
- self.models = {}
27
- self._train_models()
28
-
29
- def _train_models(self):
30
- # Training with raw numpy arrays to prevent DataFrame attribute errors
31
- for m in self.p_metrics:
32
- self.models[f"P_{m}"] = xgb.train({'objective': 'reg:squarederror'}, xgb.DMatrix(self.p_db[self.p_feats].values, label=self.p_db[m].values))
33
- for m in self.h_metrics:
34
- self.models[f"H_{m}"] = xgb.train({'objective': 'reg:squarederror'}, xgb.DMatrix(self.h_db[self.h_feats].values, label=self.h_db[m].values))
35
-
36
- def simulate_2026(self, name, role, metric, n_sims=2500):
37
- db = self.p_db if role == "Pitcher" else self.h_db
38
- feats = self.p_feats if role == "Pitcher" else self.h_feats
39
- player_latest = db[db['Name'] == name].sort_values('Season').iloc[-1:]
40
- if player_latest.empty: return None
41
-
42
- base_vals = player_latest[feats].values[0]
43
- base_vals[0] += 1 # 2026 Aging
44
-
45
- # Monte Carlo: Injecting 6% variance noise into physical traits
46
- noise = np.random.normal(1.0, 0.06, (n_sims, len(base_vals)))
47
- sim_inputs = base_vals * noise
48
- return self.models[f"{role[0]}_{metric}"].predict(xgb.DMatrix(sim_inputs))
49
-
50
- engine = AdvancedProEngine()
51
-
52
- def run_ui(role, name):
53
- if not name: return "", go.Figure()
54
-
55
- metrics = engine.p_metrics if role == "Pitcher" else engine.h_metrics
56
- primary_metric = metrics[0]
57
-
58
- # 1. KPI Scorecards
59
- kpi_html = "<div style='display: flex; flex-wrap: wrap; gap: 8px; justify-content: center;'>"
60
- for m in metrics:
61
- sims = engine.simulate_2026(name, role, m, n_sims=300)
62
- mu = np.mean(sims)
63
- val = f"{mu:.2f}" if mu < 10 else f"{int(mu)}"
64
- kpi_html += f"<div style='background:#fff; border:1px solid #eee; padding:12px; border-radius:10px; min-width:80px; text-align:center;'>"\
65
- f"<div style='font-size:0.7em; color:#777;'>{m}</div><div style='font-size:1.3em; color:#1A73E8; font-weight:bold;'>{val}</div></div>"
66
- kpi_html += "</div>"
67
-
68
- # 2. Monte Carlo Pulse with CONFIDENCE INTERVALS
69
- full_sims = engine.simulate_2026(name, role, primary_metric)
70
- low, med, high = np.percentile(full_sims, [5, 50, 95]) # The 90% Confidence Interval
71
-
72
- kde = gaussian_kde(full_sims)
73
- x = np.linspace(min(full_sims), max(full_sims), 250)
74
- y = kde(x)
75
-
76
- fig = go.Figure()
77
- # The Probability Mountain
78
- fig.add_trace(go.Scatter(x=x, y=y, fill='tozeroy', line_color='#1A73E8', fillcolor='rgba(26, 115, 232, 0.15)', name="Probability"))
79
-
80
- # The Confidence Interval (The Ribbon)
81
- fig.add_vrect(
82
- x0=low, x1=high,
83
- fillcolor="#1A73E8", opacity=0.15,
84
- layer="below", line_width=0,
85
- annotation_text=f"90% Zone: {low:.2f} - {high:.2f}",
86
- annotation_position="top left"
87
- )
88
-
89
- # The Midpoint Pill (Projected Value)
90
- fig.add_vline(x=med, line_dash="dash", line_color="#1A73E8", annotation_text="Projected")
91
-
92
- fig.update_layout(
93
- title=f"2026 {primary_metric} Confidence Pulse",
94
- paper_bgcolor='rgba(0,0,0,0)', plot_bgcolor='rgba(0,0,0,0)',
95
- height=300, margin=dict(l=10,r=10,t=50,b=10),
96
- xaxis=dict(showgrid=False, zeroline=False), yaxis=dict(visible=False)
97
- )
98
-
99
- return kpi_html, fig
100
-
101
- # --- UI with Algorithm Breakdown ---
102
- with gr.Blocks(theme=gr.themes.Soft(), css=".gradio-container {max-width: 550px !important;}") as demo:
103
- gr.Markdown("## πŸ’Ž 2026 Player Intelligence")
104
-
105
- with gr.Row():
106
- role_select = gr.Radio(["Pitcher", "Hitter"], value="Pitcher", label="Role")
107
- player_select = gr.Dropdown(choices=sorted(engine.p_db['Name'].unique().tolist()), label="Search Player", interactive=True)
108
-
109
- scorecards = gr.HTML()
110
- pulse_plot = gr.Plot()
111
-
112
- # Dynamic Updates
113
- role_select.change(lambda r: gr.update(choices=sorted(engine.p_db['Name'].unique().tolist() if r=="Pitcher" else engine.h_db['Name'].unique().tolist())), inputs=role_select, outputs=player_select)
114
- player_select.change(run_ui, inputs=[role_select, player_select], outputs=[scorecards, pulse_plot])
115
-
116
- # Algorithm Breakdown
117
- with gr.Accordion("πŸ“š ALGORITHM BREAKDOWN", open=False):
118
- gr.Markdown("""
119
- ### 🧠 1. The Brain: XGBoost
120
- We use an **Extreme Gradient Boosting** ensemble to model player performance.
121
- - **Math:** We minimize the Objective Function $$Obj(\\theta) = \\sum L(y_i, \\hat{y}_i) + \\sum \\Omega(f_k)$$
122
- - **Logic:** This handles the non-linear relationship between physical traits (like Velocity) and results (like Strikeouts).
123
- """)
124
-
125
- gr.Markdown("""
126
- ### 🎲 2. The Stress Test: Monte Carlo
127
- A single guess is risky. We run **2,500 parallel 2026 seasons** for every player.
128
- - **The Probability Pulse:** The mountain chart above shows the distribution of all outcomes.
129
- - **Confidence Intervals (The Ribbon):** We highlight the **5th to 95th percentile**. This defines the realistic 'Floor' and 'Ceiling' for 2026 based on historical volatility.
130
- """)
131
-
132
-
133
- demo.launch()