: 머신 러닝 알고리즘의 성능을 향상시키기 위해 데이터에 대한 도메인 지식을 활용하여 변수를 조합하거나 새로운 변수 만드는 과정
피쳐 추출(feature extraction)
: 피쳐들 간 내재한 특성이나 관계 분석해 이들을 잘 표현할 수 있는 새로운 선형/비선형 결합변수 만들어 데이터 줄이는 방법
: 고차원 피쳐 공간을 저차원 공간으로 투영
: PCA(주성분 분석), LDA(선형 판별 분석) 등
피쳐 선택(feature selection)
: 피쳐 중 타겟에 가장 관련성이 높은 피쳐만을 선정해 피쳐 수 줄이는 과정
: 모델 단순화, train 시간 축소, 차원의 저주 방지, 과적합(Overfitting) 문제를 줄여 일반화해주는 장점 존재
: filter, wrapper, embedded method
: 피쳐들 간 내재한 특성이나 관계 분석해 이들을 잘 표현할 수 있는 새로운 선형/비선형 결합변수 만들어 데이터 줄이는 방법


from sklearn import datasets
from sklearn.decomposition import PCA
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
iris = datasets.load_iris()
X = iris.data
y = iris.target
target_names = list(iris.target_names)
print(f"{X.shape = }, {y.shape = }")
print(f'{target_names = }')
X.shape = (150, 4), y.shape = (150,)
target_names = ['setosa', 'versicolor', 'virginica']
# PCA 객체 생성하고 차원은 2차원으로 설정(현재 4차원)
pca = PCA(n_components = 2)
pca_fitted = pca.fit(X)
print(f'{pca_fitted.components_ =}')
print(f'{pca_fitted.explained_variance_ratio_ = }')
X_pca = pca_fitted.transform(X) #주성분 벡터로 데이터 변환하기
print(f'{X_pca.shape = }')
pca_fitted.components_ =array([[ 0.36138659, -0.08452251, 0.85667061, 0.3582892 ],
[ 0.65658877, 0.73016143, -0.17337266, -0.07548102]])
pca_fitted.explained_variance_ratio_ = array([0.92461872, 0.05306648])
X_pca.shape = (150, 2)
lda = LinearDiscriminantAnalysis(n_components = 2)
lda_fitted = lda.fit(X, y)
print(f'{lda_fitted.coef_ = }')
print(f'{lda_fitted.explained_variance_ratio_ = }')
X_lda = lda_fitted.transform(X)
print(f'{X_lda.shape = }')
lda_fitted.coef_ = array([[ 6.31475846, 12.13931718, -16.94642465, -20.77005459],
[ -1.53119919, -4.37604348, 4.69566531, 3.06258539],
[ -4.78355927, -7.7632737 , 12.25075935, 17.7074692 ]])
lda_fitted.explained_variance_ratio_ = array([0.9912126, 0.0087874])
X_lda.shape = (150, 2)
import matplotlib.pyplot as plt
#PCA plotting
plt.figure()
colors = ['navy', 'turquoise', 'darkorange']
lw = 2
for color, i, target_name in zip(colors, [0, 1, 2], target_names):
plt.scatter(
X_pca[y == i, 0], X_pca[y == i, 1], color = color, alpha = 0.8, lw = lw, label = target_name
)
plt.legend(loc = 'best', shadow = False, scatterpoints = 1)
plt.title("PCA of IRIS dataset")
#LDA plotting
plt.figure()
for color, i, target_name in zip(colors, [0, 1, 2], target_names):
plt.scatter(
X_lda[y == i, 0], X_lda[y == i, 1], alpha = 0.8, color = color, label = target_name
)
plt.legend(loc = 'best', shadow = False, scatterpoints = 1)
plt.title("LDA of IRIS dataset")
plt.show()




📋 F-value
: 두 모집단의 분산의 비율
: ANOVA, regression에서는 모형이 설명하는 분산/잔차의 분산 --> F-value가 크면 모형이 잘 설명하고 있다
📋 상호정보량
: 하나의 확률변수가 다른 하나의 확률변수에 대해 제공하는 정보의 양
: 두 확률변수가 공유하는 엔트로피 --> 상관관계가 강할수록 상호정보량 커짐, 독립이라면 상호정보량 0
from sklearn import datasets
from sklearn.feature_selection import VarianceThreshold
iris = datasets.load_iris()
X = iris.data
y = iris.target
X_names = iris.feature_names
y_names = iris.target_names
#분산이 0.2 이상인 피쳐들만 선택하도록 학습
sel = VarianceThreshold(threshold = 0.2).fit(X)
print(f"{sel.variances_ = }")
#분산이 0.2 이상인 피쳐들만 선택 적용
X_selected = sel.transform(X)
X_selected_names = [X_names[i] for i in sel.get_support(indices = True)]
print(f"{X_selected_names = }")
print(f"{X_selected[:5] = }")
sel.variances_ = array([0.68112222, 0.18871289, 3.09550267, 0.57713289])
X_selected_names = ['sepal length (cm)', 'petal length (cm)', 'petal width (cm)']
X_selected[:5] = array([[5.1, 1.4, 0.2],
[4.9, 1.4, 0.2],
[4.7, 1.3, 0.2],
[4.6, 1.5, 0.2],
[5. , 1.4, 0.2]])
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import f_classif, f_regression, chi2
# K 개의 best feature 선택
####### f_classif
sel_cla = SelectKBest(f_classif, k = 2).fit(X, y)
print('f_classif : ')
print(f"{sel_cla.scores_ = }")
print(f"{sel_cla.pvalues_ = }")
print(f"{sel_cla.get_support() = }")
print("Selected features : ", [X_names[i] for i in sel_cla.get_support(indices=True)])
####### f_regression
sel_reg = SelectKBest(f_regression, k = 2).fit(X, y)
print("\nf_regression : ")
print(f"{sel_reg.scores_ = }")
print(f"{sel_reg.pvalues_ = }")
print(f"{sel_reg.get_support() = }")
print("Selected features : ", [X_names[i] for i in sel_reg.get_support(indices=True)])
####### chi2
sel_chi2 = SelectKBest(chi2, k = 2).fit(X, y)
print("\nchi2 : ")
print(f"{sel_chi2.scores_ = }")
print(f"{sel_chi2.pvalues_ = }")
print(f"{sel_chi2.get_support() = }")
print("Selected features : ", [X_names[i] for i in sel_chi2.get_support(indices=True)])
f_classif :
sel_cla.scores_ = array([ 119.26450218, 49.16004009, 1180.16118225, 960.0071468 ])
sel_cla.pvalues_ = array([1.66966919e-31, 4.49201713e-17, 2.85677661e-91, 4.16944584e-85])
sel_cla.get_support() = array([False, False, True, True])
Selected features : ['petal length (cm)', 'petal width (cm)']
f_regression :
sel_reg.scores_ = array([ 233.8389959 , 32.93720748, 1341.93578461, 1592.82421036])
sel_reg.pvalues_ = array([2.89047835e-32, 5.20156326e-08, 4.20187315e-76, 4.15531102e-81])
sel_reg.get_support() = array([False, False, True, True])
Selected features : ['petal length (cm)', 'petal width (cm)']
chi2 :
sel_chi2.scores_ = array([ 10.81782088, 3.7107283 , 116.31261309, 67.0483602 ])
sel_chi2.pvalues_ = array([4.47651499e-03, 1.56395980e-01, 5.53397228e-26, 2.75824965e-15])
sel_chi2.get_support() = array([False, False, True, True])
Selected features : ['petal length (cm)', 'petal width (cm)']
예측 정확도 측면에서 가장 좋은 성능을 보이는 featur subset(피쳐집합) 뽑아내기
기존 데이터에서 테스트를 진행할 hold-out set을 따로 두어야 한다.
최종적으로 best feature subset을 찾기 때문에 모델 성능 측면에서 매우 좋음
단 여러번 machine learning을 진행하기 때문에 시간과 비용이 많이 듦
변수선택 알고리즘
종류
Scikit-learn 파이썬 코드 예시
from sklearn.datasets import load_iris
from sklearn.feature_selection import RFE, RFECV, SelectFromModel, SequentialFeatureSelector
from sklearn.svm import SVC, SVR
X, y = load_iris(return_X_y=True)
# 분류기 svc 객체 생성, 선형분류, 클래스 3개
svc = SVR(kernel='linear', C = 3)
# RFE 객체 생성, 2개의 피쳐 선택, 1개씩 제거
rfe = RFE(estimator=svc, n_features_to_select = 2, step = 1)
# RFE + CV(Cross Validation), 5개의 폴드, 1개씩 제거
rfe_cv = RFECV(estimator=svc, step = 1, cv = 5)
# RFE 적용
rfe.fit(X, y)
print('RFE Rank : ', rfe.ranking_)
X_selected = rfe.transform(X)
X_selected_names = [X_names[i] for i in rfe.get_support(indices=True)]
print(f"{X_selected_names = }")
print(f"{X_selected[:5] = }")
# RFECV 적용
rfe_cv.fit(X, y)
print('RFECV Rank : ', rfe_cv.ranking_)
X_selected = rfe_cv.transform(X)
X_selected_names = [X_names[i] for i in rfe_cv.get_support(indices=True)]
print(f"{X_selected_names = }")
print(f"{X_selected[:5] = }")
RFE Rank : [2 3 1 1]
X_selected_names = ['petal length (cm)', 'petal width (cm)']
X_selected[:5] = array([[1.4, 0.2],
[1.4, 0.2],
[1.3, 0.2],
[1.5, 0.2],
[1.4, 0.2]])
RFECV Rank : [1 2 1 1]
X_selected_names = ['sepal length (cm)', 'petal length (cm)', 'petal width (cm)']
X_selected[:5] = array([[5.1, 1.4, 0.2],
[4.9, 1.4, 0.2],
[4.7, 1.3, 0.2],
[4.6, 1.5, 0.2],
[5. , 1.4, 0.2]])
from sklearn.datasets import load_iris
from sklearn.feature_selection import SequentialFeatureSelector
from sklearn.neighbors import KNeighborsClassifier
X, y = load_iris(return_X_y=True)
knn = KNeighborsClassifier(n_neighbors = 3)
sfs = SequentialFeatureSelector(knn, n_features_to_select = 2, direction = 'backward')
# SFS 학습
sfs.fit(X, y)
print("SFS Selected : ", sfs.get_support())
X_selected = sfs.transform(X)
X_selected_names = [X_names[i] for i in sfs.get_support(indices = True)]
print(f"{X_selected_names = }")
print(f"{X_selected[:5] = }")
SFS Selected : [False False True True]
X_selected_names = ['petal length (cm)', 'petal width (cm)']
X_selected[:5] = array([[1.4, 0.2],
[1.4, 0.2],
[1.3, 0.2],
[1.5, 0.2],
[1.4, 0.2]])
from sklearn.feature_selection import SelectFromModel
from sklearn import tree
from sklearn.datasets import load_iris
X, y = load_iris(return_X_y=True)
clf = tree.DecisionTreeClassifier()
sfm = SelectFromModel(estimator = clf)
sfm.set_output(transform = 'pandas')

sfm.fit(X, y)
print('SFM threshold : ', sfm.threshold_)
X_selected = sfm.transform(X)
X_selected.columns = [X_names[i] for i in sfm.get_support(indices = True)]
X_selected.head()
SFM threshold : 0.25
petal width (cm)
0 0.2
1 0.2
2 0.2
3 0.2
4 0.2