learn-feature-engineering-with-phoebe / Practitioner session 8 of 10
Learn Feature Engineering with Phoebe · Practitioner track · Session 8 of 10

Selection + importance

Seven sessions of building features, and tonight you take some away. Two honest warnings up front. First, selection is oversold: on our own ladder it moved held-out AUC from 0.812 to 0.813, so what it really buys is simplicity, stability and serving cost. Second, the tool most teams use to decide what to cut - the feature importances a tree hands you for free - is documented by sklearn as "strongly biased", and biased in a direction that will point you straight at the wrong column. Tonight: the selection methods, the importance that lies, the importance that does not, and the moment Lumen's session_hour finally gets retired on evidence.

🟠 Practitioner track DS · analysts · ML engineers Python · live workbench on key pages 45 min
0-3 · Welcome 3-18 · Selection methods 18-42 · Build-along: importance that does not lie 42-45 · Q&A
Part 1 · covers Google "Rules of Machine Learning" #21 and #22

Why remove features at all 7 min live

Adding a column feels free. It is not, and Google's Rules of ML say why in two sentences. Rule 21: "The number of feature weights you can learn in a linear model is roughly proportional to the amount of data you have." Rule 22: "Clean up features you are no longer using." Your data budget is finite, and every weight you spend on a column that carries nothing is a weight you did not spend on one that does.

LiveThe honest number, before anyone oversells this4 min▶

Look back at the ladder you climbed in b1. Selection is the last rung, and it is the smallest one on the board:

  • + Interactions: held-out AUC 0.812
  • + Selection: held-out AUC 0.813

One thousandth. That is the accuracy case for feature selection on this dataset, and stating it plainly is the point - most courses quietly imply selection is a performance technique. It usually is not. What it actually buys is worth more than a decimal place:

  • Simplicity. Fewer columns to explain, review, and defend when someone asks why the model did that.
  • Stability. Fewer weights spread across noise means less variance between retrains, and less sensitivity to a shift in a column nobody is watching.
  • Serving cost. Every feature in the model is a feature that must be computed, joined, monitored and kept alive at prediction time. A column you dropped is a pipeline you never have to fix at 2am.

Frame it that way with your team and the conversation improves immediately: you stop arguing about a thousandth of AUC and start arguing about how many things you want to keep running.

Self-studyFeature debt is real debt3 min read▶

Rule 22 is a maintenance rule, not a modelling one. An unused feature still has an owner, an upstream job, a schema, a backfill, and an on-call rotation attached to it. It still breaks. It still shows up in the incident channel. And because nobody remembers whether the model uses it, nobody dares delete it.

The cheapest moment to remove a feature is the moment you can show it earns nothing. That is what the rest of this session is about: producing evidence solid enough that the deletion happens.

Part 2 · covers sklearn "Feature selection" (1.13) + Kaggle Learn lesson 2, mutual information

The methods, and what each one costs 8 min live

Five families in sklearn, in rough order of cost. Read the last column hardest - each method has a specific way of misleading you, and none of them is "it removes the wrong feature at random".

MethodHow it decidesCostWatch out
VarianceThreshold Drops features that barely vary at all Trivial - no model, no target Ignores the target entirely. For Bernoulli features, to remove those that are one value in more than 80% of samples, set threshold = .8 * (1 - .8) = 0.16
SelectKBest / SelectPercentile Scores each feature against the target with chi2, f_classif or mutual_info_classif Cheap - one pass per feature Univariate, so it cannot see combinations. And sklearn's own warning: "Beware not to use a regression scoring function with a classification problem, you will get useless results"
RFE / RFECV Fits the model, drops the weakest features, repeats. RFECV cross-validates the number to keep Expensive - many refits Needs a model that exposes coef_ or feature_importances_, and inherits that model's biases
SelectFromModel Keeps features whose learned coefficient or importance clears a threshold One fit With L1, a smaller C or a larger alpha means fewer features kept. With trees, you inherit the impurity bias in Part 3
SequentialFeatureSelector Adds (or removes) one feature at a time, keeping whatever most improves cross-validated score The most expensive of the five sklearn: "SFS differs from RFE and SelectFromModel in that it does not require the underlying model to expose a coef_ or feature_importances_ attribute. It may however be slower"
LiveMutual information, and why it beats correlation5 min▶

Kaggle Learn's definition is the one to carry around: mutual information is "a measure of the extent to which knowledge of one quantity reduces uncertainty about the other." It is the first thing to reach for on a new dataset, because it answers "which columns are worth my attention this afternoon" without fitting anything.

It beats correlation for a specific reason, stated plainly in the same lesson: "correlation only detects linear relationships." A U-shaped relationship, a threshold effect, a category that matters only at the extremes - correlation reports roughly zero for all of them. Mutual information does not.

The scale: minimum 0.0, meaning the two quantities are independent, and no fixed maximum - though "values above 2.0 or so are uncommon", so treat a score above 2 as a reason to check for leakage rather than a reason to celebrate.

Its three caveats, verbatim - read them before you trust a ranking "MI can't detect interactions between features. It is a univariate metric." · "The actual usefulness of a feature depends on the model you use it with." · "Just because a feature has a high MI score doesn't mean your model will be able to do anything with that information."
Reading a mutual information score, and where to stop trusting it 0.0 1.0 2.0 3.0 0.0 means independent - knowing one tells you nothing above 2.0 is uncommon - check for leakage THE THREE CAVEATS, VERBATIM MI cannot detect interactions between features. It is univariate usefulness depends on the model you use it with a high score does not mean your model can use it Mutual information measures how much knowing one quantity reduces uncertainty about the other. Correlation only detects linear relationships. Mutual information has no such limit.
🔍 Click to zoom - a ranking worth an afternoon, not a pruning decision

The first caveat is the one that bites in this course specifically. In b6 you built interactions - relationships that no single column carries. A univariate metric is structurally blind to exactly those. If you had used mutual information to prune before building interactions, you would have deleted the ingredients.

Self-studyPicking a scoring function without wasting an afternoon3 min read▶
  • Classification: chi2 (non-negative features only), f_classif (linear dependency), mutual_info_classif (any dependency, slower).
  • Regression: f_regression, mutual_info_regression.
  • The mistake sklearn bothers to warn about: crossing the two lists. "Beware not to use a regression scoring function with a classification problem, you will get useless results." Nothing raises an error - you simply get a ranking that means nothing, which is worse.
Part 3 · covers sklearn "Permutation feature importance" (5.2)

Importance that lies, and importance that does not ★ 12 min · everyone runs it

Fit a tree, print feature_importances_, sort descending, screenshot it for the deck. It is the single most common feature-analysis move in applied machine learning, and sklearn's own documentation describes it as "strongly biased". Not approximate. Not noisy. Biased, in a direction you can predict.

One model, two rankings IMPURITY IMPORTANCE read off the trained tree customer_id (high cardinality) rank 1 prior_30d_spend rank 2 postal_code rank 3 session_hour near nothing PERMUTATION IMPORTANCE measured on the held-out set prior_30d_spend rank 1 new_vs_returning rank 2 customer_id (high cardinality) zero on unseen rows session_hour zero here too The id looks strongest on training data and is worth nothing on rows the model never saw.
🔍 Click to zoom - the same model, ranked by what it memorised and by what it actually uses
LiveWhat impurity importance is biased towards5 min▶

sklearn's warning, verbatim, is worth reading in full because every clause does work:

Impurity-based importances "favor high cardinality features (typically numerical features) over low cardinality features such as binary features or categorical variables with a small number of possible categories", and "can give high importance to features that may not be predictive on unseen data when the model is overfitting."

The mechanism is simple once you see it. A column with thousands of distinct values offers thousands of possible split points, so it will almost always find some split that reduces impurity on the training rows. It looks powerful because it is flexible, not because it is predictive. Meanwhile a genuinely useful binary flag gets one split point and one shot, and finishes lower down the list.

That is why a customer id, a raw timestamp, or a high-cardinality postal code so often floats to the top of an importance chart that then gets pasted into a slide.

The alternative, in sklearn's words: permutation importance "avoids this issue, since it can be computed on unseen data." Shuffle one column, re-score, and measure how much the score falls. If the model was genuinely relying on the column, breaking it hurts. If the model was memorising, breaking it changes nothing on rows it never saw.

LiveCompute it on the held-out set, and read both4 min▶

Permutation importance can be computed on training data or on held-out data, and comparing the two is a diagnostic in its own right. sklearn states the rule verbatim: "Features that are important on the training set but not on the held-out set might cause the model to overfit."

from sklearn.inspection import permutation_importance

r = permutation_importance(
    pipe, X_test, y_test,            # held-out rows, never the training rows
    n_repeats=30, random_state=42, scoring="roc_auc")

for i in r.importances_mean.argsort()[::-1]:
    if r.importances_mean[i] - 2 * r.importances_std[i] > 0:
        print(f"{feature_names[i]:<24} "
              f"{r.importances_mean[i]:.3f} +/- {r.importances_std[i]:.3f}")

n_repeats is what turns a single shuffle into an estimate with a spread. Without it you cannot tell a real drop from a lucky permutation, and the filter above - keep only features whose mean importance clears two standard deviations - is the cheapest way to stop yourself reading noise as a ranking.

The meta-warning, verbatim - pin this above the importance chart "Permutation importance does not reflect the intrinsic predictive value of a feature by itself but how important this feature is for a particular model." A feature that is unimportant to your current model may be very important to a better one. You are measuring a relationship, not a property of the column.
LiveThe correlated-feature trap3 min▶

Permutation importance has one failure mode you will meet on real tabular data, and it is easy to walk into. If two features are strongly correlated, permuting one leaves the model its correlate to fall back on. The score barely moves. Do the same to the other, and the score barely moves again. Both report low importance, and both are actually load-bearing.

Drop them both on that evidence and the score collapses, which is a confusing afternoon.

The correlated-feature trap in permutation importance 1 · shuffle A A shuffled B intact the model falls back on B score barely moves A looks unimportant B is still there to carry it 2 · shuffle B A intact B shuffled the model falls back on A score barely moves B looks unimportant A is still there to carry it 3 · drop both A gone B gone nothing is left to fall back on the score collapses both were load-bearing a confusing afternoon the fix: cluster the correlated features first, keep one representative per cluster, then read importance Permuting one leaves the model its correlate to fall back on, so the score barely moves.
🔍 Click to zoom - two low scores can both be wrong at the same time

The fix is mechanical: cluster the correlated features first - a hierarchical clustering on the correlation matrix does it - and keep one representative per cluster before you interpret any importance number. You are then measuring the cluster's contribution, which is the thing you actually wanted to know.

Part 4 · covers sklearn's Pipeline guidance for selection + the Lumen canon

Retiring session_hour, on evidence 6 min live

Lumen's session_hour has been sitting in this case since the intro-ML course, where it was seeded as deliberate near-useless noise. It has been suspected ever since. Tonight it gets retired properly - not because someone had a hunch, but because permutation importance on held-out data puts it at zero and stands behind the number.

The suspicion. The intro-ML course exposed session_hour as noise, but exposure is not evidence anyone can act on. "We think this column does nothing" does not survive contact with the person who built the pipeline that produces it.

The evidence. Permutation importance on the held-out set: shuffling session_hour does not move the score, because the model was never relying on it for rows it had not seen. That is a measurable, reproducible, defensible zero.

The decision. Drop it. Held-out AUC goes 0.812 to 0.813 - a rounding error in accuracy terms, and a real win in every other term: one fewer column to compute, join, monitor and break.

Where the selection step lives. Inside the Pipeline, always. sklearn is explicit: "Feature selection is usually used as a pre-processing step before doing the actual learning. The recommended way to do this in scikit-learn is to use a Pipeline."

Real world

Selection outside cross-validation is the leakage you already met. In b5 you saw sklearn's own worked example: feature selection fitted on all the data before splitting scored 0.76 accuracy on completely random noise, where the honest pipeline scored 0.50 and 0.43 +/- 0.05 under cross-validation. Selection is a fit. It learns which columns to keep from the target, and if it learns that from rows that end up in your test set, your test set is no longer a test. This is the single most common way a competent team ships a model that was never as good as the notebook said.

Self-studyAn order of operations that holds up4 min read▶
  1. Split first, before anything else touches the data.
  2. Explore with mutual information on the training rows only - to decide where to spend your afternoon, not to prune.
  3. Build features, including the interactions from b6, before any univariate pruning. Univariate metrics cannot see combinations, so pruning first deletes the ingredients.
  4. Put the selector inside the Pipeline, so it re-fits within every cross-validation fold.
  5. Judge with permutation importance on held-out data, with n_repeats, after clustering correlated features.
  6. Delete the column for real - Rule 22 - and delete the pipeline that produced it too, or you have kept the cost and lost the benefit.
Demo · the last rung of the ladder

Watch selection earn its thousandth ★ 8 min · everyone runs it

The workbench opens with the four honest feature groups you built in b1 to b6 already on: numerics, encoding, datetime and interactions. Read the held-out score, then switch on Selection and read it again. This is the smallest move in the whole course, and the one that most needs explaining honestly.

Numerics, encoding, datetime and interactions on. Press Score on held-out: 0.812. This is the model you have earned so far.

Switch on Selection and score again: 0.813. One thousandth of AUC. If you were expecting the chart to jump, that expectation is exactly what this session exists to correct.

What the workbench's selection step actually did: it dropped session_hour, the deliberate noise column. The score barely moved because the column carried nothing - which is the confirmation, not the disappointment.

Now say why you would still ship it. One fewer column to compute at prediction time, one fewer upstream job to keep alive, one fewer thing to monitor, one fewer thing to break. Accuracy is not the case for selection. Operations is.

How to read this one Every number here is computed live in your browser: 3,000 Lumen sessions, a shuffled 60/40 split, logistic regression by gradient descent. The data is synthetic; the model, the split and the AUC are real. A gain this small is a real result, honestly reported - and reporting it honestly is more useful to your team than a bigger number would be.
Homework

Try it yourself - this week ◐ 30-40 min total

Source material

Official sources covered

This session works through sklearn's feature-selection chapter and its permutation-importance page in full, plus Kaggle Learn's mutual-information lesson and the two Rules of ML that make the case for removing features at all. Certificates and graded exercises stay with the official providers (Kaggle Learn, Google MLCC). This page covers:

✓sklearn "Feature selection" (1.13) - the five method familiesPart 2 · VarianceThreshold through SequentialFeatureSelector, with the scoring-function warning
✓sklearn "Permutation feature importance" (5.2)Part 3 · the impurity bias, the held-out rule, the meta-warning, correlated features
✓Kaggle Learn "Feature Engineering" lesson 2 - Mutual InformationPart 2 · the definition, the 0.0 to ~2.0 scale, and all three caveats
◐Google "Rules of Machine Learning" - #21 and #22Part 1 · the data budget and feature debt · the rest of the doctrine is b1 and a4
✓fe-live workbench canon - the selection rungDemo · 0.812 to 0.813, dropping session_hour, computed live
Check yourself

Three questions before you go 🎯 ◐ 90 seconds

1 · Your tree's feature_importances_ puts a customer id column at the top. What does sklearn's documentation say is going on?

Thousands of distinct values means thousands of candidate split points, so the column will almost always find something that reduces impurity on the training rows. Permutation importance "avoids this issue, since it can be computed on unseen data" - and on unseen data the id is worth nothing.

2 · You rank features by mutual information and prune the bottom half before building anything. What have you risked?

MI is genuinely better than correlation, which "only detects linear relationships" - but it scores one column at a time. Two features that mean little alone and a great deal together both look droppable. Build your interactions before you prune.

3 · Why does the selection step have to sit inside the Pipeline?

Selection is a fit like any other. sklearn's recommendation is direct: "Feature selection is usually used as a pre-processing step before doing the actual learning. The recommended way to do this in scikit-learn is to use a Pipeline." Inside it, each fold selects from its own training rows.

Practitioner session 8 cheat sheet · pin this

The honest caseSelection moved held-out AUC 0.812 to 0.813. It buys simplicity, stability and serving cost - not accuracy. Say so out loud.
Rules 21 and 22Feature weights you can learn are "roughly proportional to the amount of data you have" · "Clean up features you are no longer using."
VarianceThreshold mathBernoulli features that are one value in more than 80% of samples: threshold = .8 * (1 - .8) = 0.16.
Scoring-function warning"Beware not to use a regression scoring function with a classification problem, you will get useless results." No error is raised.
SFS vs RFESFS "does not require the underlying model to expose a coef_ or feature_importances_ attribute. It may however be slower."
Mutual information"Knowledge of one quantity reduces uncertainty about the other." Beats correlation, which "only detects linear relationships." Min 0.0; above 2.0 is uncommon. Univariate - blind to interactions.
Impurity importance lies"Strongly biased" toward high-cardinality features; can rate features highly that "may not be predictive on unseen data when the model is overfitting."
Permutation importanceCompute on held-out, with n_repeats. It measures importance "for a particular model", not intrinsic value. Cluster correlated features first, or both look useless.