Ordinal and target encoding
Overview
When you have categorical features with inherent ordering or high-cardinality categories, one-hot encoding becomes wasteful or even harmful. Ordinal encoding preserves order by mapping categories to integers, while target encoding replaces categories with statistics derived from the target variable—both are compact, powerful techniques when applied correctly.
Ordinal Encoding
For a feature with categories where , we define:
WHY: Linear models and tree-based models interpret as "two steps apart", which matches the ordinal structure.
WHAT: You manually specify the order (or infer from domain knowledge), then replace each category with its rank.
HOW:
- Identify features with natural order (education level, satisfaction rating, sizes S/M/L/XL)
- Define the ordering explicitly
- Map each category to its integer rank
- Replace original values
where each is a categorical value and is the mapping function defined above.
Derivation from first principles:
- Goal: Represent ordinal categories numerically while preserving their relative ordering
- Constraint: The numeric representation must satisfy
- Simplest solution: Assign consecutive integers starting from 1
- Result: is the minimal bijective function that preserves order and uses the smallest range
Dataset:
Education: [High School, Bachelor, Master, PhD, Bachelor, High School]
Step 1: Define order
High School < Bachelor < Master < PhD
Step 2: Create mapping
High School → 1
Bachelor → 2
Master → 3
PhD → 4
Why this mapping? Because education level has clear progression—each step requires completing the previous one.
Step 3: Apply encoding
Result: [1, 2, 3, 4, 2, 1]
Why this works? A linear model learning coefficients like will correctly interpret that PhD (4) contributes more than Bachelor (2), and the difference is proportional.
Example 2: T-shirt Size
Size: [M, L, S, XL, M, S]
Step 1: Define order
S < M < L < XL
Step 2: Create mapping
S → 1
M → 2
L → 3
XL → 4
Why start at 1? Starting at 0 or 1 doesn't matter for order-preservation, but 1-indexing is conventional and avoids potential issues with models that treat0 specially.
Step 3: Apply
Result: [2, 3, 1, 4, 2, 1]
Why this step? Each original category is looked up in the mapping dictionary and replaced with its integer rank.
Target Encoding

For a categorical feature and target , the target encoding for category is:
WHY: High-cardinality features (many unique categories) explode with one-hot encoding. Target encoding compresses information while preserving predictive signal.
WHAT: Calculate the mean (or median, or any statistic) of the target variable for each category, then replace categories with those statistics.
HOW:
- Split data into train/validation
- For each category in train set, compute mean target value
- Replace categories with their means
- Handle unseen categories (global mean or special value)
- Crucial: Use cross-validation or separate encoding data to avoid leakage
where is the count of category in the training set.
Smoothed Target Encoding (prevents overfitting on rare categories):
where:
- = mean target for category
- = global mean of target
- = count of category
- = smoothing parameter (e.g., 10-100)
Derivation from first principles:
Goal: Create a single numerical feature that maximizes correlation with target while preventing overfitting.
Problem with raw mean: If category appears only once with , we'd encode it as 100—but this is likely noise, not signal.
Solution: Bayesian smoothing toward the global mean.
Starting point: We want a weighted average between category mean and global mean.
What should be? It should reflect our confidence in . High → high confidence → . Low → low confidence → .
Natural choice: where controls the smoothing strength.
Substituting:
Simplifying:
This is equivalent to adding "pseudo-observations" at the global mean—a classic empirical Bayes technique.
Training data:
City | Price (k$)
-------|----------
NYC | 500
NYC | 600
NYC | 550
Seattle | 400
Seattle | 450
Portland | 300
Step 1: Compute mean price per city
NYC: (500 + 600 + 550) / 3 = 550
Seattle: (400 + 450) / 2 = 425
Portland: 300 / 1 = 300
Why this step? We're aggregating all training examples for each category to get a representative statistic.
Step 2: Replace categories with means
City | Price | Encoded
----------|-------|--------
NYC | 500 | 550
NYC | 600 | 550
NYC | 550 | 550
Seattle | 400 | 425
Seattle | 450 | 425
Portland | 300 | 300
Why this works? The model now sees a numerical feature that directly correlates with the target. NYC's high encoding (550) tells the model "this city is expensive."
Step 3: Handle new city at test time
Test: [Boston, NYC, Seattle]
Boston is unseen. Use global mean = (550×3 + 425×2 + 300×1) / 6 = 475
Result: [475, 550, 425]
Why global mean for unseen? It's our best guess without data. Better alternatives: use validation set statistics or train a separate model for imputation.
Example 4: Smoothed Target Encoding
Suppose Portland appears only once. Raw encoding = 300 might be noise.
Apply smoothing with , global mean = 475:
Why this step? We're shrinking the extreme value (300) toward the population mean (475) because we have low confidence (only 1 observation).
For NYC with 3 observations:
Why is this still close to 550? Because 3 observations give us more confidence, so for the global mean vs0.77 for the category mean.
Wrong approach:
# Compute target encoding on ENTIRE dataset
encoding = df.groupby('city')['price'].mean()
df['city_encoded'] = df['city'].map(encoding)
# Then split train/testWhy this feels right: It's simpler—compute once, apply everywhere.
Why it's catastrophically wrong: The test set's target values leaked into the encoding. Your model sees future information. Validation accuracy will be inflated; real-world performance will crater.
The fix:
# Compute encoding ONLY on training data
encoding = train.groupby('city')['price'].mean()
train['city_encoded'] = train['city'].map(encoding)
test['city_encoded'] = test['city'].map(encoding).fillna(encoding.mean())Why this works: The encoding is computed without seeing test targets. Unseen categories get the global mean.
Even better: Use k-fold target encoding where each fold gets encoded using statistics from the other folds.
Mistake 2: Not smoothing for rare categories
Wrong: Use raw mean even for categories with1-2 samples.
Why this feels right: "That's the true mean for that category!"
Why it's wrong: With small samples, the mean is noisy. A category with 1 sample at might just be an outlier.
The fix: Apply smoothing (formula above). Rare categories get pulled toward the global mean.
Why this works: It's a bias-variance tradeoff. We accept slight bias (shrinking toward global mean) to dramatically reduce variance (wild swings from noise).
Mistake 3: Using ordinal encoding for nominal categories
Wrong: Encode [Red, Blue, Green] as [1, 2, 3] when there's no natural order.
Why this feels right: "It's just numbers, the model will figure it out."
Why it's wrong: Linear models will learn that Blue (2) is "between" Red (1) and Green (3), which is nonsense. You've injected false ordinal structure.
The fix: Use one-hot encoding, target encoding, or embedings—but never ordinal for nominal.
When to Use Which
| Feature Type | Cardinality | Encoding Choice |
|---|---|---|
| Ordinal (satisfaction) | Any | Ordinal |
| Nominal (city) | >50 | Target |
| Nominal (color) | <10 | One-hot |
| Nominal (user ID) | >10k | Target or Hash |
Recall
Imagine explaining to a 12-year-old:
"Let's say you're rating ice cream flavors from 'yuck' to 'yummy'. If 'yuck' is 1, 'okay' is 2, 'good' is 3, and 'yummy' is 4, you've just done ordinal encoding! The numbers match the order of how much you like them.
Now imagine you have a list of 100 different ice cream shops, and you want to predict how much people will pay. Instead of making 100 columns (one for each shop), you do something clever: replace each shop's name with the average price people paid there. Expensive shops get high numbers, cheap shops get low numbers. That's target encoding—you're using what happened before to create a useful number."
TEAPOT for target encoding pitfalls:
- Test leakage (don't encode test in training stats)
- Extreme smoothing needed for rare categories
- Avoid for ordinal features (overkill)
- Predict mode: handle unseen categories
- Overfitting risk without CV
- Tree models love it (compact, informative)
Connections
- One-hot Encoding - Alternative for low-cardinality nominal features
- Feature Scaling - May need to scale ordinal/target encoded features for distance-based models
- Cross-Validation - Essential for preventing target encoding leakage
- Bayesian Methods - Smoothed target encoding is empirical Bayes
- Curse of Dimensionality - Target encoding mitigates this for high-cardinality features
- Overfitting - Target encoding can overfit without proper CV/smoothing
- Tree-based Models - Handle ordinal encoding naturally via splits
#flashcards/ai-ml
What is ordinal encoding? :: Mapping categorical values to integers according to a specified order, preserving the ordinal relationship between categories (e.g., Poor=1, Fair=2, Good=3).
When should you use ordinal encoding? :: When categorical features have inherent ordering (education level, satisfaction ratings, sizes S/M/L/XL) and you want the model to respect that order.
What is target encoding?
Why is target encoding useful for high-cardinality features? :: It avoids the dimensionality explosion of one-hot encoding (500 cities → 500 columns) while preserving predictive signal by using target statistics (500 cities → 1 column with mean target per city).
What is the formula for smoothed target encoding?
Why is smoothing important in target encoding?
What is the biggest pitfall in target encoding?
How do you prevent target leakage in target encoding?
Why shouldn't you use ordinal encoding for nominal categories?
What is the derivation basis for smoothed target encoding?
How do you handle unseen categories at test time in target encoding?
Compare ordinal vs target encoding use cases :: Ordinal: inherent order (ratings, sizes, education). Target: high-cardinality nominal with predictive patterns (cities, user IDs, product SKUs). One-hot: low-cardinality nominal (colors, gender).
Concept Map
Hinglish (regional understanding)
Intuition Hinglish mein samjho
Dekho, jab tumhare pas categorical data hota hai toh usko numbers mein convert karna padta hai kyunki machine learning models sirf numbers samajhte hain. Ab do powerful techniques hain: ordinal encoding aur target encoding.
Ordinal encoding tab use karte hain jab tumhare categories mein ek natural order ho. Jaise T-shirt sizes: Small, Medium, Large, XL. Yahan clearly Small< Medium < Large < XL. Toh hum inko 1, 2, 3, 4 numbers assign kar dete hain. Simple! Model samajh jata hai ki 4 (XL) bada hai 2 (Medium) se. Education level ho ya satisfaction rating ho, jahan bhi order naturally exist karta hai, ordinal encoding perfect hai.
Target encoding ek aur hi level ka trick hai, specially jab bahut zyada unique categories hon (jaise 500 cities).Agar tum one-hot encoding karoge toh 500 columns ban jaenge—memory ki baat hi mat karo! Target encoding yeh karta hai: har city ko replace karo us city ka average house price se. NYC jahan prices high hain, usko high number milega (550k), aur Portland jahan sasta hai, usko low number (300k). Ek hi column mein pori predictive information aa gayi! Lekin yahan target leakage ka danger hai—kabhi bhi test data ka target dekh ke encoding mat banana, warna model cheat kar lega aur real world mein fail ho jayega. Hamesha sirf training data se encoding compute karo.
Rare categories ke liye smoothing bahut important hai. Agar kisi city ka sirf 1 sample hai toh uska mean noisy hoga, toh use global mean ki taraf thoda pull karte hain—bias-variance tradeoff. Aur ek galti kabhi mat karna: nominal categories (jahan order nahi hai, jaise colors) ko ordinal encoding mat do, warna model sochega "Blue, Red aur Green ke bech mein hai" jo bilkul nonsense hai!