Feature Engineering
Transform raw columns into powerful model inputs. Log transforms, interaction features, target encoding, cyclical encodings, embeddings, and the techniques that consistently beat model tuning.
The model doesn't see your data. It sees the numbers you give it. Make those numbers count.
A linear regression predicting delivery time from distance_km will give you one set of numbers. The same linear regression predicting from log(distance_km) will give you significantly better numbers — because delivery time grows sub-linearly with distance (the first kilometre adds more time per km than the fifth kilometre). Same model. Different representation. Better result.
This is the core idea of feature engineering: transforming raw columns into representations that better match the mathematical assumptions of the model. Tree-based models (Random Forest, XGBoost) are robust to raw features but still benefit from interaction features and target encoding. Linear models need transformations to handle skew and non-linearity. Neural networks benefit from normalisation and embedding representations for categoricals.
In competitive ML (Kaggle, production systems), feature engineering is consistently the highest-leverage activity. The top solution in most Kaggle competitions uses a standard model on engineered features — not a novel architecture on raw data. This module teaches every major technique with working code on the DoorDash dataset.
What this module covers:
Load the clean DoorDash dataset
Log, sqrt, Box-Cox and scaling — fix skewed distributions
Most real-world numeric features are right-skewed — a few very large values drag the mean far above the median. Linear models assume features are roughly normally distributed. When a feature is heavily skewed, a log transform makes the distribution more symmetric and often produces a dramatically better linear model.
The intuition: delivery time does not increase linearly with distance. Going from 1km to 2km adds more time than going from 9km to 10km (because acceleration, traffic signals, and restaurant location all make short distances disproportionately slow). log(distance) captures this diminishing relationship much better than raw distance.
Products, ratios and differences — capture combined effects
An interaction feature combines two existing features into one that captures their joint effect. Distance and traffic separately each explain some variance in delivery time. But distance × traffic captures the combined effect — a long distance in high traffic is much worse than either alone. Linear models cannot discover this relationship without an explicit interaction term. Tree models can, but having it explicit speeds up and improves learning.
Binning — discretise continuous variables into categories
Binning converts a continuous variable into discrete buckets. This sounds like losing information — and sometimes it is. But for linear models, binning can capture non-linear step-function relationships that a linear term cannot. For tree models, binning pre-computes splits the tree would find anyway, sometimes speeding up training significantly on high-cardinality features.
Datetime feature engineering — extract every signal from a timestamp
A raw timestamp is useless to an ML model. But the features you extract from it — hour of day, day of week, whether it's a holiday, days since the last order — are often among the most predictive features in the whole dataset. Delivery time varies dramatically by hour. Restaurant prep time varies by day of week. Order value varies by time slot. The timestamp encodes all of this, but only if you extract it.
Encoding strategies — from one-hot to target encoding
Categorical columns cannot go into an ML model as strings. They must be converted to numbers. There are many ways to do this, and the choice matters significantly for model performance. One-hot encoding is safest but creates sparse high-dimensional representations. Target encoding is compact and informative but requires careful implementation to avoid leakage.
One-hot encoding — safe, sparse, standard
Target encoding — the most powerful, most dangerous technique
Target encoding replaces each category value with the mean of the target variable for that category. "Pizza Hut" becomes 36.4 (its mean delivery time in the training set). This is extremely informative and produces compact, powerful features. It is also the most dangerous encoding technique — naive implementation directly leaks the target into the features, causing massive overfitting that looks great in cross-validation but collapses in production.
Frequency encoding — fast, leakage-safe, surprisingly effective
Aggregate features — group statistics that make each row context-aware
A single order's distance of 5km tells the model less than knowing that this order is 2km longer than the average order to this restaurant. Aggregate features add context by computing statistics within groups — per restaurant, per city, per time slot — and attaching them to each row. These are among the most consistently powerful features across all ML problems.
Feature selection — remove what doesn't help
More features is not always better. Irrelevant features add noise, slow down training, and can hurt generalisation. Feature selection identifies which features contribute meaningful signal and removes those that don't. There are three families of methods, each with different tradeoffs.
Feature leakage — the most dangerous mistake in ML
Feature leakage occurs when information about the target variable leaks into the features during training. The model learns a shortcut — it can "predict" the target because the feature contains the answer, not because it has learned the underlying pattern. Evaluation metrics look impossibly good. Then the model ships to production where the future isn't available, and performance collapses.
Leakage is not always obvious. The most common forms are subtle and require discipline to prevent consistently.
Feature stores — reuse features across models
In a production ML system, the same features are used by multiple models. The "restaurant average delivery time" feature might be used by the ETA prediction model, the fraud model, and the restaurant ranking model. Computing it three times independently wastes compute and introduces inconsistencies. A feature store computes features once, stores them, and serves them to any model that needs them.
Every common feature engineering error — explained and fixed
How feature engineering actually happens on a team — feature stores, reuse, and ownership
The SimpleFeatureStore built earlier in this module is a toy, but the problem it solves is entirely real. Once a company has more than one model — an ETA model, a fraud model, a restaurant ranking model — several of them end up wanting the exact same underlying signal: "how does this restaurant typically perform." Without a shared feature store, three teams independently write three slightly different versions of a restaurant average delivery time feature, computed on three different time windows, with three different null-handling choices. When the fraud model and the ETA model disagree about a restaurant's risk profile, nobody can tell whether that is a real signal or just three inconsistent implementations of what was supposed to be the same feature.
Production feature stores — Feast, Tecton, Hopsworks, or a company's internal equivalent — solve a harder version of the problem this module's SimpleFeatureStore only gestures at: keeping an offline store (used for training, computed in batch over historical data) and an online store (used for real-time serving, needing sub-10-millisecond lookups) consistent with each other. A feature computed one way during training and a slightly different way during serving — "training-serving skew" — is one of the most common causes of a model that performs well offline and poorly in production, and it is exactly the kind of bug that a shared, versioned feature definition is designed to prevent.
On a mature ML team, a feature group like restaurant_features from this module's example has a named owner responsible for its correctness, its freshness SLA, and reviewing changes to its definition — the same way a shared library has a maintainer. A model team that wants a new feature typically requests it from that owner or contributes the definition through a review process, rather than quietly recomputing a slightly different version inside their own training script. That discipline is what makes "reuse across models" actually work in practice, rather than becoming another source of silent inconsistency.
Five things people get wrong about feature engineering
This is roughly true for images, audio, and raw text, where deep networks learn their own representations from pixels or tokens and hand-crafted features actively get in the way. It is not true for tabular data of the kind this entire module works with. Gradient boosted trees and well-engineered features on structured columns — distance, order value, restaurant history — still consistently beat deep networks on tabular problems in both research benchmarks and industry practice, because tabular columns do not have the spatial or sequential structure that makes deep learning's automatic feature learning so effective in the first place. The "no feature engineering needed" claim is domain-specific, not universal.
Every additional feature adds a dimension a model can overfit to, particularly with a fixed amount of training data — this is exactly why the feature selection section of this module exists. A weakly correlated or purely noisy feature can degrade a linear model's generalisation, slow down training, and in high dimensions actively hurt distance-based methods through the curse of dimensionality. Polynomial feature expansion makes this concrete: going from 50 to 200 input columns under degree-2 polynomial features produces over 20,000 output features, most of which add nothing but noise and compute cost.
The single highest-leverage feature in this module's DoorDash example — distance times traffic times prep time as a combined "slow delivery" indicator — did not come from a statistical test. It came from understanding, as a person who has ordered food delivery, that these three factors compound rather than add. The statistical techniques in this module (log transforms, target encoding, aggregate statistics) are the mechanism for expressing a domain insight as a number a model can use — they are not a substitute for having the insight in the first place. The best feature engineers on any team are usually the ones who understand the business as well as they understand pandas.
Storage is the easy 10 percent. The hard problems a real feature store solves are keeping an offline batch computation and an online real-time lookup numerically consistent for the same feature, guaranteeing point-in-time correctness so training features never leak information from after the historical moment they represent, and tracking freshness and ownership across dozens of feature groups shared by multiple teams. A plain database table with extra columns solves none of these — it is the same problem the SimpleFeatureStore in this module intentionally simplifies away for teaching purposes.
A cross-validation improvement is necessary but not sufficient — the leakage section of this module exists precisely because a feature can look like a genuine improvement in CV while actually encoding information that will not exist at prediction time in production. A feature derived from a groupby aggregate that was computed on the full dataset instead of training folds only, or a feature that is a proxy for the target because of how it was defined, both inflate CV scores while quietly guaranteeing the model will underperform once deployed. A CV improvement should prompt an audit of exactly how the feature was computed, not an automatic green light to ship it.
Feature engineering — 5 questions interviewers actually ask
For tabular models like gradient boosted trees or linear models, feature engineering is where most of the modeling leverage actually lives — log transforms for skew, explicit interaction terms, target and frequency encoding for categoricals, and group aggregates all directly determine what the model can learn, since trees split on raw feature values and linear models can only combine features the way you hand them. For deep learning on unstructured data like images or text, the network learns its own internal representations from raw pixels or tokens, so hand-crafted features are less central — effort shifts toward architecture and representation learning instead. For deep learning on tabular data specifically, feature engineering still matters nearly as much as it does for trees, since the tabular structure itself does not give the network much to learn from automatically.
The rule I follow is: split the data first, then compute every statistic — means, target encodings, frequency counts, scaler parameters — using training data only, and apply those already-fitted statistics to validation and test data without recomputing them. For target encoding specifically, I use cross-fold encoding, where each training row's own target value is never used to compute its own encoded feature. For time series, I always shift before any rolling window computation and use temporal cross-validation instead of random KFold, since a feature computed with access to future rows is invisible leakage that will not surface until production. Wrapping all of this inside an sklearn Pipeline makes most of these mistakes structurally impossible rather than relying on discipline alone.
I add the feature and compare cross-validated performance against a baseline without it, using the same folds for both so the comparison is fair. If it helps, I check feature importance or permutation importance to confirm the model is actually using it rather than the improvement being noise from a different random seed. I also specifically audit how the feature was computed for leakage, since an implausibly large improvement is more often a leakage bug than a genuinely powerful feature. Only after both checks pass — a real, leakage-free improvement that the model is measurably relying on — would I consider the feature validated enough to ship.
I would start by identifying which features are genuinely shared — like per-restaurant or per-city aggregate statistics — versus features specific to a single model, and only put the shared ones into the store. Each feature group would have a named owner, a documented definition, and a freshness SLA, following exactly the registry pattern in this module's SimpleFeatureStore. The harder engineering problem I would prioritise early is offline and online consistency — making sure the batch computation used for training and the real-time lookup used for serving are guaranteed to produce the same value for the same feature, since inconsistency there causes training-serving skew that is very difficult to debug after the fact.
I would look for a growing gap between offline evaluation metrics and live production metrics as the first symptom — training-serving skew usually shows up exactly that way, since the model was validated against features computed one way but scores against features computed subtly differently. To find the specific feature, I would log feature values from both the training pipeline and the serving path for the same set of real requests and diff them directly, rather than guessing. The fix is almost always to consolidate both paths onto one shared feature definition — the same function or the same feature store computation — instead of maintaining parallel batch and real-time implementations that can silently drift apart from each other over time.
The data engineering section is complete. The data is ready. Now we build models.
Four modules. Collect data from APIs, SQL, files, and streams. Clean it — remove duplicates, fix types, handle outliers, validate schemas. Engineer features — log transforms, interactions, aggregates, target encoding. The result: a clean, feature-rich DataFrame ready for any ML algorithm.
Module 18 begins the Classical Machine Learning section with linear regression — the oldest, most interpretable, and still one of the most useful algorithms in production ML. Understanding linear regression deeply — not just calling LinearRegression().fit() — reveals the mathematical foundations that every subsequent algorithm (logistic regression, SVMs, neural networks) builds on.
Ordinary least squares, gradient descent, regularisation (Ridge, Lasso, ElasticNet), and how to diagnose and fix every failure mode — all on the DoorDash dataset.
🎯 Key Takeaways
- ✓Feature engineering consistently outperforms model tuning. The same Ridge regression on well-engineered features beats a Random Forest on raw features in many real problems. Invest in features before investing in model complexity.
- ✓Log-transform right-skewed positive columns (distances, prices, counts) before feeding to linear models. np.log1p(x) handles x=0 safely. Verify the transformation reduced skewness before assuming it helped.
- ✓Interaction features (distance × traffic, prep × traffic) capture joint effects that linear models cannot discover on their own. Always try the physically meaningful interactions first before exhaustive polynomial expansion.
- ✓Target encoding is powerful but dangerous. Never compute it on the full dataset. Always use cross-fold encoding: for each training row, compute the category mean using all other folds. Smooth rare categories toward the global mean.
- ✓Aggregate features (per-restaurant average delivery time, per-city late rate) make each row context-aware and are among the most consistently powerful features. Always compute them on training data only and apply via merge.
- ✓Leakage is the most dangerous mistake in ML. It makes evaluation metrics look great while the production model is broken. The rule: fit() only on X_train, transform() on everything. Use sklearn Pipeline to make leakage structurally impossible.
- ✓Feature stores prevent duplicate computation and inconsistency. Define features once, compute them centrally, serve them to any model. Even a simple Parquet-based store prevents the "which version of this feature was used?" debugging nightmare.
Discussion
0Have a better approach? Found something outdated? Share it — your knowledge helps everyone learning here.