Skip to content

Sample Weights: The Four Types

Not every observation deserves equal weight in a financial ML fit. López de Prado's four weight schemes (uniqueness, return-attributed, time-decay, volatility-scaling) fix different biases. Use them deliberately, not by default.

8 of 12 ~14 min

Sample Weights: The Four Types That Matter

Equal weighting is the silent default in most quant ML pipelines. You assemble a panel of observations, you fit a model, and every row counts once. The result is a model that treats a quiet Tuesday in 2017 and a Fed-day in March 2020 as the same data point. They are not the same data point. One of them is a high-information event that drove the cross-section of returns. The other is a redundant echo of a hundred other quiet days. Equal weighting throws away the structure that makes a financial dataset interesting.

This article is about how to fix that. There are four weight schemes that matter in practice, and they solve four different problems. Use the wrong one for the problem you have, and you introduce bias in the opposite direction from the one you were trying to remove.

The reference is López de Prado, Advances in Financial Machine Learning, Chapter 4 (AFML hereafter). The chapter is short. The ideas are not obvious. Most practitioners read it once, decide weighting is a nice-to-have, and ship equal weights anyway. The first time they wonder why their backtest does not survive a regime change is usually the moment they come back to it.

Why Equal Weighting Is Wrong

Three reasons, in increasing order of subtlety.

The first reason is redundancy. A feature computed over a 60-day rolling window contains roughly the same information at day tt and day t+1t+1. If your training set has daily observations, you have effectively a hundred overlapping copies of the same information. A model trained on these data is over-counting recent redundancy and under-counting genuinely independent observations. The redundancy is structural: it is built into how features are constructed.

The second reason is event concentration. Most of the cross-sectional return variation in a year happens in a handful of days. The 2020 return distribution was shaped by perhaps 15-20 days: the COVID crash in March, the recovery rally, the election volatility, the vaccine Monday, the year-end melt-up. The other 230 days contributed comparatively little to the cross-sectional signal. A model trained with equal weights learns the average day, not the high-information days. The high-information days are exactly where you need the model to perform.

The third reason is regime dependence. Older observations in your training set come from a different macro environment than the current one. A factor model fit on 2010-2015 may be appropriate for 2010-2015 but inappropriate for 2018-2024. Without down-weighting older observations, you are implicitly assuming the data-generating process is stationary. It is not.

These three reasons (redundancy, event concentration, regime dependence) drive the three weight schemes in AFML Chapter 4. The fourth scheme (return-attributed) addresses a meta-issue: how to combine the others.

(López de Prado, M., Advances in Financial Machine Learning, Ch. 4. ISBN 978-1119482086.)

Type 1: Uniqueness Weights

The basic insight: an observation at time tt is more informative if it is not a duplicate of observations at nearby times. The weight should be proportional to how “unique” the observation is.

Formally, define the average uniqueness of observation ii as the average number of concurrent labels that observation ii contributes to. If observation ii is a label that overlaps with cc other labels in the dataset (because they share a common feature computation window), then the uniqueness weight is:

ui=1ciu_i = \frac{1}{c_i}

where cic_i is the number of labels that overlap with the label of observation ii.

For a triple-barrier label with vertical barrier hh days, the label window is [t,t+h][t, t+h]. If another observation’s label window overlaps with this one (i.e., another label starts at t′∈[t−h+1,t+h−1]t' \in [t-h+1, t+h-1]), they share information. The uniqueness is the inverse of the count of overlapping labels.

A clean way to compute this is via the concurrency matrix. Let CC be the matrix where CijC_{ij} indicates whether observations ii and jj share a common label computation window. The average uniqueness of observation ii is:

uˉi=1ci∑j:Cij=11cj\bar{u}_i = \frac{1}{c_i} \sum_{j : C_{ij} = 1} \frac{1}{c_j}

The intuition: an observation that overlaps with many others gets a small weight. An observation whose label window is isolated gets a high weight.

Why does this matter operationally? Suppose you have a daily dataset of 1,000 observations over 4 years (~1,000 trading days). With h=5h = 5 day labels, each label overlaps with up to 10 neighbors. The redundancy factor is roughly 10x. Without uniqueness weighting, your model treats your 1,000 observations as if they were 1,000 independent samples; in reality they are closer to 100 independent samples. The effective sample size is one-tenth of what you think it is. Confidence intervals on your Sharpe ratio are 3x too narrow.

The fix: weight by uˉi\bar{u}_i. Now your 1,000 observations, properly weighted, contribute the information content of roughly 100 independent observations. The Sharpe confidence interval widens to reflect reality.

(AFML, §4.4.1.)

Type 2: Return-Attributed Weights

This is the meta-weight. The other three weights are computed from the structure of the dataset (overlap, time, volatility). The return-attributed weight comes from the observed return associated with each observation: how much “money was made” by being on the right side of this label.

The formula:

wi=∣riSt∣⋅1∑j∣rjSt∣w_i = \left| \frac{r_i}{S_t} \right| \cdot \frac{1}{\sum_j \left| \frac{r_j}{S_t} \right|}

where rir_i is the return associated with observation ii and StS_t is some baseline (typically the average volatility-adjusted return at time tt).

The idea: a label that produces a large return (positive or negative) carries more information than a label that produces a tiny return. This is a way to focus the model on the labels that actually mattered for P&L.

The catch: this weight depends on the labels themselves, which creates a chicken-and-egg problem if your labels are themselves noisy estimates of true returns. The right way to use return-attributed weights is as a final step, after you have a model and want to focus the fit on the labels that contributed most to your P&L.

A common pattern: fit the model with uniqueness weights, evaluate P&L attribution on each label, then refit using return-attributed weights on the labels that drove most of the P&L. This is a form of importance sampling.

A subtler pattern: use return-attributed weights to identify which observations are “regime-defining”, those with outsized absolute returns, and up-weight them in subsequent training runs. The model then learns the regime structure explicitly, rather than treating the regime-defining days as noise.

The risk: return-attributed weights can overweight outliers. A single flash crash day might dominate the weights. The fix is to clip the absolute returns at some multiple of the rolling volatility, or to use the rank of the return rather than its raw value.

(AFML, §4.6.)

Type 3: Time-Decay Weights

The idea: older observations are less relevant than recent ones, because the underlying distribution has drifted. Down-weight older samples.

The standard form is exponential decay:

wi=exp⁡(−tnow−tiT)w_i = \exp\left( -\frac{t_{\text{now}} - t_i}{T} \right)

where tit_i is the timestamp of observation ii, tnowt_{\text{now}} is the time of the fit, and TT is the decay time constant.

The half-life (time until the weight halves) is Tln⁡2≈0.693TT \ln 2 \approx 0.693 T. A half-life of 1 year means T≈1.44T \approx 1.44 years.

How to choose TT? Three approaches, in order of preference.

Approach 1: Match the half-life to your target holding period. If you are fitting a model for a 5-day holding period, a half-life of 3-6 months is reasonable. If you are fitting for a quarterly rebalance, a half-life of 1-2 years. The half-life should be long enough to include enough data, but short enough to emphasize the recent regime.

Approach 2: Use cross-validation to optimize TT. Hold out the last 20% of your data, fit the model on the first 80% with various TT, evaluate on the holdout. The TT that maximizes out-of-sample performance is your choice. This is the honest approach, but it requires holding out enough data to detect differences.

Approach 3: Use the half-life of the alpha’s IC. From a previous fit (without time decay), measure how the IC decays over time. Set TT to roughly the IC half-life. This links the data weighting to the actual decay of the signal you are trying to capture.

The risk with time decay: if you make TT too small, you fit only the recent regime and lose the ability to generalize. If you make TT too large, you are back to equal weighting with all its problems. A useful diagnostic: fit the model with various TT and see how the in-sample and out-of-sample performance change. The point where out-of-sample performance starts degrading is your optimal TT.

(AFML, §4.7.)

Type 4: Volatility-Scaling Weights

The idea: high-volatility periods produce larger absolute returns, which can dominate a model fit. Scale by inverse volatility so each regime contributes equally.

The formula:

wi=1σtiw_i = \frac{1}{\sigma_{t_i}}

or, with rolling standardization:

wi=1σti,rollingw_i = \frac{1}{\sigma_{t_i, \text{rolling}}}

where σti\sigma_{t_i} is the realized volatility at the time of observation ii.

Why this matters: a regression of returns on features is implicitly a return-space regression. A 1% move in a low-volatility regime and a 5% move in a high-volatility regime are different in magnitude but may carry similar information. Without volatility scaling, the high-volatility observations dominate the fit, and the model effectively learns “what happens during volatile periods” rather than “what drives returns.”

A more sophisticated version scales by the inverse of the standard deviation of the label, not the standard deviation of returns. This accounts for the fact that labels may have different noise levels (e.g., labels constructed from shorter windows are noisier).

The combined scheme most people use in practice:

wi=uˉi⋅exp⁡(−tnow−tiT)⋅1σtiw_i = \bar{u}_i \cdot \exp\left(-\frac{t_{\text{now}} - t_i}{T}\right) \cdot \frac{1}{\sigma_{t_i}}

This is uniqueness weights (to handle feature overlap) times time decay (to handle regime shift) times inverse volatility (to handle absolute-return heterogeneity). Three weights, three problems addressed, one final weight.

(See, e.g., AFML, §6.5 for related discussion of volatility scaling in the bet-sizing context.)

Combining the Weights

The order matters. Apply uniqueness weights first, then time decay, then volatility scaling. Each subsequent step operates on the result of the previous one.

A common mistake: applying time decay first, then uniqueness. This under-weights observations whose features overlap with later observations (which is most of them). The correct order: identify the unique information content of each observation (uniqueness), then weight by how relevant that information is to the current regime (time decay), then scale to put all observations on the same volatility footing.

The weights are multiplicative, not additive. You are not picking one scheme; you are stacking them.

A practical implementation note: when stacking weights, normalize so that the sum of weights equals the number of observations (or some other convenient constant). This keeps the loss function at a similar scale regardless of which weights you use, which makes hyperparameter tuning easier.

A Concrete Example

Suppose you are fitting a model on 4 years of daily observations (about 1,000 trading days). Labels are triple-barrier with h=5h = 5. Features include 20-day rolling volatility and 60-day momentum.

Uniqueness weights: With h=5h = 5, each label window is 5 days. Two observations ii and jj overlap if their label windows intersect. For a daily dataset, each label overlaps with about 10 others (5 before, 5 after, minus itself). Average uniqueness is roughly 0.1. So most observations get a uniqueness weight of about 0.1, with some outliers at 0.05 (highly redundant) or 0.5 (relatively isolated).

Time decay: With a 2-year half-life (T≈2.88T \approx 2.88 years), observations from 4 years ago get weight exp⁡(−4/2.88)≈0.25\exp(-4/2.88) \approx 0.25. Observations from 1 year ago get weight exp⁡(−1/2.88)≈0.71\exp(-1/2.88) \approx 0.71. The oldest observations are down-weighted by 75%; the recent ones retain 70%+.

Volatility scaling: Realized volatility over the 4-year period ranges from about 8% (annualized, in calm 2017) to 60%+ (annualized, in March 2020). The inverse-volatility weight ranges from about 1/0.08 = 12.5 (calm periods) to 1/0.6 = 1.7 (crisis periods). Crisis-period observations are down-weighted by a factor of 7x relative to calm-period observations.

Combined: A typical observation from 2018 (calm, mid-sample) gets weight ≈0.1⋅0.5⋅5=0.25\approx 0.1 \cdot 0.5 \cdot 5 = 0.25. A crisis observation from March 2020 gets ≈0.1⋅0.95⋅1.7=0.16\approx 0.1 \cdot 0.95 \cdot 1.7 = 0.16. A 2014 observation (old, calm) gets ≈0.1⋅0.25⋅6=0.15\approx 0.1 \cdot 0.25 \cdot 6 = 0.15.

The relative weights tell the story: the model fits 2018 data twice as hard as it fits 2020 crisis data, because 2018 contains more unique information per unit of regime drift. This is exactly the point. A model that fits 2020 too hard will be calibrated to crisis dynamics, which then mis-prices 2021-2024 calm-regime opportunities.

When NOT to Use Weights

Three cases where equal weighting is fine.

Case 1: Cross-sectional models at a single point in time. If your dataset is a snapshot of features and labels for many assets on a single day, there is no time decay to apply, no rolling feature overlap, no return attribution. Equal weighting is correct.

Case 2: Classification problems where each label is an independent event. If you are predicting whether a specific event (earnings announcement, FDA decision, M&A close) is positive or negative, each event is a discrete observation. Time decay may still apply if the events cluster in different regimes, but uniqueness and volatility-scaling usually do not.

Case 3: Pre-feature-engineering. Before you compute rolling features, your dataset may have minimal overlap between observations. Uniqueness weights are roughly equal. Time decay and volatility scaling may still apply, but uniqueness is moot.

In all other cases (most quant ML pipelines), you should be using at least one of these four weight schemes, and probably two or three stacked.

What the Weights Buy You

A factor model fit with proper weights produces more accurate factor loadings in the recent regime, with realistic confidence intervals that reflect the true effective sample size. The performance improvement on the backtest is rarely dramatic (you might go from Sharpe 1.5 to Sharpe 1.7), but the robustness improvement is meaningful. A weighted-fit model is less likely to fail catastrophically when the regime changes, because it is anchored to recent, unique, volatility-adjusted observations rather than the full noisy history.

The Sharpe ratio improvement is the wrong metric. The right metric is: how does the model perform in 2024 if it was fit on data ending in 2023? A model with proper weights handles this transition better than a model fit with equal weights.

(AFML, Ch. 4 conclusion.)

Implementation Notes

The weights are easy to implement. Uniqueness weights require a concurrency matrix (which is O(N2)O(N^2) to compute naively, but O(Nh)O(Nh) with rolling windows). Time decay is a single exponential. Volatility scaling requires rolling realized volatility.

A few practical tips:

  • Normalize weights so ∑iwi=N\sum_i w_i = N. This keeps the loss function scale-invariant.
  • Clip extreme weights at the 1st and 99th percentiles to prevent single observations from dominating.
  • When stacking weights, verify that the effective sample size (computed as (∑wi)2/∑wi2(\sum w_i)^2 / \sum w_i^2) is at least 30, otherwise your standard errors are unreliable.
  • Re-evaluate weights at each refit. A model fit in 2020 with weights based on 2010-2020 data should be refit in 2024 with weights based on 2014-2024 data.

The takeaway: weights are not a “nice to have.” They are part of the model specification, on par with the choice of features and hyperparameters. A model with bad features and good weights will outperform a model with good features and bad weights, because the bad-weight model is implicitly fitting the wrong sample distribution.

The Bigger Picture

The four weight schemes are not just technical fixes. They encode four different prior beliefs about financial data:

  • Uniqueness weights: the signal in the data is sparse; most observations are redundant.
  • Return-attributed weights: the signal is concentrated in events that drove P&L.
  • Time decay weights: the signal is non-stationary; recent is more relevant.
  • Volatility-scaling weights: the signal is in relative returns, not absolute returns.

None of these priors are universally true. All of them are often true. The art of quant ML is knowing which priors apply to your specific dataset and stacking the corresponding weights in the right order. A momentum model on daily US equities from 2010-2024 needs all four. A cross-sectional value model on a single day needs none. Most pipelines need somewhere in between.

(López de Prado, M., Advances in Financial Machine Learning, Ch. 4, §4.5. ISBN 978-1119482086.)