Data Preparation / Data Preprocessing Slides 📂 Introduction · 11 of 13 41 min read

Feature Engineering & Feature Scaling

A practical, visual guide to crafting predictive features and scaling them right. Build interaction ratios, polynomial and cyclical date features, bins, aggregations and domain metrics; scale in the correct order; and catch the multicollinearity that feature engineering itself creates — with VIF checks and a leak-proof sklearn pipeline.

Feature Engineering & Feature Scaling

Where domain knowledge, creativity and maths combine. A brilliant feature set with a simple model almost always beats a poor feature set with a complex one — invest your time here first.
Interactions Date & Cyclical Binning & Aggregation Multicollinearity

Press Next → or use ← → arrow keys

Section 01

Why Feature Engineering Matters

Three features, a 59% lift, same model
An e-commerce team lifted click-through from 3.2% to 5.1% — a 59% relative gain worth ₹18 crore a year — without touching the model. They just added three engineered features: days since last purchase, average spend per visit, and hour-of-day as sine/cosine. Better information, not a better algorithm.
1 · Clean 2 · Engineercreate signal 3 · Encode 4 · Scaleafter engineering 5 · Select
⚠️
Engineer before you scale

Create, transform and combine features first, then scale the result. Scale first and your ratios become dimensionless nonsense that no longer mean anything.

Section 02

Six Ways to Engineer a Feature

✖️
Interaction
Combine two features to capture a joint effect.
spend / days · age × income
📈
Polynomial
Powers & cross-terms let linear models bend.
age² · x₁·x₂
📅
Date / Time
Pull calendar & cyclical signals from timestamps.
dayofweek · sin(2π·h/24)
📦
Binning
Bucket continuous values into ordered bands.
pd.cut · pd.qcut
📊
Aggregation
Group statistics a single row can't express.
customer avg · city median
🔧
Domain
Expert-crafted ratios and risk scores.
debt/income · bmi
💡
The best features come from people, not automation

Ask what an expert mentally computes when making the same call — a credit officer thinks "debt-to-income", a doctor thinks "BMI". Encode that intuition and the model inherits it.

Section 03

Interaction Features — Ratios & Products

A microfinance model jumped from AUC 0.71 to 0.84 on one feature: debt_to_income. Debt and income alone were weak — their ratio was the single most predictive signal in the whole dataset.

# ratios — always guard the divisor
df['debt_to_income'] = \
    df['debt'] / (df['income'] + 1)
df['spend_per_day'] = \
    df['amount'] / (df['days'] + 1)

# products & differences
df['price_x_qty'] = df['price']*df['qty']
df['balance_change'] = \
    df['end'] - df['start']

# safe divide
df['r'] = np.where(df['den'] > 0,
    df['num']/df['den'], 0)
Feature importance debt/income spend/day debt income the ratio out-ranks its raw parts
Section 04

Polynomial Features — Let Lines Bend

A straight line can't fit a U — degree-2 can linear ✗ degree-2 polynomial ✓
poly = PolynomialFeatures(degree=2)
# age, income → +age², age·income, income²
Pipeline([
  ('scaler', StandardScaler()),   # FIRST
  ('poly', PolynomialFeatures(2)),
  ('model', Ridge(alpha=1.0))])   # not OLS!
🧨
Scale first, then Ridge

Expanding unscaled values gives astronomical x² terms and numerical chaos. And poly terms are always correlated by construction — use Ridge/Lasso, never plain OLS.

Section 05

Date/Time & Cyclical Encoding

A delivery model on raw Unix timestamps missed that Friday drops take 40% longer. Extracting is_friday, day_of_week and hour cut RMSE from 4.2 to 1.8 hours.

Raw hour — 23 & 0 look far apart ✗ 0h 23h "distance = 23" — but they're 1 hour apart! sin/cos on a circle — they sit adjacent ✓ 0h 23h 6h 12h 18h
df['hour_sin'] = np.sin(2*np.pi*df['hour']/24);  df['hour_cos'] = np.cos(2*np.pi*df['hour']/24)
df['is_weekend'] = (df['order_date'].dt.dayofweek >= 5).astype(int)
Section 06

Binning — Equal-Width vs Equal-Frequency

pd.cut — equal width skew → some bins nearly empty pd.qcut — equal frequency every bin holds equal data
df['age_grp']  = pd.cut(df['age'], bins=[0,25,35,45,55,100], labels=['18-25','26-35','36-45','46-55','55+'])
df['inc_q']    = pd.qcut(df['income'], q=4, labels=['Q1','Q2','Q3','Q4'])   # better for skew
Section 07

Aggregation — Signals a Single Row Can't See

# customer-level stats → merge back
agg = df.groupby('customer_id').agg(
  avg_spend=('amount', 'mean'),
  order_count=('order_id', 'count'),
  return_rate=('is_returned', 'mean'),
).reset_index()
df = df.merge(agg, on='customer_id')

# rolling window (time series)
df['roll_30d'] = (df.groupby('customer_id')
   ['amount'].transform(
     lambda x: x.rolling(30,
       min_periods=1).mean()))
📊
Context beats the single transaction

A customer's average spend, order count and return rate say far more about their next action than any one order. Aggregations inject that history into every row.

🚧
Aggregate on train only

Compute group stats on the training set, then merge onto test with those same stats — computing on the full data leaks the future into the past.

Section 08

Domain Features — Encoding Expertise

DomainRawEngineeredWhy it works
Creditdebt, incomedebt / incomeAffordability — the standard risk metric
E-commercespend, visitsspend / visitsValue per engagement → premium behaviour
Healthcareweight, heightweight / height²BMI — an established medical indicator
Retaillast_purchase, todaydays_since_lastRecency — the strongest repeat-purchase signal
Telecomcalls, plan_limitcalls / limit × 100Utilisation % → predicts upsell & churn
Financeassets, liabilitiesassets / liabilitiesCurrent ratio — standard liquidity metric
🎓
Every field has its "hidden" ratio

These aren't clever tricks — they're the numbers domain experts already trust. Encoding them hands the model decades of accumulated professional judgment for free.

Section 09

Then — and Only Then — Scale

ScalerFormulaRangeBest for
MinMax(x−min)/(max−min)[0, 1]Neural nets, image data
Standard(x−μ)/σμ=0, σ=1Linear models, SVM, PCA — the default
Robust(x−Q2)/IQRmedian-centredLegitimate outliers present
MaxAbsx/|max|[−1, 1]Sparse data, TF-IDF (keeps zeros)
🔢
The non-negotiable order

clean → engineer → encode → scale → select. Scaling must come after engineering so your ratios, powers and aggregations all end up on a comparable footing before the model ever sees them.

Section 10 · Impact

Where the Accuracy Actually Comes From

Model accuracy as you add each stage Raw only + Engineeringbiggest jump + Scaling+distance/gradient Treeseng helps, scale n/a
🚀
Engineering is the highest-leverage step

The largest jump comes from engineering, especially for linear models. Scaling then adds more for distance- and gradient-based algorithms. Trees skip the scaling gain but still love the new features.

Section 10 · Pipeline

One Pipeline: Engineer → Scale → Model

class FeatureEngineer(BaseEstimator,
                      TransformerMixin):
  def fit(self, X, y=None): return self
  def transform(self, X):
    X = X.copy()
    X['debt_to_income'] = X.debt/(X.income+1)
    X['hour_sin'] = np.sin(2*np.pi*X.hour/24)
    return X

full = Pipeline([
  ('engineer', FeatureEngineer()),
  ('prep',     preprocessor),   # std/robust/mm/ohe
  ('model',    GradientBoostingClassifier())])
full.fit(X_train, y_train)
joblib.dump(full, 'fe_pipeline.pkl')
X_train (raw) FeatureEngineerratios · dates · cyclical ColumnTransformerStandard · Robust · MinMax · OneHot GradientBoosting → ŷ joblib.dump(pipeline)
Section 11

The Hidden Danger — Multicollinearity

When income "caused" more defaults
A 0.84-AUC loan model failed audit: its income coefficient read −2.3 — higher income, more default? The cause was multicollinearity — annual_income had a VIF over 45 from correlating with debt_to_income and income_sq, making the coefficients mathematically unstable. Dropping the twins and using Ridge flipped it to a sane +1.4.
VIF 10 income_sq48.2 debt/inc31.6 income18.0 BEFORE income_sq3.1 debt/inc2.4 income2.1 AFTER FIX
Section 11 · Impact

Who Multicollinearity Hurts

AlgorithmHarmed?Fix
Linear / Logistic RegressionseverelyDrop features or use Ridge/L2
Ridge / LassopartlyAlready mitigated — Lasso auto-selects
KNNyesDrop duplicated-signal features
SVMmildlyApply PCA before SVM
Decision Tree / RF / XGBoostnoNothing needed — splits ignore it
Neural NetworkmildlyDrop correlated pairs (faster convergence)
📏
Read the VIF like a traffic light

VIF < 5 acceptable · 5–10 investigate · > 10 serious multicollinearity. It answers "how well do the other features predict this one?" — high means redundant.

Section 11 · Fixes

Four Ways to Fix It

✂️
Drop a twin
Of each >0.85 pair, keep the one more correlated with the target.
🧊
Ridge (L2)
Penalises coefficient size, stabilising them without dropping features.
🧭
PCA
Compress correlated features into uncorrelated components (n_components=0.95).
🎫
drop='first'
Fixes the one-hot dummy trap where all N columns sum to 1.
🧬
Lasso (L1)
Auto-selects one of a correlated pair and zeros the other.
🌳
…or use trees
Random Forest / XGBoost are immune — no fix required at all.
📌
Polynomials are collinear by construction

Any PolynomialFeatures(degree≥2) produces terms correlated by maths — never follow it with plain OLS. Always Ridge or Lasso.

Section 12 · Part 1

The Golden Rules — 1 to 5

🛠️ FEATURE ENGINEERING · RULES 1–5
1
Engineer before scaling. Scale first and your combinations become dimensionless and lose all meaning.
2
Start with domain knowledge. Ask which ratios an expert mentally computes — that's your best feature list.
3
Guard every divisornum / (den + 1) or np.where(den>0, …) — one zero can poison a column.
4
Cyclical-encode time with sin/cos so 23:00 sits next to 00:00, not at the far end of a line.
5
Scale then expand. StandardScaler → PolynomialFeatures, never the reverse — and never OLS after.
Section 12 · Part 2

The Golden Rules — 6 to 9 & Takeaway

🛠️ FEATURE ENGINEERING · RULES 6–9
6
qcut over cut for skew. Equal-frequency bins stop 80% of the data piling into one bucket.
7
Aggregate on train only, then merge to test — group stats from the full set leak the target.
8
Wrap engineering in a transformer (BaseEstimator + TransformerMixin) so it replays identically at inference.
9
Validate every feature — check its distribution and target correlation, and watch VIF for collinearity you just created.
🎯
Better features beat better models

The ₹18-crore unlock came from three features, not a new architecture. Feature engineering — where domain knowledge, creativity and maths meet — is the highest-leverage step in the whole workflow. Invest there first.

🛠️ End of tutorial · Press to review, or click Restart