skills/timeseries/scaled-pinball-loss/SKILL.md
Scaled Pinball Loss (SPL) metric for evaluating quantile forecasts, normalized by mean absolute successive differences of training data
npx skillsauth add wenmin-wu/ds-skills timeseries-scaled-pinball-lossInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
The Scaled Pinball Loss (SPL) evaluates quantile forecast accuracy while being scale-independent across time series. The numerator is the standard pinball (quantile) loss; the denominator normalizes by the mean absolute successive difference of the training data, similar to how MASE normalizes by naive forecast error. This makes SPL comparable across series with different scales.
import numpy as np
def scaled_pinball_loss(y_true, y_pred, quantile, y_train):
"""Compute SPL for a single quantile forecast."""
h = len(y_true)
# Pinball numerator
errors = y_true - y_pred
pinball = np.where(errors >= 0, quantile * errors, (quantile - 1) * errors)
numerator = np.sum(pinball)
# Scale denominator: mean absolute successive differences
N = len(y_train)
denom = np.sum(np.abs(np.diff(y_train))) / (N - 1)
return numerator / (h * denom)
def mean_spl(y_true, quantile_preds, quantiles, y_train):
"""Average SPL across all quantiles."""
scores = []
for q, pred in zip(quantiles, quantile_preds):
scores.append(scaled_pinball_loss(y_true, pred, q, y_train))
return np.mean(scores)
quantiles = [0.005, 0.025, 0.165, 0.25, 0.5, 0.75, 0.835, 0.975, 0.995]
score = mean_spl(y_val, preds_per_quantile, quantiles, y_train)
q * e if e >= 0, else (q-1) * e(h * denominator) for scale-free metricdenom ≈ 0, the series is constant — clip to a small epsilondata-ai
Walk backward through a time series and multiplicatively rescale segments when jumps exceed a fraction of the running mean to correct data collection anomalies
testing
Transform forecasting target to next/current ratio minus one so that optimizing MAE or squared error implicitly minimizes SMAPE
tools
Convert point forecasts to prediction intervals by scaling with logit-transformed quantile ratios passed through a Normal CDF
testing
Use scipy periodogram to identify dominant seasonal frequencies in a time series before selecting Fourier feature orders or ARIMA seasonal parameters