Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

Quantile regression predicts a selected point in the conditional distribution of a target—not just its conditional mean. In Python, use statsmodels.QuantReg for interpretable linear coefficients, scikit-learn’s QuantileRegressor for a regularized linear pipeline, and quantile-loss boosting for nonlinear predictions. You can fit lower and upper quantiles to form a nominal prediction interval, but you must check its coverage on held-out data: fitting the models does not guarantee that the interval will contain the advertised share of future outcomes.

What quantile regression predicts

Ordinary least squares (OLS) models the conditional mean, E[Y | X=x]. Quantile regression models a chosen conditional quantile, QY(τ | X=x), where 0 < τ < 1. The 90th percentile is quantile 0.90; quantiles are usually written from 0 to 1 and percentiles from 0 to 100. See the scikit-learn overview of linear models.

  • τ = 0.50: conditional median.
  • τ = 0.05: conditional 5th percentile, a lower-tail estimate.
  • τ = 0.95: conditional 95th percentile, an upper-tail estimate.

For example, a delivery-time model might estimate a conditional median of 30 minutes, a 10th percentile of 20 minutes, and a 90th percentile of 48 minutes for orders with the same modeled characteristics. The range can reflect changing spread across feature values, but it is not a guaranteed range for every order.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Quantile regression is useful when outcomes are skewed, have changing variability (heteroskedasticity), or when a decision depends on a tail or threshold rather than the average. Applications include demand, energy load, traffic, response times, salaries, house prices, and insurance claims. It is not automatically preferable to mean regression: if the decision is specifically about expected revenue, expected cost, or a mean effect, the conditional mean may be the right target.

Pinball loss: the objective behind a quantile

For target quantile τ, quantile regression minimizes pinball loss (also called quantile or tilted absolute loss). With residual u = y − ŷ, one common form is:

ρτ(u) = τ max(u, 0) + (1 − τ) max(−u, 0)

Under-predictions and over-predictions receive different weights. At τ = 0.90, predicting too low is penalized more heavily than predicting too high; at τ = 0.10, the reverse is true. At τ = 0.50, the loss is proportional to absolute error, whose optimum is the conditional median. The scikit-learn model-evaluation guide documents pinball loss and its use for quantile predictions.

Target quantile Error given greater penalty
0.10 Prediction is too high
0.50 Under- and over-prediction are weighted equally
0.90 Prediction is too low

Pinball loss grows linearly with the size of a residual, unlike squared error, which grows quadratically. That makes quantile regression less sensitive to extreme residual magnitudes than least squares in that specific sense. It does not make a model immune to bad data, high-leverage observations, misspecification, or sparse tails.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Choose the Python implementation

Need Good starting point Key API
Linear coefficients, summaries, and econometric interpretation statsmodels QuantReg(y, X).fit(q=...)
Regularized linear model inside an ML pipeline scikit-learn QuantileRegressor(quantile=...)
Nonlinear tabular prediction and quantile bands scikit-learn boosting GradientBoostingRegressor(loss="quantile") or histogram boosting
Existing boosted-tree workflow at scale XGBoost reg:quantileerror; check installed-version API

scikit-learn’s stable documentation is version 1.9.0 (retrieved August 18, 2026); the cited stable statsmodels documentation is 0.14.6. APIs and installed package versions may differ, so consult the documentation for the version in your environment rather than assuming development documentation describes a stable release.

Linear quantile regression with statsmodels

statsmodels.regression.quantile_regression.QuantReg is a natural choice when a linear specification and coefficient summaries matter. Its fitting method accepts the target quantile as q. With array or DataFrame inputs, add an intercept explicitly unless your design matrix already contains one. The estimator uses iterative reweighted least squares; inference and covariance choices are not the same as ordinary least squares. See the statsmodels QuantReg API.

python -m pip install numpy pandas statsmodels
import pandas as pd
import statsmodels.api as sm

# A small example dataset
df = pd.DataFrame({
    "hours": [1, 2, 3, 4, 5, 6, 7, 8],
    "score": [52, 55, 57, 63, 68, 70, 74, 80],
})

X = sm.add_constant(df[["hours"]])
y = df["score"]

model = sm.QuantReg(y, X)
median_result = model.fit(q=0.50)
print(median_result.summary())
print(median_result.params)

To compare coefficient patterns across quantiles, fit separate models:

quantiles = [0.10, 0.50, 0.90]
results = {q: sm.QuantReg(y, X).fit(q=q) for q in quantiles}

predictions = pd.DataFrame({
    f"q{int(q * 100)}": results[q].predict(X)
    for q in quantiles
})
print(predictions)

A formula interface is also available:

import statsmodels.formula.api as smf

result = smf.quantreg("score ~ hours", data=df).fit(q=0.50)
print(result.summary())

Interpret a coefficient as a shift in the modeled conditional quantile under the fitted specification. For instance, a coefficient of 3.2 on hours in a 90th-quantile model means that, holding included predictors constant, one additional hour is associated with a 3.2-unit increase in the modeled conditional 90th percentile. It does not say that 90% of individuals increase by 3.2 units, nor does it establish a causal effect. Tail coefficients can differ substantially from median coefficients. Very extreme quantiles need far more supporting data than the median; inference also depends on covariance and bandwidth choices.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Regularized linear quantiles with scikit-learn

QuantileRegressor minimizes pinball loss with an L1 penalty, making it useful as a regularized linear baseline in scikit-learn pipelines. Its quantile argument is named quantile, and must be strictly between 0 and 1. The separate alpha argument controls regularization; it does not select the quantile. The documented default solver is "highs", which uses SciPy’s linear-programming machinery. See the linear-model guide and QuantileRegressor API.

python -m pip install numpy pandas scipy scikit-learn
from sklearn.linear_model import QuantileRegressor

median_model = QuantileRegressor(
    quantile=0.50,
    alpha=0.01,
    solver="highs",
)
median_model.fit(X_train, y_train)
median_prediction = median_model.predict(X_test)

For mixed numeric and categorical inputs, place preprocessing and estimation in a pipeline so transformations are learned only from the training data:

from sklearn.compose import make_column_transformer
from sklearn.linear_model import QuantileRegressor
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import OneHotEncoder, StandardScaler

numeric_features = ["age", "income"]
categorical_features = ["region"]

preprocessor = make_column_transformer(
    (StandardScaler(), numeric_features),
    (OneHotEncoder(handle_unknown="ignore"), categorical_features),
)

model = make_pipeline(
    preprocessor,
    QuantileRegressor(quantile=0.50, alpha=0.01, solver="highs"),
)
model.fit(X_train, y_train)
predictions = model.predict(X_test)

The model remains linear in the transformed features. L1 regularization can help with expanded feature sets, but very large one-hot matrices may make solver performance a consideration. Fit separate estimators for separate quantiles; independently estimated models can cross. Tune and evaluate with pinball loss for the quantile you intend to use, not only the estimator’s default score.

Nonlinear quantile regression with gradient boosting

Boosted trees can model nonlinear effects and interactions without manually specifying them as in a linear model. GradientBoostingRegressor uses loss="quantile" and the parameter alpha to select the quantile. The HistGradientBoostingRegressor variant uses loss="quantile" with the parameter quantile instead. Do not confuse either API with QuantileRegressor, where alpha is the regularization strength. scikit-learn describes histogram boosting as a faster variant for intermediate and large datasets; whether it is faster for a particular workload depends on data, hardware, and configuration. See the GradientBoostingRegressor API and official quantile interval example.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
from sklearn.ensemble import GradientBoostingRegressor

common_params = {
    "learning_rate": 0.05,
    "n_estimators": 200,
    "max_depth": 2,
    "min_samples_leaf": 9,
    "min_samples_split": 9,
    "random_state": 42,
}

models = {
    q: GradientBoostingRegressor(
        loss="quantile",
        alpha=q,
        **common_params,
    ).fit(X_train, y_train)
    for q in [0.05, 0.50, 0.95]
}

predictions = {q: model.predict(X_test) for q, model in models.items()}
lower = predictions[0.05]
median = predictions[0.50]
upper = predictions[0.95]

For histogram boosting, the corresponding parameter is named quantile:

from sklearn.ensemble import HistGradientBoostingRegressor

models = {
    q: HistGradientBoostingRegressor(
        loss="quantile",
        quantile=q,
        max_iter=300,
        learning_rate=0.05,
        max_leaf_nodes=31,
        random_state=42,
    ).fit(X_train, y_train)
    for q in [0.05, 0.50, 0.95]
}

Separate quantiles can need different hyperparameters: a configuration that works for the median may not work well for a tail. Tune models against quantile-specific validation loss and inspect their calibration rather than assuming one setting is optimal for all three.

Building and evaluating an interval

Predictions from the 5th- and 95th-quantile models define a nominal 90% conditional quantile interval when the lower prediction is below the upper prediction. The word “nominal” matters: the quantile targets describe what the models are trained to estimate, not a coverage guarantee for new observations.

For each quantile, evaluate pinball loss using that same quantile value:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
import numpy as np
from sklearn.metrics import mean_pinball_loss

for q in [0.05, 0.50, 0.95]:
    loss = mean_pinball_loss(
        y_test,
        predictions[q],
        alpha=q,
    )
    print(f"q={q:.2f}: {loss:.4f}")

For a nominal central 90% interval, measure empirical coverage and width on held-out data:

coverage = np.mean((y_test >= lower) & (y_test <= upper))
mean_width = np.mean(upper - lower)
median_width = np.median(upper - lower)

print(f"Empirical coverage: {coverage:.1%}")
print(f"Mean width: {mean_width:.3f}")
print(f"Median width: {median_width:.3f}")

Coverage should be near the nominal target over an appropriate evaluation population, subject to finite-sample variation; it need not equal 90% exactly. Interpret it together with width: an extremely wide interval may cover many outcomes but be unhelpful, while a narrow one can under-cover. R² and RMSE may be useful for other goals, but neither directly evaluates the quality of a particular quantile estimate.

Overall coverage can hide failures. Check it across important categories, time periods, geographies, volume bands, or bins of predicted median and risk features. Also check quantile calibration: on held-out data, approximately a fraction q of outcomes should fall below predictions from a q-quantile model. Sampling variation, misspecification, and distribution changes can make the observed fraction differ.

A confidence interval commonly describes uncertainty about an estimated parameter or mean function; a prediction interval concerns a future outcome. Quantile models estimate conditional quantiles and can be used to construct predictive ranges, but independent fitted quantiles do not automatically form a formally calibrated prediction interval. In scikit-learn’s demonstration, the displayed interval undercovers its nominal 90% target on the example test set. That result illustrates a possible failure, not a universal benchmark.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Detect and address quantile crossing

Conditional quantiles must be ordered, but independently fitted models can violate that order for some feature values. For example, a predicted 5th percentile can exceed the predicted 95th percentile, or a median can fall outside the lower and upper predictions.

Best Value
Sale
Hands-On Machine Learning with Scikit-Learn, Keras, and TensorFlow: Concepts, Tools, and Techniques to Build Intelligent Systems
  • Use scikit-learn to track an example ML project end to end
  • Explore several models, including support vector machines, decision trees, random forests, and ensemble methods
  • Exploit unsupervised learning techniques such as dimensionality reduction, clustering, and anomaly detection
  • Dive into neural net architectures, including convolutional nets, recurrent nets, generative adversarial networks, autoencoders, diffusion models, and transformers
  • Use TensorFlow and Keras to build and train neural nets for computer vision, natural language processing, generative models, and deep reinforcement learning
crossing_lower_median = np.mean(lower > median)
crossing_median_upper = np.mean(median > upper)
crossing_any = np.mean((lower > median) | (median > upper))

print(crossing_lower_median, crossing_median_upper, crossing_any)

One pragmatic display-time repair is to sort the predicted quantiles for each row:

ordered = np.sort(np.column_stack([lower, median, upper]), axis=1)
lower_fixed, median_fixed, upper_fixed = ordered.T

Sorting enforces order, but it does not retrain the models, preserve their original quantile identities, or guarantee calibration. Treat it as post-processing, then evaluate the repaired predictions. More principled options include jointly trained quantile models with non-crossing constraints, rearrangement methods, a suitable location-scale model, or conformal calibration.

XGBoost’s quantile-regression documentation describes the reg:quantileerror objective and QuantileDMatrix, notes that the feature was added in XGBoost 2.0.0, and warns that crossing can occur. Its example is version-sensitive; check the installed version and API before adapting it, and do not assume identical support across language bindings.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Conformalized quantile regression for calibration

When empirical coverage is too low, conformalized quantile regression (CQR) combines fitted lower and upper quantiles with a separate calibration set. In broad terms, train the quantile models on training data, score how calibration observations fall outside their predicted intervals, use an appropriate finite-sample quantile of those scores to choose an expansion, and apply it to future intervals. Reserve a final test set to assess the complete procedure. The method was introduced by Romano, Patterson, and Candès.

Under exchangeability, conformal methods can provide finite-sample marginal coverage without requiring a correctly specified outcome distribution. This is not a guarantee of coverage conditional on every feature value or subgroup. Temporal dependence, grouped observations, and distribution shift can violate the assumptions; calibration may consume data and widen intervals. Time-series and grouped settings need validation designs and methods that account for their structure. A hand-written calibration routine also needs careful finite-sample indexing and handling of ties and missing values.

Forecasting, validation, and data leakage

If observations are time ordered and deployment predicts the future, do not use a random train/test split. Use a chronological holdout or a suitable time-series cross-validation design, and construct lagged features without access to future values. The scikit-learn lagged-feature forecasting example illustrates quantile boosting in a forecasting context.

Leakage can make intervals seem far better calibrated than they will be in deployment. Watch for future information in lag features, aggregations computed across the full dataset, target-derived categories, or variables recorded only after the outcome. For repeated observations from the same customer, patient, device, or location, split and evaluate by group when that matches deployment; ordinary random splitting can leak group-specific information and invalidate simple independence assumptions. Recheck calibration over time when the data-generating process may drift.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Common modeling edge cases

  • Extreme tails: A 99th-quantile model relies on relatively few tail observations. Its estimates can be unstable or dominated by a handful of cases. Choose a quantile that fits the decision and the available tail data.
  • Unobserved uncertainty drivers: Quantile regression can reflect changing spread when features explain it, but it cannot discover uncertainty sources absent from the inputs. Missing drivers can make intervals too narrow.
  • Nonnegative outcomes: An unconstrained model can predict a negative lower bound for demand, claims, or other nonnegative quantities. Consider a transformation, a distribution-aware model, or justified domain-aware post-processing; assess the effect on decision-relevant quantiles.
  • Transformed targets: A log transform may help with positive skew, but transform predictions back consistently. Quantiles transform differently from means under nonlinear transformations, and naive inverse transformations can mislead.
  • Censoring or truncation: If observations are capped, censored, or systematically absent beyond a threshold, ordinary quantile regression on recorded values may be inappropriate. Consider methods designed for censored outcomes or survival analysis.

Which model should you use?

Choose When it fits Trade-off to remember
statsmodels.QuantReg Linear coefficients, summaries, and inference matter; a linear conditional-quantile specification is plausible. Inference depends on covariance choices; it is not a high-capacity nonlinear predictor.
sklearn.QuantileRegressor You need a regularized linear baseline, sparse or encoded features, and pipeline or cross-validation integration. Solver performance can matter for very large expanded designs; separate quantiles can cross.
scikit-learn gradient boosting Tabular relationships are nonlinear or interactions matter and prediction is the priority. Fit and tune quantiles separately unless using a joint method; validate tails and crossing.
XGBoost quantile objective Your workflow already uses XGBoost or benefits from its optimized boosted-tree ecosystem. Confirm version-specific arguments and check crossing and calibration.

The right choice follows the decision: select a quantile that represents the operational target, a model class that matches the relationship, and a validation and calibration strategy that resembles deployment.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.