KBKnowledge Base
Machine Learning · 2.3.11

Quantile Regression

The pinball loss, and how minimizing it recovers a conditional quantile.

On this page
In plain English — beginner to advanced

Beginner: ordinary least squares always answers the same question — "what is the average y I should expect for this x?" Sometimes that is not the question you actually have. A logistics company asking "how late could this delivery realistically run?" does not want the average delivery time — it wants a number that only 5% of deliveries exceed, so it can set an honest SLA. That is a question about a quantile of the delivery-time distribution — the 95th percentile, specifically — not about its mean. Quantile regression fits a model that directly targets whichever quantile you name, by swapping out squared error for a different loss function built exactly for that purpose.

Intermediate: recall from 2.1.2 (Statistical Decision Theory) that a loss function silently names the statistic your model is trying to learn — squared loss names the conditional mean, absolute loss names the conditional median. The pinball loss (also called the quantile loss), written ρ_τ for a chosen level τ ∈ (0, 1), generalizes that idea one step further: it is asymmetric, charging different penalties for under- and over-prediction depending on τ. Fit a linear model by minimizing the average pinball loss instead of squared error, and the function you get out is a genuine estimate of the conditional τ-quantile of y given x — not a mean shifted up or down by guesswork.

Advanced: the real payoff shows up under heteroscedasticity — when the spread of y | x itself changes with x, as it does for delivery times (short routes are predictable, long routes are erratic) or income (entry-level salaries cluster tightly, senior salaries scatter widely). In that regime, quantiles at different τ are not parallel shifts of the mean line — they fan out, and can even have different slopes. Fitting several quantile regressions at once, say τ = 0.1, 0.5, 0.9, recovers that fanning shape directly from data, which a single mean-plus-constant-margin model cannot do even in principle.

Worked intuition — the pinball loss, one residual at a time: pick τ = 0.9 and imagine two candidate predictions for a delivery that actually took 60 minutes. Predict q = 50 (an under-prediction, residual r = 10): the loss charged is τ·r = 0.9 × 10 = 9. Predict q = 70 instead (an over-prediction, residual r = -10): the loss is (τ-1)·r = -0.1 × -10 = 1. Same-sized miss, nine times the penalty for guessing too low versus too high — exactly the asymmetry a 90th-percentile estimate needs, since underestimating "how late it could get" is the expensive mistake there, and it is what pulls the fitted line up toward the top of the point cloud rather than through its middle.

Formula

The pinball (quantile) loss for a residual r, at quantile level τ ∈ (0, 1):

ρτ(r)=r(τ1[r<0])={τrr0(τ1)rr<0\rho_\tau(r) = r\big(\tau - \mathbb{1}[r < 0]\big) = \begin{cases} \tau r & r \ge 0 \\ (\tau - 1) r & r < 0 \end{cases}

Here r is the residual (actual minus predicted). For r ≥ 0 (under-prediction) the loss is τ·r; for r < 0 (over-prediction) it is (τ-1)·r, which is positive since τ-1 < 0 and r < 0. At τ = 0.5 both branches reduce to 0.5|r| — a fact this lesson's ExpertNote returns to. Fitting a linear model means choosing weights w to minimize the average of this loss over the training set:

w^τ=argminw1ni=1nρτ(yiwxi)\hat{w}_\tau = \arg\min_{w} \frac{1}{n}\sum_{i=1}^{n} \rho_\tau\big(y_i - w^\top x_i\big)
Derivation: minimizing expected pinball loss gives exactly the τ-quantile

This mirrors, step for step, the squared-loss derivation from 2.1.2 — fix a single scalar decision and differentiate the expected loss with respect to it. There, the unknown was a mean; here it is a quantile. Let Y be a random variable with density f and CDF F, and ask: which single number q minimizes the expected pinball loss E[ρ_τ(Y - q)]?

First split the expectation into the two cases the piecewise definition of ρ_τ demands — the region where Y ≥ q (so the residual Y - q ≥ 0, charged at rate τ) and the region where Y < q (residual negative, charged at rate 1-τ):

E[ρτ(Yq)]=τE[(Yq)1[Yq]]  +  (1τ)E[(qY)1[Y<q]]\mathbb{E}\big[\rho_\tau(Y-q)\big] = \tau\,\mathbb{E}\big[(Y-q)\mathbb{1}[Y\ge q]\big] \;+\; (1-\tau)\,\mathbb{E}\big[(q-Y)\mathbb{1}[Y<q]\big]

Write both expectations out as integrals against the density, splitting at q:

=τq(yq)f(y)dy  +  (1τ)q(qy)f(y)dy= \tau \int_{q}^{\infty} (y-q)\,f(y)\,dy \;+\; (1-\tau)\int_{-\infty}^{q} (q-y)\,f(y)\,dy

Now differentiate this whole expression with respect to q — the free variable we get to choose. Both integrals have q in a limit of integration and inside the integrand, so this needs two standard calculus facts about differentiating an integral whose bound moves (a direct application of the Leibniz rule, since the integrand itself vanishes at y = q in both cases, which cancels the usual boundary term and leaves only the derivative from the bound):

ddqq(yq)f(y)dy=(1F(q))ddqq(qy)f(y)dy=F(q)\frac{d}{dq}\int_{q}^{\infty}(y-q)f(y)\,dy = -\big(1-F(q)\big) \qquad \frac{d}{dq}\int_{-\infty}^{q}(q-y)f(y)\,dy = F(q)

The first says: as q creeps up, every remaining point in the upper tail loses exactly one unit of "distance to q" per unit q moves, and there are 1-F(q) probability mass worth of such points — hence the derivative is -(1-F(q)). The second is the mirror image on the lower tail: F(q) probability mass, each gaining one unit of "q minus y" per unit q moves, giving +F(q). Apply both facts to the two terms above:

ddqE[ρτ(Yq)]=τ((1F(q)))  +  (1τ)F(q)\frac{d}{dq}\,\mathbb{E}\big[\rho_\tau(Y-q)\big] = \tau\cdot\big(-(1-F(q))\big) \;+\; (1-\tau)\cdot F(q)

Expand and collect the F(q) terms:

=τ+τF(q)+F(q)τF(q)=F(q)τ= -\tau + \tau F(q) + F(q) - \tau F(q) = F(q) - \tau

Set this derivative to zero — the first-order condition for a minimum — and solve directly:

F(q)τ=0    F(q)=τF(q) - \tau = 0 \;\Longrightarrow\; F(q) = \tau

That is: the minimizer q* is exactly the value where the CDF equals τ — which is the definition of the τ-quantile of Y. It is a genuine minimum, not a saddle or a maximum, because a second differentiation gives f(q), the density at q, which is non-negative — the objective is convex (piecewise linear with a single non-negative kink), exactly the same qualitative shape absolute loss has at τ = 0.5. Conditioning every step on X = x throughout (replacing Y with Y | X=x, and F with the conditional CDF F(· | x)) upgrades this from "a fact about one unconditional distribution" to "the Bayes-optimal predictor under pinball loss is the conditional τ-quantile function", the exact regression-shaped version of the claim:

q(x)=argminqE[ρτ(Yq)X=x]=F1(τx)q^{*}(x) = \arg\min_{q} \mathbb{E}\big[\rho_\tau(Y-q) \mid X=x\big] = F^{-1}(\tau \mid x)

Where this is used: this is precisely why fitting a linear model by minimizing average pinball loss over a training set — exactly the objective in the Formula block above — produces a genuine estimate of the conditional τ-quantile function q_τ(x), not merely "the OLS line shifted up or down by some ad-hoc margin." The linear model is restricting the search to lines, but the loss it minimizes is still targeting the same population quantity this derivation just pinned down — which is exactly why quantile regression's fitted lines at different τ are allowed to have different slopes, not just different intercepts, whenever the true conditional quantiles genuinely fan out the way they do under heteroscedastic noise.

Watch a quantile-regression line sweep from the bottom of the cloud to the top

Synthetic data with noise that widens as x grows. The colored line is refit from scratch at every value of τ by minimizing average pinball loss over a slope/intercept grid — no library, just the objective from the Formula block, evaluated directly. Notice it tilts as τ changes, not just shifts, because the spread itself grows with x.

The pinball loss itself — an asymmetric V, not a symmetric one

ρτ(r) plotted against the residual r directly, the same function the Formula block defines and the sweep diagram above minimizes every frame. The two black dots mark the cost of a residual of −10 versus +10 at the current τ — drag τ and watch which side gets the steeper, more expensive branch.

Implemented three ways — fitting several quantiles by minimizing pinball loss

The from-scratch tabs minimize average pinball loss directly via subgradient descent — the loss is piecewise linear, so it has no single derivative at a zero residual, only a subgradient, which is all that descent needs on a convex objective. The library tab solves the equivalent linear program statsmodels sets up internally and should land on essentially the same three fitted lines, confirming the manual implementation is minimizing the correct objective rather than something that merely looks similar.

cpp
#include <cmath>
#include <cstdio>
#include <vector>
#include <random>

struct Point { double x, y; };

double pinballLoss(double residual, double tau) {
    return residual >= 0.0 ? tau * residual : (tau - 1.0) * residual;
}

double avgPinballLoss(const std::vector<Point>& pts, double slope, double intercept, double tau) {
    double total = 0.0;
    for (const auto& p : pts) total += pinballLoss(p.y - (intercept + slope * p.x), tau);
    return total / pts.size();
}

// Subgradient of the average pinball loss w.r.t. (slope, intercept). Piecewise
// linear, so there is no single derivative at a zero residual -- the
// subgradient below picks a consistent branch there, which is all
// subgradient descent requires to converge on a convex objective.
void subgradient(const std::vector<Point>& pts, double slope, double intercept,
                  double tau, double& gSlope, double& gIntercept) {
    gSlope = 0.0;
    gIntercept = 0.0;
    for (const auto& p : pts) {
        double r = p.y - (intercept + slope * p.x);
        double sign = (r > 0.0) ? -tau : (1.0 - tau);
        gIntercept += sign;
        gSlope += sign * p.x;
    }
    gSlope /= pts.size();
    gIntercept /= pts.size();
}

void fitQuantileLine(const std::vector<Point>& pts, double tau, int steps, double lr,
                      double& slope, double& intercept) {
    slope = 0.0;
    intercept = 0.0;
    for (const auto& p : pts) intercept += p.y;
    intercept /= pts.size();
    for (int i = 0; i < steps; ++i) {
        double gSlope, gIntercept;
        subgradient(pts, slope, intercept, tau, gSlope, gIntercept);
        slope -= lr * gSlope;
        intercept -= lr * gIntercept;
    }
}

int main() {
    std::mt19937 rng(7);
    std::uniform_real_distribution<double> unif(0.0, 100.0);
    std::normal_distribution<double> stdNormal(0.0, 1.0);

    const double trueIntercept = 15.0, trueSlope = 0.5;
    std::vector<Point> points;
    for (int i = 0; i < 200; ++i) {
        double x = unif(rng);
        double sigma = 3.0 + 0.25 * x;
        double y = trueIntercept + trueSlope * x + stdNormal(rng) * sigma;
        points.push_back({x, y});
    }

    for (double tau : {0.1, 0.5, 0.9}) {
        double slope, intercept;
        fitQuantileLine(points, tau, 3000, 0.01, slope, intercept);
        double loss = avgPinballLoss(points, slope, intercept, tau);
        std::printf("tau=%.1f  y_hat = %.2f + %.3f*x   avg pinball loss=%.3f\n",
                     tau, intercept, slope, loss);
    }
    return 0;
}
Real-world examples
  • Delivery-time / SLA estimation. "How late could this realistically run?" is a high-percentile question, not a mean question — a logistics platform fits τ = 0.95 quantile regression on historical delivery times against route features (distance, time of day, traffic) and quotes that fitted value as the SLA, rather than the mean delivery time plus an arbitrary buffer.
  • Financial risk — Value-at-Risk (VaR). VaR at the 5% level is, by definition, literally a specific quantile (the 5th percentile) of a portfolio's loss distribution — "there is only a 5% chance losses exceed this amount." Quantile regression lets that threshold depend on conditioning variables (market volatility, portfolio composition) rather than being estimated as one fixed unconditional number.
  • Demand forecasting for inventory planning. Fitting both a low quantile (say τ = 0.1) and a high one (τ = 0.9) for expected demand brackets the likely range a retailer should stock for — order to the low quantile and you risk stockouts; order to the high quantile and you risk excess inventory; the gap between the two is a data-driven, asymmetric-risk-aware safety margin.
  • Econometric wage and income studies. Quantile regression is the classical tool for asking whether an intervention (a minimum-wage law, a unionization rate, an education level) affects low earners, median earners, and high earners differently — a mean regression can only report one average effect, hiding the fact that the true effect might be large at the 10th percentile of wages and negligible at the 90th.
  • Growth charts in pediatrics. A child's height or weight percentile against age-matched peers is exactly a conditional-quantile estimate — the same "5th, 50th, 95th percentile" curves printed on a pediatric growth chart are the output of quantile regression run against age, fit once across a large reference population.
  • Server latency and SRE service-level objectives. Teams reporting p50/p95/ p99 latency are reading off empirical quantiles directly; conditioning those same percentiles on request features (payload size, region, endpoint) via quantile regression turns a single flat p99 number into a per-request expectation that tracks which requests are inherently slower, not just which requests happened to be slow in a fixed historical window.
Common mistakes
  • Quantile crossing. Fit several quantiles independently (say τ = 0.1 and τ = 0.9 as two separate optimization problems) and it is entirely possible, especially with limited data or a badly misspecified linear form, for the higher-τ line to dip below the lower-τ line at some x — logically impossible for true quantiles (the 90th percentile cannot be smaller than the 10th percentile of the same distribution) but perfectly possible for two independently-fit approximations of them. Standard fixes: fit all the desired quantiles jointly under an explicit non-crossing constraint, or the cruder but common post-hoc fix of simply sorting the fitted values at each x so they come out monotonic in τ by construction.
  • "τ = 0.5 is just robust OLS." Median regression and OLS often look similar on roughly symmetric noise, which invites treating τ = 0.5 quantile regression as merely "a robust version of least squares." They target genuinely different population quantities — the conditional median versus the conditional mean — that happen to coincide only when the conditional noise distribution is symmetric. Under skewed noise (income, wait times, insurance claims — all classically right-skewed) the median and mean can differ substantially, and conflating them is a real, not merely pedantic, mistake.
  • Expecting the same slope across τ. Forgetting that quantile regression's coefficients can, and under heteroscedasticity typically should, differ across τ — that variability is the entire reason to reach for quantile regression at all. If every quantile shared the same slope and only the intercept shifted, ordinary least squares plus a constant per-quantile offset would already do the job, and there would be no need for a separate technique.
Going deeper

Set τ = 0.5 in the pinball loss and check both branches: ρ_{0.5}(r) = 0.5·r for r ≥ 0, and ρ_{0.5}(r) = (0.5-1)·r = -0.5·r for r < 0. Since r ≥ 0 means r = |r|, and r < 0 means -r = |r|, both branches are exactly 0.5|r| — the pinball loss at τ = 0.5 is not merely "similar to" absolute loss, it is literally a constant multiple of it, ρ_{0.5}(r) = \tfrac12|r|. Multiplying a loss function by a positive constant never changes which value minimizes it, so minimizing ρ_{0.5} and minimizing |r| are the identical optimization problem. This is exactly the "median minimizes absolute loss" result from Statistical Decision Theory (2.1.2) — that lesson's Bayes-optimal predictor under absolute loss — reappearing here as the single special case τ = 0.5 of the general F(q) = τ result derived above (plug τ = 0.5 into that result and it reads F(q) = 0.5, precisely the definition of the median). Nothing new needed proving twice; the general derivation already contained it.

Check yourself
Two data scientists each fit a separate quantile regression to the same delivery-time data — one at τ=0.2, one at τ=0.8 — using different subsets of features. At a particular x, the τ=0.2 line predicts 42 minutes and the τ=0.8 line predicts 38 minutes. Is this a valid outcome, and if not, what is it called and how would you fix it?

Invalid -- this is quantile crossing. By definition the 80th percentile of a distribution can never be smaller than its 20th percentile at the same x, so a τ=0.8 prediction (38) coming in below the τ=0.2 prediction (42) is a contradiction, not just an unusual result. It typically arises from fitting the two quantiles as fully independent optimization problems (worse here, with different feature subsets, since the two models are not even constrained to agree on structure). Standard fixes: refit all desired quantiles jointly with an explicit non-crossing constraint baked into the optimization, or apply the simpler post-hoc fix of sorting the fitted quantile values at each x so they come out monotonically increasing in τ by construction.

Key takeaway

Quantile regression replaces squared loss with the asymmetric pinball loss ρ_τ, and minimizing its expectation over a single scalar choice provably lands exactly on the τ-quantile — F(q) = τ, derived the same way 2.1.2 derived the conditional mean, just with a different loss and a different first-order condition. Fitting a linear model against that loss turns this from a fact about one number into an estimate of an entire conditional quantile function, one that is free to tilt and fan out with x exactly where the data's spread genuinely changes — the single biggest thing a mean-only regression can never show you, and the case τ=0.5 folds the median-minimizes-absolute-loss result from 2.1.2 in as a special case rather than a coincidence.

Newsletter

Stay in the loop

Subscribe to get new docs, diagrams, and engineering write-ups by Dharaneesh Boobalan delivered to your inbox.

  • Deep-dive write-ups on ML, inference, and systems.
  • New Draw.io diagrams & interactive canvases.
  • Agentic patterns and rocket-science notes.
  • No spam. One tasteful email when there's something new.

Crafted by Dharaneesh Boobalan

Newsletter

Get new docs, diagrams, and write-ups in your inbox.

We never share your details. Unsubscribe anytime.