[λΌμ΄νΈ λ¨Έμ λ¬λ] Session 12. μμ°¨ νΉμ± μ ν μκ³ λ¦¬μ¦κ³Ό λλ€ ν¬λ μ€νΈ νΉμ± μ€μλ μ¬μ©
μ΄λ² μΈμ μμλ μμ°¨ νΉμ± μ νμ νλ λ°©λ²κ³Ό λλ€ ν¬λ μ€νΈμμ νΉμ± μ€μλλ₯Ό μ¬μ©νλ λ°©λ²μ μμλ³΄κ² μ΅λλ€. κ°λ³ΌκΉμ?
1. μμ°¨ νΉμ± μ ν μκ³ λ¦¬μ¦
λͺ¨λΈ 볡μ‘λλ₯Ό μ€μ΄λ λ°©λ²μ Session 11μμ μκ°νμλλ°μ, λ€λ₯Έ λ°©λ²μ νΉμ± μ νμ ν΅ν μ°¨μ μΆμ(dimensionality reduction)κ° μμ΅λλ€. κ·μ κ° μλ λͺ¨λΈμμ μ μ©νμ£ . μ°¨μ μΆμμλ μ£Όμ μΉ΄ν κ³ λ¦¬μΈ νΉμ± μ ν(feature selection)κ³Ό νΉμ± μΆμΆ(feature extraction)μ΄ μμ΅λλ€.
νΉμ± μ νμ νΉμ± μ€μμ μ ννλ κ²μ΄κ³ , μΆμΆμ νΉμ±μμ μ»μ μ 보λ€λ‘ μ νΉμ±μ λ§λλ κ²μ λλ€. νΉμ± μ νμ μμ΄μ μ€μν κ²μ λ¬Έμ μ κ°μ₯ κ΄λ ¨μ΄ λμ νΉμ± λΆλΆμ§ν©μ μλμ ννλ κ²μ λλ€. μ΄λ²μλ νΉμ± μ ν μκ³ λ¦¬μ¦μΈ μμ°¨ νΉμ± μ ν(sequential feature selection) μκ³ λ¦¬μ¦μ λν΄ μμλ³΄κ² μ΅λλ€. μμ°¨ νΉμ± μ ν μκ³ λ¦¬μ¦μ νμ μκ³ λ¦¬μ¦(greedy search algorithm)μΌλ‘ d μ°¨μμ΄μλ νΉμ±κ³΅κ°μ dλ³΄λ€ μμ k μ°¨μμΌλ‘ μΆμμν΅λλ€.
μμ°¨ νΉμ± μκ³ λ¦¬μ¦ μ€ μ ν΅μ μΈ κ²μ μμ°¨ νμ§ μ ν(sequential backward selection, SBS)μ λλ€. SBSλ μ΄κΈ° νΉμ±μ λΆλΆκ³΅κ°μΌλ‘ μ°¨μμ μΆμμν΅λλ€.
SBS μκ³ λ¦¬μ¦μ μ νΉμ±μ λΆλΆκ³΅κ°μ΄ λͺ©νν νΉμ± κ°μκ° λ λκΉμ§ μ 체 νΉμ±μμ μμ°¨μ μΌλ‘ νΉμ±μ μ κ±°ν©λλ€. μ΄λ νΉμ±μ μ κ±° κΈ°μ€μ μν΄ μ΅μνν κΈ°μ€ ν¨μκ° νμν©λλ€. κΈ°μ€ν¨μμμ κ³μ°ν κ°μ μ κ±° μ νμ λͺ¨λΈμ μ±λ₯ μ°¨μ΄μ λλ€. κ°μ₯ κΈ°μ€ κ°μ΄ ν° νΉμ±μ μ κ±°νκ² λκ² μ£ . κ°λ¨ν λ€ λ¨κ³λ‘ μ 리ν΄λ³΄κ² μ΅λλ€.
- μκ³ λ¦¬μ¦μ k=d (dλ μ 체 νΉμ±κ³΅κ°μ μ°¨μ)λ‘ μ΄κΈ°νν©λλ€.
- 쑰건 x = argmax J(Xk - x)λ₯Ό μ΅λννλ νΉμ± x'λ₯Ό κ²°μ ν©λλ€.
- νΉμ± μ§ν©μμ νΉμ± x'λ₯Ό μ κ±°ν©λλ€.
- kκ° λͺ©νν κ°μκ° λλ©΄ μ’ λ£νκ±°λ 2λ‘ λμκ°λλ€.
SBS μκ³ λ¦¬μ¦μ μ¬μ΄ν·λ°μ ꡬνλμ΄μμ§ μμ΅λλ€. νμ΄μ¬μΌλ‘ μ§μ ꡬνν μ½λλ μλμ κ°μ΅λλ€.
from sklearn.base import clone
from itertools import combinations
import numpy as np
from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split
class SBS():
def __init__(self, estimator, k_features, scoring=accuracy_score,
test_size=0.25, random_state=1):
self.scoring = scoring
self.estimator = clone(estimator)
self.k_features = k_features
self.test_size = test_size
self.random_state = random_state
def fit(self, X, y):
X_train, X_test, y_train, y_test = \
train_test_split(X, y, test_size=self.test_size,
random_state=self.random_state)
dim = X_train.shape[1]
self.indices_ = tuple(range(dim))
self.subsets_ = [self.indices_]
score = self._calc_score(X_train, y_train,
X_test, y_test, self.indices_)
self.scores_ = [score]
while dim > self.k_features:
scores = []
subsets = []
for p in combinations(self.indices_, r=dim - 1):
score = self._calc_score(X_train, y_train,
X_test, y_test, p)
scores.append(score)
subsets.append(p)
best = np.argmax(scores)
self.indices_ = subsets[best]
self.subsets_.append(self.indices_)
dim -= 1
self.scores_.append(scores[best])
self.k_score_ = self.scores_[-1]
return self
def transform(self, X):
return X[:, self.indices_]
def _calc_score(self, X_train, y_train, X_test, y_test, indices):
self.estimator.fit(X_train[:, indices], y_train)
y_pred = self.estimator.predict(X_test[:, indices])
score = self.scoring(y_test, y_pred)
return score
μ¬κΈ°μ λͺ©νν νΉμ± κ°μ kλ k_feature λ§€κ°λ³μμ λλ€. accuracy_score ν¨μλ₯Ό μ¬μ©ν΄ λͺ¨λΈμ μ±λ₯μ νκ°νκ³ , fit λ©μλμ λ°λ³΅λ¬Έ μμμ itertools.combination ν¨μμ μν΄ μμ±λ νΉμ± μ‘°ν©μ νκ°νκ³ μ€μ λλ€. κ·Έλ¦¬κ³ X_test μ κΈ°μ΄ν μ‘°ν©μ μ νλ μ μλ₯Ό self.scores_리μ€νΈμ λͺ¨μλλ€. μ΄ μ μλ‘ λμ€μ κ²°κ³Όλ₯Ό νκ°ν©λλ€. μ΅μ’ μΌλ‘ λ§λ€μ΄μ§ νΉμ±μ μ΄ μΈλ±μ€λ self.indices_μ ν λΉλ©λλ€. μ΄κ²μ transformμμ μ νλ νΉμ±μΌλ‘ ꡬμ±λ μλ‘μ΄ λ°°μ΄μ λ°νν λ μ°μ λλ€.
μ΄μ μ¬μ΄ν·λ°μ KNN λΆλ₯κΈ°λ₯Ό ν΅ν΄μ νμΈν΄λ³ΌκΉμ?
import matplotlib.pyplot as plt
from sklearn.neighbors import KNeighborsClassifier
knn = KNeighborsClassifier(n_neighbors=5)
# νΉμ±μ μ νν©λλ€.
sbs = SBS(knn, k_features=1)
sbs.fit(X_train_std, y_train)
# νΉμ± μ‘°ν©μ μ±λ₯ κ·Έλνλ₯Ό μΆλ ₯ν©λλ€.
k_feat = [len(k) for k in sbs.subsets_]
plt.plot(k_feat, sbs.scores_, marker='o')
plt.ylim([0.7, 1.02])
plt.ylabel('Accuracy')
plt.xlabel('Number of features')
plt.grid()
plt.tight_layout()
plt.show()
fit μμμ SBSκ° λ°μ΄ν°μ μ νλ ¨κ³Ό ν μ€νΈλ‘ λλκΈ°λ νμ§λ§ μ¬μ ν μ΄ μ½λμμλ X_train λ°μ΄ν°λ§ μ£Όμ ν©λλ€. μ΄λ SBSμ fit λ©μλκ° λλλ λ°μ΄ν°μ μ€ ν μ€νΈ μΈνΈλ₯Ό κ²μ¦μΈνΈ(validation set)μ΄λΌκ³ λΆλ₯΄κΈ°λ ν©λλ€. μ΄ κ²½μ°μλ νλ ¨ λ°μ΄ν°μ ν μ€νΈ λ°μ΄ν°λ₯Ό 미리 λΆλ¦¬ν΄λμμΌν©λλ€.
SBSλ‘ κ° λ¨κ³μμ κ°μ₯ μ’μ νΉμ±μ‘°ν©μ μ μλ₯Ό λͺ¨μλμμΌλ―λ‘ μ΄ μ½λλ₯Ό μ€ννλ©΄ κ²μ¦ μΈνΈλ‘ κ³μ°ν KNN λΆλ₯κΈ°μ μ νλλ₯Ό νμΈν μ μμ΅λλ€.
μ κ·Έλνμμ νμΈν μ μλ―μ΄ KNN λΆλ₯κΈ°μ μ νλλ νΉμ± κ°μκ° μ€μμ λ ν₯μλ©λλ€. κ·Έλ λ€λ©΄ μ΄μ μλ ν μ€νΈ μΈνΈμμμ KNN λΆλ₯κΈ° μ±λ₯μ νκ°ν΄λ³΄λλ‘ νκ² μ΅λλ€.
knn.fit(X_train_std, y_train)
print('νλ ¨ μ νλ:', knn.score(X_train_std, y_train))
print('ν
μ€νΈ μ νλ:', knn.score(X_test_std, y_test)
νλ ¨ μΈνΈμμλ 97% μ λμ μ νλλ₯Ό, ν μ€νΈ μΈνΈμμλ 96% μ λμ μ νλλ₯Ό 보μ¬μ£Όλ€μ. κ·ΈλΌ μ νλ μΈ κ°μ νΉμ±μμμ μ±λ₯λ νμΈν΄λ³ΌκΉμ?
knn.fit(X_train_std[:, k3], y_train)
print('νλ ¨ μ νλ:', knn.score(X_train_std[:, k3], y_train))
print('ν
μ€νΈ μ νλ:', knn.score(X_test_std[:, k3], y_test))
μ 체 νΉμ±μ 1/4λ μλλ νΉμ±μ μ¬μ©νμ§λ§ ν μ€νΈ μΈνΈμ μ νλλ ν¬κ² λ¨μ΄μ‘λ€κ³ νκΈ΄ νλ€μ΄λ³΄μ λλ€. μ΄ μΈ κ°μ νΉμ±μ νλ³μ λ³΄κ° μλ λ°μ΄ν°μ λ³΄λ€ κ·Έλ¦¬ μμ§ μλ€λ λ»μ λλ€.
Wine λ°μ΄ν°μ μ μλλ 그리 ν¬μ§ μμ λ°μ΄ν°μ μ΄λΌ λ°μ΄ν°μ μ νλ ¨κ³Ό ν μ€νΈλ‘ λλ κ²κ³Ό λ€μ νλ ¨κ³Ό κ²μ¦μΌλ‘ λλ κ²μ μν₯μ λ§μ΄ λ°μ΅λλ€.
μ¬κΈ°μ μ μ μλ μ μ νΉμ± κ°μλ₯Ό μ€μ΄λ κ²μ΄ KNN λͺ¨λΈμ μ±λ₯μ λμ΄μ§ μμ§λ§ ν μ΄ν° ν¬κΈ°λ₯Ό μ€μΌ μ μμλ€λ μ μ΄κ³ , κ·Έ λλ¬Έμ λ κ°λ¨ν λͺ¨λΈμ μ»μ μ μμλ€λ μ μ λλ€.
2. λλ€ ν¬λ μ€νΈμ νΉμ± μ€μλ μ¬μ©
μ΄μ μΈμ μμ μμλΈμ μκ°ν λ μ κΉ λ±μ₯νλ λλ€ ν¬λ μ€νΈλ₯Ό κΈ°μ΅νμλμ? λλ€ ν¬λ μ€νΈλ₯Ό μ¬μ©νλ©΄ κ²°μ νΈλ¦¬μμ κ³μ°ν νκ· λΆμλλ₯Ό κ°μμν΄μΌλ‘μ¨ νΉμ±μ μ€μλλ₯Ό νμΈν μ μμ΅λλ€. μ¬μ΄ν·λ°μμ RandomForestClassifier λͺ¨λΈμ νλ ¨νκ³ feature_importances_μμ±μμ νΉμ± μ€μλ κ°μ νμΈν μ μμ΅λλ€.
from sklearn.ensemble import RandomForestClassifier
feat_labels = df_wine.columns[1:]
forest = RandomForestClassifier(n_estimators=500,
random_state=1)
forest.fit(X_train, y_train)
importances = forest.feature_importances_
indices = np.argsort(importances)[::-1]
for f in range(X_train.shape[1]):
print("%2d) %-*s %f" % (f + 1, 30,
feat_labels[indices[f]],
importances[indices[f]]))
plt.title('Feature Importance')
plt.bar(range(X_train.shape[1]),
importances[indices],
align='center')
plt.xticks(range(X_train.shape[1]),
feat_labels[indices], rotation=90)
plt.xlim([-1, X_train.shape[1]])
plt.tight_layout()
plt.show()
μ μ½λλ₯Ό μ€ννλ©΄ κ° νΉμ±μ μλμ μ€μλμ λ°λ₯Έ μμλ₯Ό νλ‘ λ³΄μ¬μ€λλ€. μ΄ μ€μλλ ν©μ΄ 1μ΄ λλλ‘ μ κ·ν λμ΄μμ΅λλ€. 500κ° κ²°μ νΈλ¦¬μμ κ°μ₯ νλ³λ ₯μ΄ μ’μ νΉμ±μ prolineλΆν° alcoholκΉμ§μ λλ€. μ΄ κ·Έλνμμ μμ νΉμ± μ€ λ κ°λ μμμ ꡬνν SBS μκ³ λ¦¬μ¦μμ μ νν 3κ°μ νΉμ±μ λ€μ΄μμ΅λλ€.
λλ€ ν¬λ μ€νΈμμ λ κ° μ΄μμ νΉμ±μ΄ μλ‘ μκ΄κ΄κ³κ° κΉλ€λ©΄, νλλ μμ£Ό μ μ‘μλ΄μ§λ§ λ€λ₯Έ μ 보λ μ μ°Ύμλ΄μ§ λͺ»ν μ μμ΅λλ€. λ§μ½ νΉμ± μ€μλ κ°λ³΄λ€ λͺ¨λΈμ μ±λ₯μλ§ κ΄μ¬μ΄ μλ€λ©΄ 무μνμ λ μ’μ΅λλ€λ§, μμλμ λ μ’μ΅λλ€.
μ¬μ΄ν·λ°μ SelectFromModelμ λͺ¨λΈ νλ ¨μ΄ λλ λ€μμ μ¬μ©μκ° μ ν κ°μ κΈ°λ°μΌλ‘ νΉμ±μ μ νν©λλ€. λμ€μ λ±μ₯ν Pipelineμ λ¨κ³μμ RondomForestClassifierλ₯Ό νΉμ± μ νκΈ°λ‘ μ¬μ©ν λ μ μ©ν©λλ€. μλ μ½λλ μ¬μ©μ μ§μ κ°, μ¦ μκ³κ°μ 0.1λ‘ ν΄ νΉμ±μ μ€μν 5κ°λ‘ μ€μ¬μ€λλ€.
from sklearn.feature_selection import SelectFromModel
sfm = SelectFromModel(forest, threshold=0.1, prefit=True)
X_selected = sfm.transform(X_train)
print('μ΄ μκ³ μ‘°κ±΄μ λ§μ‘±νλ μνμ μ:', X_selected.shape[1])
# μ΄ μκ³ μ‘°κ±΄μ λ§μ‘±νλ μνμ μ: 5
for f in range(X_selected.shape[1]):
print("%2d) %-*s %f" % (f + 1, 30,
feat_labels[indices[f]],
importances[indices[f]]))
μ¬κΈ°κΉμ§ μμ°¨ νΉμ± μ ν μκ³ λ¦¬μ¦κ³Ό λλ€ ν¬λ μ€νΈμ λν΄μ μμ보μμ΅λλ€. μ£Όλ‘ μ°¨μ μΆμλ λ°μ΄ν°μ ν¬κΈ°λ₯Ό μ€μ΄λ κΈ°λ²λ€μ΄μλλ°μ, λ€μμΌλ‘ κΈ°λ€λ¦¬κ³ μλ μΈ κ°μ μΈμ λ€μμλ μ°¨μ μΆμλ₯Ό μ¬μ©ν λ°μ΄ν° μμΆμ λ€λ£° μμ μ λλ€. κ·ΈλΌ μ λ λ€μ μΈμ μμ PCAλ₯Ό λ€κ³ λμμ€λλ‘ νκ² μ΅λλ€. λ€μ μΈμ μμ 봬μ!