특성 선택: 분산 임계값과 SelectKBest
학습자는 분산이 거의 0인 특성을 제거한 다음, 일변량 통계 검정으로 남은 특성의 순위를 매기고 정보량이 가장 큰 상위 K개만 유지합니다.
특성 선택: 분산 임계값과 SelectKBest은(는) CoddyKit의 무료 Machine Learning Academy 강의입니다. 이것은 4개 중 3번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Machine Learning Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Machine Learning Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
이 강의의 일부는 아직 번역되지 않았으며 영어로 표시됩니다.
Why Remove Features?
Adding more features is not always better. Irrelevant features add noise without signal, increasing the risk of overfitting, slowing training, and wasting memory. Redundant features provide duplicate information and can destabilise some models. Feature selection identifies and removes these unhelpful inputs, leaving a compact set of informative features. The result: faster training, lower memory usage, reduced overfitting, and often better generalisation — especially for models without built-in regularisation like KNN or Naive Bayes.
Variance Threshold: Remove Near-Constant Features
VarianceThreshold removes features whose variance falls below a specified threshold. A feature with zero variance is constant — it has the same value for every example and therefore provides no discriminative information. Near-constant features (very low variance) are almost as uninformative. Setting threshold=0 removes only perfectly constant features; threshold=0.01 removes any feature where 99%+ of values are the same. This is a fast, model-agnostic first pass at cleaning the feature set.
from sklearn.feature_selection import VarianceThreshold
import numpy as np
# Create feature matrix with some constant/near-constant columns
X = np.array([
[1, 2, 1, 5], # col 3: near constant (mostly 1)
[2, 4, 1, 3],
[3, 6, 1, 4],
[4, 8, 2, 7], # col 3 varied
[5, 10, 1, 2]
], dtype=float)
print('Column variances:', X.var(axis=0).round(2))
vt = VarianceThreshold(threshold=0.5) # remove columns with variance < 0.5
X_filtered = vt.fit_transform(X)
print('Features kept:', vt.get_support())
print('X shape before:', X.shape, '-> after:', X_filtered.shape)Applying Variance Threshold to Real Data
Variance threshold is especially useful after one-hot encoding, when some categories may have very few examples (producing a near-zero-variance binary column) or when working with genomics, text, or sensor data where most features are near-zero. Set the threshold based on the expected proportion of zeros: if 95% of values are zero, the variance is at most 0.95 × 0.05 = 0.0475, so threshold=0.05 removes any feature that is at least 95% constant.
from sklearn.feature_selection import VarianceThreshold
from sklearn.datasets import load_breast_cancer
import numpy as np
X, y = load_breast_cancer(return_X_y=True)
print('Original n_features:', X.shape[1])
vt = VarianceThreshold(threshold=10.0) # remove low-variance features
X_filtered = vt.fit_transform(X)
print('After threshold=10.0, n_features:', X_filtered.shape[1])
print('Removed features:', (~vt.get_support()).sum())SelectKBest: Rank by Statistical Test
SelectKBest evaluates each feature independently using a univariate statistical test and keeps the top K features. For classification: use chi2 (chi-squared, for non-negative features) or f_classif (ANOVA F-statistic). For regression: use f_regression (linear correlation) or mutual_info_regression. The tests score how much each feature individually correlates with the target. Setting k='all' ranks all features by score rather than selecting a fixed number.
from sklearn.feature_selection import SelectKBest, f_classif
from sklearn.datasets import load_breast_cancer
import numpy as np
X, y = load_breast_cancer(return_X_y=True)
skb = SelectKBest(score_func=f_classif, k=10)
X_new = skb.fit_transform(X, y)
print('Original shape:', X.shape)
print('After SelectKBest(k=10):', X_new.shape)
print('Top feature mask:', skb.get_support())
scores = skb.scores_
top5_idx = np.argsort(scores)[::-1][:5]
print('Top 5 feature indices:', top5_idx)
print('Top 5 F-scores:', np.round(scores[top5_idx], 2))Mutual Information: Non-Linear Scoring
The F-test in f_classif only detects linear relationships between features and target. Mutual information (mutual_info_classif, mutual_info_regression) measures any statistical dependence — linear or non-linear. A feature with a non-linear relationship to the target will score zero with F-test but high with mutual information. Mutual information is slower to compute but more informative, especially for tree-based models where non-linear relationships matter.
from sklearn.feature_selection import SelectKBest, mutual_info_classif, f_classif
from sklearn.datasets import load_breast_cancer
import numpy as np
X, y = load_breast_cancer(return_X_y=True)
feature_names = load_breast_cancer().feature_names
# Compare F-test and mutual information rankings
f_scores = f_classif(X, y)[0]
mi_scores = mutual_info_classif(X, y, random_state=42)
import pandas as pd
df = pd.DataFrame({'feature': feature_names, 'f_score': f_scores, 'mi_score': mi_scores})
print('Top 5 by F-test:'); print(df.sort_values('f_score', ascending=False).head(5)['feature'].values)
print('Top 5 by MI: '); print(df.sort_values('mi_score', ascending=False).head(5)['feature'].values)Selecting K: Cross-Validation Over Feature Counts
How many features should you keep? The right way to choose K is to treat it as a hyperparameter and find the value that maximises cross-validation score. Use SelectKBest inside a Pipeline and add selectkbest__k to your grid search parameters. This avoids the common mistake of selecting K based on training performance (which always improves with more features) and instead finds the K that maximises generalisation.
from sklearn.feature_selection import SelectKBest, f_classif
from sklearn.linear_model import LogisticRegression
from sklearn.pipeline import Pipeline
from sklearn.model_selection import GridSearchCV
from sklearn.datasets import load_breast_cancer
X, y = load_breast_cancer(return_X_y=True)
pipe = Pipeline([('sel', SelectKBest(f_classif)), ('clf', LogisticRegression(max_iter=1000))])
param_grid = {'sel__k': [5, 10, 15, 20, 30]}
grid = GridSearchCV(pipe, param_grid, cv=5)
grid.fit(X, y)
print('Best k:', grid.best_params_['sel__k'])
print('Best CV score:', round(grid.best_score_, 4))SelectPercentile: Relative Feature Selection
SelectPercentile is a sibling of SelectKBest that keeps the top percentile% of features rather than a fixed count K. This is more robust when the number of features varies across datasets or when applying the same pipeline to different problems. For example, SelectPercentile(f_classif, percentile=20) keeps the best 20% of features regardless of how many there are. The trade-off: you get a relative budget rather than an absolute count.
from sklearn.feature_selection import SelectPercentile, f_classif
from sklearn.datasets import load_breast_cancer
X, y = load_breast_cancer(return_X_y=True)
for pct in [20, 50, 80]:
sel = SelectPercentile(f_classif, percentile=pct)
X_new = sel.fit_transform(X, y)
print(f'percentile={pct}: kept {X_new.shape[1]} of {X.shape[1]} features')Feature Selection vs Regularisation
Feature selection and regularisation are complementary but different approaches. Feature selection explicitly removes features before training, producing a sparser model with fewer inputs. Regularisation (L1/L2 penalty) keeps all features but shrinks unimportant coefficients toward zero — L1 (Lasso) even produces exact zeros. Feature selection is explicit and interpretable; regularisation is continuous and keeps more information. For interpretability, explicit feature selection is preferred. For predictive power, regularisation often wins by making soft, data-driven importance decisions.
Limitation: Features Are Not Independent
The key limitation of univariate selection (VarianceThreshold, SelectKBest) is that it evaluates each feature independently. A feature that has no marginal correlation with the target might still be very useful in combination with another feature (interaction). Two redundant features might each score high individually but add no value beyond the first one. These methods cannot detect such dependencies. Recursive Feature Elimination (RFECV), covered in the next lesson, addresses this by letting the model itself rank features based on their combined predictive contribution.
Practical Workflow for Feature Selection
A recommended feature selection workflow: (1) Start with VarianceThreshold to remove constant and near-constant features; (2) apply SelectKBest with mutual information for a quick ranking of remaining features; (3) plot CV score vs K to find the elbow; (4) incorporate the selected features in a full pipeline with cross-validation; (5) if the model has built-in importance (tree-based), use permutation importance for a second-pass check. Always embed selection inside a Pipeline to prevent leakage.
from sklearn.feature_selection import VarianceThreshold, SelectKBest, f_classif
from sklearn.ensemble import RandomForestClassifier
from sklearn.pipeline import Pipeline
from sklearn.model_selection import cross_val_score
from sklearn.datasets import load_breast_cancer
X, y = load_breast_cancer(return_X_y=True)
pipe = Pipeline([
('vt', VarianceThreshold(threshold=0.1)), # step 1
('sel', SelectKBest(f_classif, k=15)), # step 2
('clf', RandomForestClassifier(n_estimators=100, random_state=42))
])
scores = cross_val_score(pipe, X, y, cv=5)
print('Pipeline CV score:', round(scores.mean(), 4))SelectFromModel: Let the Model Decide
SelectFromModel uses a trained model's feature importances (or coefficients) to select features above a threshold. After fitting a random forest or Lasso, pass it to SelectFromModel with a threshold such as 'mean' (keep features with importance above the mean) or 'median'. This is especially useful as a pipeline step before a secondary estimator — it embeds the importance-based selection directly into the cross-validation loop, preventing leakage.
from sklearn.feature_selection import SelectFromModel
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import cross_val_score
from sklearn.pipeline import Pipeline
X, y = load_breast_cancer(return_X_y=True)
pipe = Pipeline([
('sel', SelectFromModel(RandomForestClassifier(n_estimators=50, random_state=42), threshold='mean')),
('clf', RandomForestClassifier(n_estimators=100, random_state=42))
])
scores = cross_val_score(pipe, X, y, cv=5)
print('SelectFromModel CV:', round(scores.mean(), 4))Quick Check
Test your understanding of VarianceThreshold and SelectKBest from this lesson.
Lesson Recap
In this lesson you learned: VarianceThreshold removes constant and near-constant features as a fast first pass, SelectKBest ranks features by univariate tests (F-test or mutual information) and keeps the top K, and always embed feature selection inside a Pipeline and cross-validate K as a hyperparameter. Next up we explore Recursive Feature Elimination with Cross-Validation (RFECV), which lets the model itself vote out the least useful features.
자주 묻는 질문
“특성 선택: 분산 임계값과 SelectKBest” 강의는 무료인가요?
네 — “특성 선택: 분산 임계값과 SelectKBest” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Machine Learning Academy 강의 전체를 잠금 해제할 수 있습니다. Machine Learning Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
“특성 선택: 분산 임계값과 SelectKBest”에서 뭘 배우나요?
학습자는 분산이 거의 0인 특성을 제거한 다음, 일변량 통계 검정으로 남은 특성의 순위를 매기고 정보량이 가장 큰 상위 K개만 유지합니다. 브라우저에서 직접 실행하는 실습 코드로 Machine Learning Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.
Machine Learning Academy을(를) 시작하는 데 경험이 필요한가요?
사전 경험은 필요하지 않습니다. CoddyKit의 Machine Learning Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 3번째 강의입니다.
“특성 선택: 분산 임계값과 SelectKBest” 강의는 얼마나 걸리나요?
대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.
이 Machine Learning Academy 강의에서 코드를 작성하고 실행할 수 있나요?
네. 모든 Machine Learning Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.
이 강의의 모든 강의
- 새 특성 만들기: 로그 변환, 구간화 및 상호작용
- 날짜 및 시간 특성 추출
- 특성 선택: 분산 임계값과 SelectKBest
- 교차 검증을 활용한 재귀적 특성 제거