Univariate Feature Selection with f_classif and f_regression
Univariate feature selection scores each feature separately against the target using a statistical test such as f_classif or f_regression, then discards features whose p-values are too high.
Why Fewer Columns Can Help
Many real datasets come with far more input columns than a model can comfortably use. Some of those columns carry useful information about what you want to predict. Others are noise: values that vary randomly and have no real connection to the target. Feature selection is the family of techniques for deciding which columns to keep before a model is trained on them.
This article focuses on one simple approach available in scikit-learn. A univariate method scores each feature, SelectPercentile turns those scores into a keep-or-drop decision based on a fixed share of the columns, and you then check the result. Keep one question in mind as you read: if you were told to keep half of a set of columns, what would you use to decide which half is worth keeping?
Scoring Each Feature on Its Own
Univariate feature selection scores each feature separately against the target using a statistical test such as f_classif or f_regression, then discards features whose p-values are too high.
The word univariate means one variable at a time. Every column is tested against the target separately, without asking how it interacts with the other columns. The result of each test is a p-value. A high p-value means the feature is unlikely to be related to the target, so it becomes a candidate for removal. A low p-value means the feature looks related to the target and is more likely to be kept.
The method needs two decisions. First, you choose a statistical test. The default for classification is f_classif, and f_regression is the matching choice for regression. Second, you choose a rule for discarding features based on the p-values that test produces. Every discarding rule uses a threshold, and the methods differ in how they compute that threshold.
Read the diagram as a single feature's journey. The feature is never compared with its neighbours at this stage. Its own p-value alone decides whether it is a candidate for removal, and the threshold set by the discarding rule determines where the line falls.
What do you think happens?
A feature gets a p-value of 0.8 against the target. Is it kept or discarded?
Reveal answer
Discarded
A high p-value means the feature is unlikely to be related to the target, so it becomes a candidate for removal. Features whose p-values are too high are removed by the discarding rule.
Keeping a Fixed Percentage with SelectPercentile
The two simplest discarding rules differ only in how the size of the kept set is specified. SelectKBest selects a fixed number k of features, so you say how many columns survive no matter how many columns the dataset has. SelectPercentile selects a fixed percentage of features, so you say what share of the columns survives and the count adjusts automatically as the dataset grows or shrinks.
The usage pattern has three steps. First, you create the selector with a percentile. The percentile argument is a number from 0 to 100 that sets the share of features to keep; 50 means half of the features. Second, you fit the selector on training data so that it can score the features against the training targets. Third, you transform the training data, which keeps only the selected columns.
Notice that fit uses the training targets, so the selector learns which features to keep from training data only. The same fitted selector is then used to transform the test data, so the model sees exactly the same columns it was trained on. Fitting on the training split alone is what keeps the test set honest.
Working out how many features SelectPercentile keeps
A dataset has 10 input features. You create SelectPercentile with a percentile of 20 and keep the top-ranked share. How many features survive, and which ones?
- 1Count the inputs
There are 10 features before selection.
- 2Apply the percentage
20 percent of 10 features is 2 features. The count is set by the share, so it scales with the width of the dataset.
- 3Rank by score
Each feature has already been scored alone against the training target. Sort the features from strongest to weakest score.
- 4Keep the top share
Keep the 2 highest-scoring features and discard the other 8.
Two features survive. In the diagram these are Feature 3 and Feature 7, which were the top-ranked features in this made-up scoring. If the same pipeline later received 40 features, the same 20 percent setting would keep 8 features without any change to the code.
Reading the Boolean Mask
Transforming the data tells you how many features survived, but not which ones. The get_support method answers the second question. It returns a Boolean mask: an array with one True or False value per original feature. True marks a feature that was kept, and False marks a feature that was removed.
The position of each entry in the mask corresponds to the position of that feature in the original input. The mask is therefore a direct map from original column positions to keep-or-drop decisions. Its length always equals the number of input columns, not the number that survived.
Reading a six-feature mask
The mask returned by get_support is True, False, True, True, False, False. Which original features were kept?
- 1Pair each entry with a position
Entry 0 belongs to position 0, entry 1 to position 1, and so on up to position 5.
- 2Find the True entries
The True values sit at positions 0, 2 and 3.
- 3Find the False entries
The False values sit at positions 1, 4 and 5, which were removed.
- 4Map to names if you need them
Use the same positions to look up the original column names in your own dataset, since the mask itself stores only True or False.
Features at positions 0, 2 and 3 were kept, and features at positions 1, 4 and 5 were dropped.
A larger illustration uses a breast cancer dataset with 30 real features. Fifty columns of random noise are appended, so the input has 80 columns in total. Running SelectPercentile with percentile 50 keeps about half of them. The mask is then plotted as a single horizontal strip of 80 cells, in order, with black for True and white for False.
Reading that strip across, most of the original 30 features appear black, meaning kept, while most of the 50 noise columns appear white, meaning removed. The recovery is not perfect: some real features were dropped and some noise columns were kept. The strip is a visual reading aid, so when you need exact positions, go back to the Boolean mask values themselves.
Does Removing Features Improve a Model?
Removing features only matters if the model performs as well or better afterward, so the check has to be made explicitly. In the walkthrough, logistic regression is trained twice on the same train-test split: once on all features and once on only the selected features. Both models are then scored on the test set.
In that synthetic example the reduced feature set scored slightly higher. Removing the noise columns improved performance even though some genuine features were lost along the way. The walkthrough itself warns that this was a very simple synthetic setup and that results on real data are usually mixed.
Univariate selection remains useful in two situations. The first is when there are so many features that building a model on all of them is infeasible. The second is when you suspect that many features are completely uninformative. Outside those situations, the benefit is uncertain, and it can be small or absent.
| Question | SelectKBest | SelectPercentile |
|---|---|---|
| What you specify | A fixed count k of features | A fixed percentage from 0 to 100 |
| Size when the dataset grows | Stays the same | Grows with the number of inputs |
| Best fit | A downstream limit on input columns | One pipeline that handles inputs of different widths |
Two discarding rules that share the same scoring step but differ in how the kept set is sized
Where Judging Features One at a Time Goes Wrong
Because each feature is judged alone, the method can miss features that matter only in combination with other features. Two columns that are weak individually may be strong together, but the univariate test never asks how they interact. This is a limit of the method's design, not a bug in any one setting.
Common mistake Fitting the selector on the full dataset before splitting it
What it looks likeCalling fit on all rows, then splitting into training and test sets
Why it failsThe test rows influence which features are kept, so the test score is no longer an honest estimate.
Do this insteadSplit the data first, fit the selector on the training split only, and transform both splits with that fitted selector.
Common mistake Assuming the mask lists feature names
What it looks likeReading the mask as if it stores column names
Why it failsThe mask holds only True or False values, one per original position.
Do this insteadPair each mask entry with its original position and look up the names in your own column list.
Common mistake Treating a fixed percentage as a fixed number of columns
What it looks likeExpecting 20 percent to keep the same count for every dataset
Why it failsA percentage scales with the number of inputs, so the count changes as the width changes.
Do this insteadCompute the expected count from the actual number of input columns, or use SelectKBest if you need a fixed count.
Common mistake Discarding a feature because its individual p-value is high
Why it failsA feature weak alone may matter in combination with another feature, and the univariate test cannot see that interaction.
Do this insteadCheck the decision against the final model's performance rather than trusting the individual p-value alone.
Testing Your Reading of a Mask
A dataset has six input columns named age, income, zip_code, height, noise_1 and noise_2, in that order. After running SelectPercentile, get_support returns True, True, False, False, True, False. Which columns were kept, and which were dropped?
Hints
- Pair each mask entry with its position first, starting from position 0.
- The True entries are at positions 0, 1 and 4. Look up those positions in the column list.
- Check your answer: kept columns are age, income and noise_1; dropped columns are
zip_code, height and noise_2.
Key Takeaways for Using Univariate Selection
- 1Univariate feature selection tests each feature against the target on its own and removes features whose p-values are too high.
- 2SelectPercentile keeps a fixed share of the features, while SelectKBest keeps a fixed count.
- 3
get_supportreturns a Boolean mask with one entry per original feature, and its positions map directly onto the input columns. - 4Fit the selector on training data only, then transform both splits, and judge the benefit by comparing model performance rather than trusting one score.
- 5Selection helps most when the feature count is very large or many features are likely uninformative, and its benefit is uncertain on other data.
At a glance
- Univariate feature selection tests each feature against the target on its own and removes features whose p-values are too high.
- SelectPercentile keeps a fixed share of the features, while SelectKBest keeps a fixed count.
get_supportreturns a Boolean mask with one entry per original feature, and its positions map directly onto the input columns.- Fit the selector on training data only, then transform both splits, and judge the benefit by comparing model performance rather than trusting one score.
- Selection helps most when the feature count is very large or many features are likely uninformative, and its benefit is uncertain on other data.