More features are not more information. As dimensionality grows, data becomes sparse, distances lose their meaning, and models that rely on locality — KNN above all — degrade badly. This chapter opens with that problem, the curse of dimensionality, and then develops the first family of answers: choosing a subset of the features you already have.
We cover filter methods, which score features independently of any model using statistical tests — variance threshold, chi-square, ANOVA F-test, — and then wrapper methods, which judge a feature subset by the performance of an actual trained model. Forward selection and backward elimination illustrate the trade-off: wrappers capture feature interactions that filters cannot see, but pay for it with a combinatorial search. The companion chapter takes the other route, constructing new features rather than selecting old ones — for example, combining height and weight into a single new feature, BMI, rather than just picking one of the two original columns. Feature selection, by contrast, always keeps the original variables intact; it only decides which ones to keep.
Adding more features to a dataset is not free. Beyond a certain point extra features stop helping, and for distance-based methods such as KNN they actively cause problems, for reasons that are geometric rather than statistical.
Given additional features that are pure noise (no relation to target):
Consider the following concrete example. All features are uniformly distributed over [0, 1]. We want to classify a query at X = 0.6 using the 10% nearest neighbors rule (use only training samples whose features all fall within ±5% of the feature range, i.e., 10% of the axis length):
| p (dimensions) | Fraction of data covered | Data you need for 10 observations in neighborhood |
|---|---|---|
| p = 1 | 10% (0.1) | 100 rows |
| p = 2 | 1% (0.01) | 1,000 rows |
| p = 3 | 0.1% (0.001) | 10,000 rows |
| p = 10 | 0.00000001% | 10 billion rows |
Takeaway: In high dimensions, the local 10% neighborhood is essentially the entire dataset. There is no concept of "nearby." The distance between any two randomly chosen points becomes approximately the same constant. KNN's core assumption — that nearby points share a label — fails catastrophically.
In high dimensions, everyone is your neighbor... and no one is.
The curse of dimensionality tells us that too many features cause problems, so the natural response is to keep only a useful subset of them. We first state that task precisely.
Given a feature matrix \(X \in \mathbb{R}^{n \times d}\) with \(n\) samples and \(d\) features, and target variable \(y \in \mathbb{R}^n\), our goal is to select a subset \(S \subseteq \{1, 2, ..., d\}\) such that features in \(S\) are most predictive of \(y\).
Exponential Search Space: There are \(2^d\) possible subsets of \(d\) features. For \(d = 30\) this gives \(2^{30} = 1,073,741,824\) subsets, so evaluating every subset is not computationally feasible. Practical methods therefore search this space in a restricted way.
Because exhaustive search is impossible, practical methods fall into two families that differ in how they judge a feature. Filter methods score each feature with a statistical test, independently of any model. Wrapper methods judge a subset by training a model on it and measuring how well it performs.
| Characteristic | Filter Methods | Wrapper Methods |
|---|---|---|
| Timing | Preprocessing step, independent of ML algorithm | "Wraps" around a specific ML algorithm |
| Evaluation | Statistical measures (correlation, chi-square) | Actual model performance (cross-validation) |
| Speed | Fast and scalable | Slower but more accurate |
| Model Dependence | Algorithm-agnostic | Tailored to specific algorithm |
Note: A third category called "Embedded Methods" (e.g., LASSO, Random Forest feature importance) exists where feature selection happens during model training.
All filter methods share the same three-step procedure, and they differ only in the statistical score used in the first step:
The simplest filter method removes features with very low variance:
Important: Standardization or normalization is required before applying variance threshold so that the same threshold works for all features. A threshold between 0.01 and 0.1 is generally effective.
from sklearn.feature_selection import VarianceThreshold
selector = VarianceThreshold(threshold=0.01)
X_selected = selector.fit_transform(X)The Chi-Square test measures the association between one input column and one output column. Both columns must be categorical. For example, is there a relationship between the "Gender" column and the "Education" column? The contingency table (also called a "crosstab") below shows the frequency of each combination of values between the two columns:
| Female | Male | |
|---|---|---|
| Without graduation | 6 | 7 |
| College | 13 | 16 |
| Bachelor's degree | 16 | 15 |
| Master's degree | 8 | 11 |
| Total | 43 | 49 |
Where \(c\) is the degree of freedom, \(O_i\) is the observed frequency, and \(E_i\) is the expected frequency in cell \(i\).
The expected frequency is computed as:
from sklearn.feature_selection import SelectKBest, chi2
# Method 1: Select top-k features
selector = SelectKBest(score_func=chi2, k=5)
X_selected = selector.fit_transform(X_categorical, y)
# Method 2: Select features above threshold
selector_threshold = SelectKBest(score_func=chi2, k='all')
selector_threshold.fit(X_categorical, y)
# Filter by p-value threshold
significant_features = selector_threshold.pvalues_ < 0.05
X_significant = X_categorical.iloc[:, significant_features]ANOVA (Analysis of Variance) is used when:
Where \(K\) = number of classes, \(N\) = total samples.
Higher F-statistic indicates greater difference between class means, making the feature more informative.
from sklearn.feature_selection import SelectKBest, f_classif
# Apply ANOVA F-test to all numerical features
selector = SelectKBest(score_func=f_classif, k=5)
X_selected = selector.fit_transform(X_numerical, y)
# Get F-scores and p-values
f_scores = selector.scores_
p_values = selector.pvalues_
The four filter methods above apply to different combinations of feature and target type. The table below summarises when each one is appropriate.
| Method | Target Type | Feature Type | Captures Non-linear | Model-agnostic |
|---|---|---|---|---|
| Variance Threshold | Any | Any | No | Yes |
| Correlation | Continuous | Continuous | No | Yes |
| Chi-Square | Categorical | Categorical | No | Yes |
| ANOVA F-test | Categorical | Continuous | No | Yes |
Filter methods score each feature on its own, so they cannot see that two features are useful only in combination. Wrapper methods address this by evaluating whole subsets.
Wrapper methods use a predictive model to evaluate feature subsets, using model performance as the selection criterion.
Common wrapper methods:
Forward Selection is a greedy algorithm that builds the feature set incrementally:
Backward Selection is the reverse of Forward Selection:
The computational cost of filter vs. wrapper methods:
| Method | Complexity | Description | Example (100 features) |
|---|---|---|---|
| Filter Methods | O(d) | Evaluate each feature independently | 100 evaluations |
| Wrapper Methods | O(d²) | Must evaluate feature combinations | ~5050 evaluations (50× more expensive) |
Note: This analysis focuses on the combinatorial search complexity and doesn't account for the varying computational costs of different filter methods (chi-square vs. ANOVA) or ML algorithms (linear regression vs. KNN vs. random forest) used in wrapper methods.
Having seen both families in detail, we can now summarise the trade-off between them:
| Aspect | Filter | Wrapper |
|---|---|---|
| Speed | ✅ Fast | ❌ Slow |
| Model Involvement | ❌ No (Algorithm Independent) | ✅ Yes (Algorithm Specific) |
| Captures Feature Interaction | ❌ No | ✅ Yes |
| Evaluation | Statistical (e.g., Chi-Square, ANOVA) | CV Performance |
| Examples | Chi-Square, ANOVA | Forward/Backward Selection, RFE |
| Overfitting Risk | ✅ Low | ❌ High |
Problem: For \(d = 3, 4,\) and \(5\) features, how many possible subsets exist? List all subsets for \(d = 3\).
For \(d = 3\) with features \(\{A, B, C\}\):
Dataset: Examining the relationship between "Income Level" (Low, Medium, High) and "Subscription Status" (Subscribed, Not Subscribed).
| Income Level | Subscribed (O) | Not Subscribed (O) | Row Total |
|---|---|---|---|
| Low | 20 | 30 | 50 |
| Medium | 40 | 25 | 65 |
| High | 10 | 15 | 25 |
| Column Total | 70 | 70 | 140 |
Expected Values:
Uniform data on [0,1]^p. You want to capture a 5% neighborhood along each axis so you look at points that fall in [x − 0.025, x + 0.025] on every axis.
(a) Coverage fraction = (0.05)^p.
(b) Required dataset size N = 50 / coverage:
This is exactly why feature reduction (selection + extraction: Units 7–8) is mandatory before KNN on wide data.
Consider a dataset with 5 features and the following evaluation metrics:
Final selected features: {F1, F3, F2, F5}
Final selected features: {F1, F5}
Using the contingency table from Example 2, compute the Chi-Square statistic and determine if Income Level is a significant predictor of Subscription Status at \(\alpha = 0.05\).
Step 1: State Hypotheses
Step 2: Calculate Expected Frequencies
| Income Level | Subscribed (E) | Not Subscribed (E) |
|---|---|---|
| Low | 25 | 25 |
| Medium | 32.5 | 32.5 |
| High | 12.5 | 12.5 |
Formula: \(E_{ij} = \frac{\text{Row}_i \times \text{Column}_j}{\text{Grand Total}}\)
Step 3: Compute Chi-Square Statistic
Total: \(\chi^2 = 6.462\)
Step 4: Determine Degrees of Freedom and Critical Value
Critical value at \(\alpha = 0.05\), \(df = 2\): 5.991
Step 5: Conclusion
Since \(6.462 > 5.991\), we reject H\(_0\).
Conclusion: There is a significant association between Income Level and Subscription Status. This feature would be selected by the Chi-Square filter method. Higher \(\chi^2\) values indicate a stronger feature-target relationship.
Consider a dataset with 4 features and the following evaluation metrics when adding features one by one:
| Step | Features Added | Accuracy | Feature Selected |
|---|---|---|---|
| 1 | {} | 0.60 | - |
| 2 | {F1} | 0.75 | F1 |
| 3 | {F1, F3} | 0.82 | F3 |
| 4 | {F1, F3, F2} | 0.85 | F2 |
| 5 | {F1, F3, F2, F4} | 0.84 | F4 |
Selected features: {F1, F3, F2}
Reasoning:
You run KNN on 3 different feature subsets of a 500-row dataset, getting 10-fold CV accuracy of 89% using p=4 features; 85% using p=40 features; and 72% using p=400 features. The true information content is actually contained in those 4 features.
(a) Curse of Dimensionality on KNN. As feature count grows, the extra 36 (and then 396) noise dimensions inflate distances between every pair of points, swamping the useful signal in the first 4 dimensions. KNN cannot tell "true nearby" from "randomly close on noise axes."
(b) Distances become less discriminative uniformly — the ratio of (nearest neighbor distance / farthest neighbor distance) → 1 in high dimensions. More and more of the K nearest neighbors are actually of the wrong class because label structure doesn't correlate with the noise dimensions at all.
(c) Recovery menu: (i) Filter feature selection / ANOVA / MI to prune dimensions. (ii) Wrapper selection (forward/backward — this chapter). (iii) PCA extraction (Chapter 6) onto a low-dim subspace before KNN. (iv) Switch classifier to Random Forest which ignores noise features (doesn't fix KNN but sidesteps the curse for the modeling step).
You have 4 features with the following variances after standardization: A=0.15, B=0.003, C=0.08, D=0.001. If you apply VarianceThreshold with threshold=0.01, which features will be selected?
Features with variance >= 0.01 are selected:
Selected features: A and C
You compute ANOVA F-statistics for three features predicting a binary target:
Using \(\alpha = 0.05\), which features are significant? Rank them by importance.
Compare each p-value to \(\alpha = 0.05\):
Ranking by F-statistic (higher = more important):
For each scenario, identify the most appropriate filter method:
You have 5 features (F1-F5) and the following accuracy improvements when adding features:
| Current Features | Add F1 | Add F2 | Add F3 | Add F4 | Add F5 |
|---|---|---|---|---|---|
| {} | 0.65 | 0.70 | 0.75 | 0.60 | 0.68 |
| {F3} | 0.82 | 0.78 | - | 0.80 | 0.79 |
| {F3, F1} | - | 0.88 | - | 0.85 | 0.86 |
Task: Which features would be selected using forward selection with a stopping rule of maximum 3 features?
Using the same dataset as Problem 5, the accuracies when removing features from the full set are:
| Current Features | Remove F1 | Remove F2 | Remove F3 | Remove F4 | Remove F5 |
|---|---|---|---|---|---|
| {F1,F2,F3,F4,F5} | 0.84 | 0.80 | 0.75 | 0.86 | 0.85 |
| {F1,F2,F3,F5} | 0.83 | 0.79 | 0.74 | - | 0.84 |
| {F1,F2,F3,F5} | 0.82 | 0.78 | 0.73 | - | - |
Task: Which features would be selected using backward selection with a stopping rule of minimum 3 features?
p = 100 features, each uniform on [0,1]. To make a prediction at a query, KNN(k=100) on a dataset of n = 100,000 rows considers 100 nearest neighbors among 100,000. For each feature independently, what's the average local "fraction" of the feature axis that those 100 neighbors span? (Approximate: treat each axis independently, assume 100 neighbors span ~ 100/100,000 = 0.1% of the order statistics on a single axis.)
Order-statistics approximation: on any 1-D axis, the 100 nearest neighbors span roughly a fraction 100/100,000 = 0.1% of the axis length on average. So the neighborhood per feature is 0.1% of the axis. Hypercube volume fraction = (0.001)^100 = 10⁻³⁰⁰. That's far more extreme than the number of atoms in the observable universe (~10⁸⁰). In other words, even with 100k rows, in 100 dimensions the 100 "nearest" neighbors are NOT local in any meaningful sense — they are scattered across essentially the entire range of every feature. KNN's local-structure assumption collapses.
Answer all 8 questions. Click an option for instant feedback.
Your score: 0 / 8