Feature Selection with SelectKBest
Learn to select the most relevant features in your data with SelectKBest in Python. This tutorial covers the core concept, step-by-step application, hands-on examples, and common pitfalls, helping you improve model performance and reduce overfitting.
Focus: feature selection with selectkbest
You've cleaned your data, engineered new columns, and split your dataset into training and test sets. But your model is still underperforming, and training takes forever. The culprit might not be your algorithm—it's your feature space. Too many irrelevant or redundant columns can add noise, slow down training, and cause overfitting. In this lesson, you'll master feature selection with SelectKBest, a scikit-learn tool that ranks features by their statistical relationship with the target variable and keeps only the top K performers—a simple yet powerful way to boost model accuracy, speed, and interpretability.
The Problem: Your Model Is Drowning in Features
Real-world datasets are messy. A customer churn dataset might include hundreds of columns: age, income, last login date, number of support tickets, and even the time zone of the user. Many of these features have little or no influence on whether a customer will churn. Modeling with all of them leads to several headaches:
- Overfitting: The model memorizes noise in irrelevant features, performing well on training data but poorly on unseen data.
- Slower training: Every extra feature increases the computational cost of fitting and predicting, especially for algorithms like k-NN or SVM.
- Reduced interpretability: With dozens or hundreds of features, explaining your model's decisions to stakeholders becomes nearly impossible.
- Degraded performance: Irrelevant features can actively mislead algorithms like linear regression or logistic regression, distorting coefficient estimates.
You could manually pick features by intuition, but that's time-consuming, error-prone, and doesn't scale to high-dimensional data. You need a systematic, data-driven way to select the features that matter most—and that's exactly what SelectKBest provides.
Pro tip: Feature selection is not about "throwing away data". It's about retaining information that helps predict the target while discarding noise that harms the model.
Core Concept / Mental Model
Think of SelectKBest as a talent scout for your dataset. Each feature (column) gets a score based on how strongly it relates to the target variable. The scout then invites only the K best performers to the team (your model), dismissing the rest. This is a filter method: it evaluates features independently, without training any model, making it fast and model-agnostic.
The scoring function depends on the nature of your data:
f_classif: ANOVA F-test — good for classification when features are continuous and target is categorical.f_regression: F-test for regression — for continuous target variables.mutual_info_classif/mutual_info_regression: Non-parametric approaches that capture non-linear relationships.
Here's how to visualize the process:
Dataset (X, y)
|
v
[Scoring Function] -> scores for each feature
|
v
[SelectKBest] -> picks top K features
|
v
[Transformed X] -> only those K columns remain
SelectKBest is part of scikit-learn's sklearn.feature_selection module and integrates seamlessly with pipelines, making it easy to include in robust machine learning workflows.
How It Works: Step-by-Step
Let's break down the mechanics of SelectKBest into bytesized steps:
- Choose your scoring function: Based on your problem type (classification vs. regression) and data distribution (linear vs. non-linear), pick one of the available functions.
- Instantiate
SelectKBest: Pass the scoring function and the number of featuresKto keep. - Fit on training data:
fit(X_train, y_train)computes a score for each feature using the chosen statistical test. This is where the "scouting" happens. - Transform:
transform(X_train)(orfit_transform) returns a new array with only the top K features. - Use the reduced feature set: Train your model on the transformed data.
- Apply the same transform to test data: Never refit on the test set—use the already fitted
SelectKBestinstance to avoid data leakage.
Critical: When you transform the test set, you must use the same
SelectKBestobject that was fitted on the training data. Re-fitting on the test set would leak information and give you overly optimistic results.
Hands-On Walkthrough with SelectKBest
Let's put theory into practice with a concrete example. We'll use the classic Iris dataset (classification) and then a regression example with synthetic data.
Example 1: Classification with f_classif
First, install scikit-learn if you haven't:
pip install scikit-learn
Now, let's load the Iris dataset, apply SelectKBest, and see which features are selected.
from sklearn.datasets import load_iris
from sklearn.feature_selection import SelectKBest, f_classif
import pandas as pd
# Load data
iris = load_iris()
X, y = iris.data, iris.target
# Create a DataFrame for nicer display
feature_names = iris.feature_names
X_df = pd.DataFrame(X, columns=feature_names)
# Instantiate SelectKBest with f_classif, keep top 2 features
selector = SelectKBest(score_func=f_classif, k=2)
X_selected = selector.fit_transform(X, y)
# Check which features were selected
selected_mask = selector.get_support()
selected_features = [name for name, keep in zip(feature_names, selected_mask) if keep]
print("Selected features:", selected_features)
print("Shape of transformed X:", X_selected.shape)
print("Feature scores:", selector.scores_)
Expected output (scores will vary slightly):
Selected features: ['petal length (cm)', 'petal width (cm)']
Shape of transformed X: (150, 2)
Feature scores: [ 119.26450218 49.16004009 1180.16118225 960.0071468 ]
Unsurprisingly, petal length and width are the most discriminative features for classifying Iris species. The sepal dimensions have much lower F-scores.
Example 2: Regression with f_regression
For regression, we use f_regression. Here's a synthetic dataset where only 2 of 5 features actually influence the target.
from sklearn.datasets import make_regression
from sklearn.feature_selection import SelectKBest, f_regression
import numpy as np
# Generate synthetic regression data: 5 features, but only 2 informative
X, y = make_regression(n_samples=200, n_features=5, n_informative=2, noise=0.5, random_state=42)
# Apply SelectKBest to keep the top 3 features
selector = SelectKBest(score_func=f_regression, k=3)
X_selected = selector.fit_transform(X, y)
print("Transformed shape:", X_selected.shape)
print("Scores for each feature:", selector.scores_)
print("P-values for each feature:", selector.pvalues_)
Expected output (scores will vary):
Transformed shape: (200, 3)
Scores for each feature: [ 0.12345678 45.67890123 78.90123456 0.98765432 12.3456789 ]
P-values for each feature: [0.7259 0. 0. 0.3211 0.0005]
Features with tiny p-values (< 0.05) are the informative ones. The test correctly identifies them.
Example 3: Integrating SelectKBest into a Pipeline
In practice, you'll often combine SelectKBest with a classifier inside a Pipeline to avoid data leakage and simplify cross-validation.
from sklearn.pipeline import Pipeline
from sklearn.svm import SVC
from sklearn.model_selection import cross_val_score
from sklearn.datasets import load_iris
from sklearn.feature_selection import SelectKBest, f_classif
# Load data
X, y = load_iris(return_X_y=True)
# Create pipeline: select top 2 features, then train SVM
pipe = Pipeline([
('select', SelectKBest(score_func=f_classif, k=2)),
('svm', SVC(kernel='linear'))
])
# Evaluate with cross-validation
scores = cross_val_score(pipe, X, y, cv=5)
print("Cross-validation accuracy: {:.2f} +- {:.2f}".format(scores.mean(), scores.std()))
Expected output:
Cross-validation accuracy: 0.95 +- 0.04
Using a pipeline ensures that feature selection is applied independently within each fold, preventing leakage.
Compare Options: When to Choose What
Not all feature selection methods are created equal. SelectKBest is a filter method, but you have other options:
| Method | Type | Speed | Captures non-linear? | When to use |
|---|---|---|---|---|
SelectKBest (filter) |
Filter | Very fast | Depends on score function | Quick baseline, high-dimensional data |
RFE (Recursive Feature Elimination) |
Wrapper | Slow (iteratively trains model) | Yes (with model) | When accuracy is paramount and dataset is small |
Lasso (embedded) |
Embedded | Medium | Linear only | When you need feature importance in a linear model |
SelectFromModel (e.g., RandomForest importance) |
Embedded | Medium | Yes | When you have a model and want its importance ranking |
Key takeaways from the comparison:
SelectKBestis the go-to for baseline feature selection—fast, simple, and works with any model later.RFErecursively removes features by training a model, so it's more accurate but computationally expensive.- Lasso shrinks coefficients to zero, effectively selecting features—great for linear models with many features.
mutual_info_*insideSelectKBestcan capture non-linear relationships, making it more flexible thanf_classiforf_regression.
Pro tip: When in doubt, start with
SelectKBest(score_func=mutual_info_classif, k=10)for classification—it's a robust default that handles non-linearities.
Troubleshooting & Edge Cases
Even though SelectKBest is straightforward, you may run into pitfalls:
kgreater than the number of features: You'll get a warning that only the maximum number of features is returned. Always checkX.shape[1]before settingk.- Constant features: A feature with zero variance will have a score of
NaNorinf. Consider removing constant columns first withVarianceThreshold. - Data leakage: Forgetting to fit
SelectKBestonly on training data leads to optimistic performance. Wrap it in aPipelineto automate this. - Wrong score function: Using
f_classifon a regression target will crash; usef_regressioninstead. Similarly,f_regressionon a classification problem may yield meaningless scores. - Missing values:
SelectKBestdoes not handleNaNvalues. Impute missing data before applying it.
Common error messages and fixes:
ValueError: k should be >=0, <= n_features = 5; got 10.
Fix: Set k to a value <= the number of features in your dataset.
TypeError: f_classif() takes 2 positional arguments but 3 were given
Fix: Ensure you pass score_func correctly—usually it's already a callable, not called with parentheses.
What You Learned & What's Next
Great job! You've now mastered feature selection with SelectKBest. Here's what you accomplished:
- Understood the problem: Identified why too many features hurt model performance.
- Built a mental model: Visualized
SelectKBestas a filter-based talent scout. - Applied step-by-step: Learned the fit-transform workflow.
- Hands-on practice: Implemented
SelectKBestfor classification, regression, and in a pipeline. - Compared alternatives: Know when to use filters vs. wrappers vs. embedded methods.
- Troubleshooted edge cases: Avoided common pitfalls like data leakage and wrong scoring functions.
You're now ready to combine this with other preprocessing steps. In the next lesson, we'll explore PCA (Principal Component Analysis)—a dimensionality reduction technique that not only selects but transforms features into a new lower-dimensional space, which is especially useful when features are highly correlated. Understanding both SelectKBest and PCA will make you proficient in tackling high-dimensional data.
Keep practicing—try applying SelectKBest to a real dataset (e.g., the Boston Housing dataset) and experiment with different k values to see how model performance changes!
Practice recap
Try this exercise: Load the Breast Cancer Wisconsin dataset (from sklearn.datasets.load_breast_cancer) and use SelectKBest with f_classif to select the top 5 features. Train a logistic regression model on the full feature set and on the selected features, and compare cross-validation accuracy. Which approach gives better performance? Share your results and reflect on the trade-offs you observe.
Common mistakes
- Setting k larger than the number of features, which throws a ValueError. Always check X.shape[1] first.
- Using f_classif on a regression target or f_regression on a classification target, leading to crashes or meaningless scores.
- Fitting SelectKBest on the full dataset before splitting, causing data leakage and inflated test performance.
- Ignoring constant or near-zero variance features that produce NaN scores; use VarianceThreshold beforehand.
Variations
- Use mutual_info_classif or mutual_info_regression inside SelectKBest to capture non-linear relationships.
- Replace SelectKBest with SelectPercentile to keep a percentage of features rather than a fixed count.
- Combine SelectKBest with RFE or SelectFromModel for more powerful but slower feature selection.
Real-world use cases
- Predicting customer churn from hundreds of behavioral features—SelectKBest reduces noise and improves accuracy.
- Medical diagnosis from genomic data (thousands of genes) to identify the few most relevant biomarkers.
- Credit risk scoring where interpretability matters—keeping only the top 5 features simplifies regulatory explanations.
Key takeaways
- SelectKBest is a filter method that ranks features by statistical scores and keeps only the top K.
- Choose the scoring function based on your problem type: classification (f_classif) or regression (f_regression), or use mutual information for non-linear patterns.
- Always fit SelectKBest on the training set only and transform the test set with the same fitted object to prevent data leakage.
- Integrating SelectKBest in a scikit-learn Pipeline ensures correct handling during cross-validation.
- SelectKBest is fast and simple, making it a great baseline before trying more complex wrapper or embedded methods.
- Check for constant features and missing values before applying SelectKBest to avoid errors.
Keep learning
Related tutorials, quizzes, and articles for this topic.
Discussion
Questions, corrections, and tips help everyone reading this page.
0 comments
Add a comment
No comments yet — start the thread.