# Modeling approach

The app fits a single-metric **weighted quadratic aging curve** for each player.


# The model

For seasons indexed by Age, weighted by playing time:

    y = β₀ + β₁·Age + β₂·Age² + ε

Implementation: `statsmodels.api.WLS(y, X, weights=w).fit()`, with weights equal to PA (batters) or IP (pitchers). Seasons with more playing time pull the curve harder than partial seasons.


# Why weighted

A 90-PA September call-up and a 700-PA full season carry the same arithmetic information to ordinary least squares, but they're not equally informative about the player's true ability. Weighting by PA pushes the fit toward seasons that contain more signal.


# Peak age

When β₂ \< 0 the parabola opens downward and there's a real maximum. Setting the derivative to zero gives the peak age in closed form:

    Age* = -β₁ / (2·β₂)

That's the value the app marks with a dashed vertical line and labels *Peak: \##.#*.

When β₂ ≥ 0 the curve is flat or concave-up -- usually a sign of an unfinished or unusual career -- and the peak marker is suppressed.


# Confidence band

`get_prediction(X).summary_frame(alpha=0.05)` produces a 95% mean prediction interval at each input age. The shaded ribbon spans `mean_ci_lower` to `mean_ci_upper`. It widens at the edges of the career, where fewer seasons constrain the fit.


# Career summary

[summarize_career()](../reference/model.summarize_career.md#baseball_trajectory.model.summarize_career) returns:

| Field           | What it is                                                |
|-----------------|-----------------------------------------------------------|
| `weighted_mean` | Career rate stat, weighted by the same PA/IP as the fit.  |
| `best_season`   | The season with the highest `y_col` (Season, Age, value). |
| `peak_age`      | Closed-form peak from the fit (or `None` if non-concave). |
| `total_weight`  | Career total of PA or IP.                                 |

The one-row summary table in the UI is built from this dict.


# Assumptions and caveats

- **A single quadratic shape** describes the arc. Bimodal arcs (injury-recovery careers, mid-career position changes, knuckleballers) won't be modeled well.
- **Weights are exogenous.** A manager who benches a struggling player reduces their PA, which biases the fit slightly toward years the player was healthy and effective.
- **No era adjustments.** A 1908 OPS is treated the same as a 2019 OPS. See [Limitations](limitations.md) for more.
