#428Smoothed Target (Mean) EncodingMedium

Smoothed Target (Mean) Encoding

Background

Categorical features with many levels (user ID, zip code, product SKU) cannot be one-hot-encoded without exploding the feature space. Smoothed target encoding replaces each category with the average of the target restricted to that category, blended toward a global prior so rare categories don't overfit. It is the technique that dominates Kaggle leaderboards in tabular / CTR contexts.

Problem statement

Implement smoothed_target_encode(values, targets, smoothing=10.0, prior=None) returning a dict mapping each category to its smoothed encoding:

enc(c)  =  ncyˉc  +  myˉnc+m\mathrm{enc}(c) \;=\; \frac{n_c\,\bar{y}_c \;+\; m\,\bar{y}}{n_c + m}

where ncn_c is the number of samples in category cc, yˉc\bar{y}_c is the mean target in that category, yˉ\bar{y} is the global target mean (the prior), and mm is the smoothing strength. A high mm pulls rare categories toward the global mean; a low mm trusts each category's own mean.

Input

  • values - sequence of category labels (hashable), length nn.
  • targets - sequence of numeric targets, same length.
  • smoothing - float >= 0, prior weight mm (default 1010).
  • prior - optional float; if None, use the global target mean.

Output

  • dict[label -> float] of encodings, one entry per unique value in values.

Examples

Example 1 - balanced classes, no smoothing pull needed

Input:  values = ["A","A","B","B"], targets = [1, 1, 0, 0], smoothing = 0
Output: {"A": 1.0, "B": 0.0}

Example 2 - rare category pulled to the global prior

Input:  values = ["A","A","A","A","A","A","A","A","A","B"],
        targets = [1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
        smoothing = 10
Output: {"A": ~0.95,  "B": ~0.818}

Explanation: global prior = 0.90.9. "A": (91+100.9)/(9+10)=18/190.947(9 \cdot 1 + 10 \cdot 0.9)/(9 + 10) = 18/19 \approx 0.947. "B": (10+100.9)/(1+10)=9/110.818(1 \cdot 0 + 10 \cdot 0.9)/(1 + 10) = 9/11 \approx 0.818 (heavily pulled to the prior).

Constraints

  • The prior defaults to the overall target mean (sum(targets) / n). Pass an explicit prior to fix it across slices (e.g. for leave-one-out variants).
  • smoothing = 0 reduces to raw mean target per category (no shrinkage).
  • Return a dict with one entry per unique value (no row-aligned output).

Notes

  • Leakage. The naive version computes the encoding on the training set that the encoder is then applied to — this directly leaks the target. Production setups use out-of-fold (K-fold) target encoding so the encoding for each row is computed from rows outside its fold. That is the second hidden problem in this set.
  • Why smoothing matters. A rare category with 1 sample has a mean of either 0 or 1 — pure noise. The Bayesian-flavoured shrinkage to the prior keeps that noise from dominating the model.
  • Multi-class / regression. Same formula; "target mean" is the class-conditional mean for binary problems, the literal mean for regression, or the per-class probabilities one column at a time for multi-class.
Python
Loading...

▶ Run executes the 3 visible sample tests below in your browser. Submit runs the full suite — including hidden tests — on the server for an official verdict.

  • Reference: smoothing zero raw means
  • Sample: rare category to prior
  • Example: explicit prior override