본문 바로가기

머신러닝/[기타]

특성 선택(Feature Selection)

 모델의 학습하는데 있어 X(특성, Feature)와 y(정답, target) 데이터셋을 사용해 훈련하는 감독 학습(Supervised  learning)의 기준에서 바라볼 때, X의 개수가 다양하다는 것은 y를 예측할 힌트가 많아진다는 말 같습니다. 그러면 특성의 개수는 무작정 많다고해서 좋은것인가- 한다면, 그것은 아닙니다. 그저 많기만한 특성은 모델을 과대적합시킬 뿐일 것입니다. 머신러닝은 분명 빅데이터를 필요로 하지만, 어느정도 스케일이 갖춰졌다면, 이후부터는 항상 시나리오에 적합한 데이터의 품질(Quality)과의 싸움이 됩니다. 때문에 다양한 특성을 가진 데이터셋을 확보했다면, 그 다음은 가장 유용한 특성을 선별(Selection)하는 과정이 필요합니다. 이제, 그 선별을 어떻게 하는지, 살펴보겠습니다. 추가로, 특성 선택은 차원 축소(Dimesionality Reduction)과는 다른 개념입니다. 두 방법 모두 데이터의 특성 수를 줄이고자하지만, 차원 축소(예: PCA, SVD)는 새로운 특성 조합을 생성합니다. 특성 선택은 값을 특성을 변경하지 않고 포함 및 제외하는 방법론입니다.

 주의해야할 것은, 특성 선택은 모델 평가 루프 내에 포함되어야합니다. 예를 들어, Cross-validation을 사용하는 경우, CV for 루프 안에 특성 선택 모듈을 넣어, 특성 선택과 모델 훈련, 모델 평가가 하나의 흐름으로 만들어져야한다는 것입니다. 특성 선택으로 어떤 데이터셋을 확정짓고, CV를 통해 모델을 평가하는 것은 실수입니다.

1. 분산(Varation)에 따른 선별

본래 예측모델에서 중요한 특성이란, 타겟과의 상관관계가 큰 특성을 의미합니다. 하지만 상관관계 계산에 앞서 어떤 특성의 값 자체가 다양한 표본에 따라 그다지 변하지 않는다면, 예측에 별 도움이 되지 않을 가능성이 높습니다. 극단적인 예시로써, 남자들을 대상으로 한 설문조사 데이터에서 남자라는 성별특성은, 당연하게도 무의미합니다. 때문에, 표본 변화에 따른 데이터 값의 변화량 즉, 분산이 기준치보다 낮은 특성은 제거하는 것이 분산에 따른 선별 방법입니다.
하지만 분산에 의한 선택은 반드시 상관관계와 일치한다는 보장은 없습니다.

from sklearn.feature_selection import VarianceThreshold

select_VT = VarianceThreshold(0.001)
X_train_VT = select_VT.fit_transform(X_train)
X_test_VT = select_VT.transform(X_test)

2. 단일 변수 선택

단일 변수 선택법은 각각의 특성을 하나만 사용했을 때의 예측모델의 성능을 평가하여, 정확도 또는 상관관계가 가장 좋은 특성만을 선택하는 방법입니다. 예를 들어, 몸무게(y)를 예측하기 위한 특성(X)에 키, 나이, 성별이 있다면 키-몸무게, 나이-몸무게, 성별-몸무게를 어떤 특정지표(정확도, 카이제곱값 등)로써 평가하여 가장 좋은 특성을 선별하는 방법입니다.
하지만 좋은 단일 변수만을 모았을 때 반드시 모델이 개선된다는 보장은 없습니다.

from sklearn.feature_selection import chi2, SelectKBest

select_SKB = SelectKBest(chi2, k=10000)
X_train_SKB = select_SKB.fit_transform(X_train)
X_test_SKB = select_SKB.transform(X_test)

3. 모델 기반 변수 선택(Model based method)

트리 기반 모델(또는 선형모델)들이 특성 중요도(Feature Importance)를 제공하는 것에 기반한 방법입니다. 특성 중요도는 예측의 불확실성을 낮출수록 증가하므로, (X,y)를 트리 기반 모델에 학습시킨 뒤, 특성 중요도가 기준치보다 높은 특성을 선택하는 방법입니다. 특성 선택에 사용한 모델과, 최종 예측 모델은 다를 수 있습니다.

from sklearn.feature_selection import SelectFromModel
from sklearn.ensemble import ExtraTreesClassifier

model_ETC = ExtraTreesClassifier
model_ETC.fit(X_train,y_train)
print(model_ETC.feature_importances_)
select_SFM = SelectFromModel(model_ETC, threshold='median').fit(X_train,y_train)
X_train_SFM = select_SFM.transform(X_train)
X_test_SFM = select_SFM.transform(X_test)

4. 반복적 특성 선택(Recursive Feature Selection)

그냥 모든 특성 조합을 다 시도해보고 가장 좋은 셋을 찾겠다는, 어쩌면 가장 단순한 방법입니다. 1개의 특성에서 출발하여 지정한 특성 개수(n_features_to_select)에 도착할 때까지 특성을 추가하는 방법과 모든 특성에서 출발하여 지정한 특성 개수에 도달할 때까지 특성을 제거하는 방법이 있습니다. 보통 후자(Recursive Feature Elimination, RFE)를 사용합니다.

from sklearn.feature_selection import RFE
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier

model_LR = LogisticRegression()
model_RF = RandomForestClassifier()
select_RFE = RFE(model_LR, n_features_to_select=20)
#select_RFE = RFE(model_RF, n_features_to_select=20)
X_train_RFE = select_RFE.fit_transform(X_train,y_train)
X_test_RFE = select_RFE.transform(X_test)

마무리

항상 시나리오에 맞는 특성 선택은 모델 개선에 있어 중요한 역활을 합니다. 그러나 앞서 말했듯 반드시 모델이 개선된다는 보장은 없습니다. 여러가지 방법을 시도해보고, 가장 맞는 것을 찾아나가야합니다.

실제 데이터셋을 다루다보면, 타겟값이 불균형하게 분포된 데이터셋을 만나게 됩니다. 예를들어 암에 걸린 환자를 구분하는 이진분류 문제에서, 암에 걸린(True) 타겟에 대한 데이터는 고작 100개, 암에 걸리지 않은(False) 타겟에 대한 데이터는 1000000개가 있을 때에 단순히 특성 선택을 시도하게 되면, True 타겟에 대한 모든 데이터 표본이 무시당하는 상황이 벌어질 수 있습니다. 때문에 특성 선택을 시행하기전, 클래스 불균형 문제를 해결하려는 노력이 필요합니다.