본문 바로가기
머신러닝

Feature Selection Guide on Kaggle

by 짱태훈 2024. 9. 10.
728x90

본 게시물은 kaggle에서 게시된 게시물을 토대로 만들었습니다.

https://www.kaggle.com/code/prashant111/comprehensive-guide-on-feature-selection

 

Comprehensive Guide on Feature Selection

Explore and run machine learning code with Kaggle Notebooks | Using data from multiple data sources

www.kaggle.com

위 사이트를 참고한 것으로 개인의 공부를 위해 참고한 것입니다.


Feature Selection

 

Filter Methods

  • Basic Methods
    • Remove Constant Features
    • Remove Quasi-Constandt Features
  • Univeriate Selection Methods
    • Select KBest
    • Select Percentile
  • Information Gain
  • Fisher Score (chi-square implementation)
  • ANOVA F-Value for Feature Selection
  • Correlation-Matrix with Heatmap

Wrapper Methods

  • Forward Selection
  • Backward Elimination
  • Exhaustive Feature Selection
  • Recursive Feature Elimination
  • Recursive Feature Elimination with Cross-Validation

Embedded Methods

  • LASSO Regression
  • Random Forest Importance

How to choose the right feature selection method

Tips and tricks for feature selection


Feature Selection

특성 선택(Feature Selection) 또는 변수 선택(variable selection)은 데이터 세트의 전체 특성 중에서 머신러닝 알고리즘을 구축하기 위해 중요한 일부 특성(또는 변수) 을 선택하는 과정이다. Feature Selection 또는 변수 선택은 모델 성능을 향상시키고, 계산 복잡성을 줄이며, 모델의 해석 가능성을 높이는 데 중요한 역할을 하기 때문에 중요한 부분이다. 따라서 이번에 이렇게 Feature Selection을 따로 게시한 것이다.

 

Feature Selection의 장점을 더 자세히 알아보면 다음과 같다.

  • 향상된 정확도: 불필요한 특성을 제거함으로써 모델의 정확도 향상
  • 해석하기 쉬운 간단한 모델: 더 적은 특성을 가진 모델은 해석이 더 쉽다.
  • 짧아진 학습 시간: 사용할 특성이 적어지면 모델의 훈련 시간이 단축된다.
  • 과적합(overfitting) 감소로 인한 일반화 성능 향상: 불필요한 특성을 줄임으로써 과적합이 줄어들고, 모델이 새로운 데이터에 대해 더 잘 일반화된다.
  • 소프트웨어 개발자가 구현하기 쉬움: 특성 수가 적을수록 소프트웨어 개발자가 이를 구현하는 데 용이하다.
  • 데이터 오류의 위험 감소: 적은 특성을 사용하는 모델은 데이터 오류의 위험이 줄어든다.
  • 변수 중복 제거: 특성 간의 중복을 줄임으로써 모델의 효율성을 높일 수 있다.
  • 고차원 공간에서의 학습 문제: 고차원 공간에서 발생하는 나쁜 학습 행동을 방지할 수 있다.

이러한 장점을 가진 Feature Selection의 방법은 앞에서 목차를 통해 보았듯이 3가지가 있다.

  • 필터 방법(Filter methods): 데이터의 통계적 특성을 기반으로 독립적으로 특성을 선택하는 방법
  • 래퍼 방법(Wrapper methods): 모델을 학습하여 성능을 평가한 후, 최적의 특성 조합을 선택하는 방법
  • 임베디드 방법(Embedded methods): 특성 선택이 모델 학습 과정에 내재되어 동시에 이루어지는 방법

Filter methods부터 하나씩 알아보려고 한다.


 

 

Filter methods

데이터의 통계적 특성을 기반으로 독립적으로 특성을 선택하는 방법으로 주요 기법으로 기본 방법 (Basic methods), 단변량 방법 (Univariate methods), 정보 이득 (Information gain), 피셔 점수 (Fisher score), 상관 행렬과 히트맵 (Correlation Matrix with Heatmap)이 있다.

일반적으로 전처리 단계에서 사용되는 방법이며, 특성 선택은 머신러닝 알고리즘과는 독립적으로 이루어진다. 그럼에도 특성은 결과 변수와의 상관관계를 측정하는 다양한 통계적 테스트에서 얻은 점수를 기준으로 선택해야 한다. 따라서 Filter Methods는 다음과 같은 특징을 가진다.

  • 데이터의 특성(특성의 특징)에 의존하고, 머신러닝 알고리즘을 사용하지 않는다.
  • 머신러닝 알고리즘을 사용하지 않는다.
  • 불필요한 특성을 빠르게 삭제하는 데 적합하다.

 

기본 방법 (Basic methods)

가장 기본적인 방법으로 각 특성의 통계적 중요도를 측정하고 기준에 따라 특성을 선택하는 방법

상수 특성과 준-상수 특성을 제거하는 것으로 불필요한 특성을 제거하는 것이다.

 

1. 상수 특성 제거(Remove constant features)

상수 특성 제거는 동일한 값만을 갖는 특성을 제거하는 것으로 모든 행에서 동일한 값을 갖는 특성을 제거하는 것이다. 이전 게시물에서 필자가 nunique==1인 것을 DataFrame에서 drop한 것을 말한다. 이러한 값을 제거하는 이유는 아무런 정보도 제공하지 않기 때문이다.

제거하는 방법으로는 두 가지가 있다. 먼저 첫 번째는 필자가 지금까지 해온 방법으로 sklearn에서 제공하는 함수를 사용하지 않고 직접 구현하는 방법이다. 두 번째는 sklearn에서 제공하는 VarianceThreshold 함수를 이용하는 방법이다. 

unique_one_columns = [col for col in train_df.columns if train_df[col].nunique() == 1]
print(f'고유값이 1인 컬럼 개수: {len(unique_one_columns)}')
from sklearn.feature_selection import VarianceThreshold

unique_columns = VarianceThreshold(threshold=0)
unique_columns.fit(train_df)

위와 같이 사용할 수 있으며 특성의 분산(variance)을 계산하여 분산이 0인(즉, 모든 값이 동일한) 특성을 찾아 제거하는 것이다.

 

2. 준-상수 특성 제거(Remove quasi-constant features)

대부분의 데이터에서 같은 값을 가지지만, 일부 값만 다른 것을 제거하는 것이다.

target을 구별하거나 예측하는 데 거의 도움이 되지 않지만, 특정 상황에서는 예외가 있을 수 있기 때문에 주의해야 한다.

quasi-constant features를 제거하는 방법은 분산이 0인 것을 제거하는 방법과 같이 VarianceThreshold 함수를 사용해서 제거할 수 있다. 아래와 같이 기본 값이 0인 threshold 값을 변경해 제거할 수 있다.

from sklearn.feature_selection import VarianceThreshold

unique_columns = VarianceThreshold(threshold=0.01)
unique_columns.fit(train_df)

0.01은 100개의 샘플 중 99개의 값에서 동일한 값을 가진다면, 이 특성은 분산이 매우 낮기 때문에 제거하는 것으로 사용자의 선택에 따라 달라질 수 있다.

 

단변량 특성 선택 방법 (Univariate Selection Methods)

분산 분석과 같은 단변량 통계 테스트를 기반으로 가장 좋은 특성들을 선택하는 방법이다. scikit-learn에서 특성 선택을 위한 여러 방법이 제공되며, transform 메서드를 통해 특성을 변환할 수 있다.

 

F-테스트 기반 방법

두 개의 랜덤 변수 간의 선형 의존성을 추정하는 것으로 특성과 목표 변수 간의 선형 관계를 가정한다. 또한 변수들이 정규 분포(Gaussian distribution)를 따른다고 가정한다. F-테스트 기반의 방법으로 4가지가 있다.

 

  • SelectKBest: 선택된 상위 K개의 특성을 반환합니다. K는 사용자가 지정할 수 있다.
  • SelectPercentile: 상위 특정 백분율에 해당하는 특성들을 선택한다.
  • SelectFpr, SelectFdr, SelectFwe: 각각 False Positive Rate(FPR), False Discovery Rate(FDR), Family Wise Error Rate(FWE)에 기반하여 특성을 선택하는 방법
  • GenericUnivariateSelection: 위의 방법들 중 하나를 선택하여 커스터마이즈할 수 있는 일반적인 단변량 특성 선택 방법

1. SelectKBest

가장 높은 점수를 받은 상위 K개의 특성을 선택하는 것으로 데이터셋의 각 특성에 대해 통계적인 검정을 수행하고, 그 결과에서 가장 유의미한 K개의 특성을 추출하는 방식

ex) 카이제곱(chi-square) 테스트를 사용하여 iris 데이터셋에서 상위 두 개의 특성만 선택할 수 있다. 

사용자가 설정한 K 값에 따라 상위 K개의 특성을 반환하며, 이를 통해 불필요한 특성을 제거하고 모델 성능을 개선할 수 있다.

from sklearn.feature_selection import SelectKBest, chi2

X_new = SelectKBest(chi2, k=2).fit_transform(X, y)
X_new.shape

ex) (150, 4) -> (150, 2)

 

 

2. SelectPercentile

가장 높은 점수를 받은 특성 중에서 특정 백분위수에 해당하는 특성을 선택하는 방법

사용자가 설정한 백분위수에 해당하는 특성들을 선택하고 선택한 특성들이 모델 학습에 사용되도록 한다.

특성의 전체 분포를 기준으로 상위 백분위 특성을 선택하기 때문에, SelectKBest와 달리 특성의 개수가 아닌 비율로 특성을 선택하는 방식

from sklearn.feature_selection import SelectPercentile, chi2

X_new = SelectPercentile(chi2, percentile=10).fit_transform(X, y)
X_new.shape

ex) (1797, 64) -> (1797, 7)

 

정보 이득(Information Gain, 상호 정보)

특정 특성의 존재 또는 부재가 target을 올바르게 예측하는 데 얼마나 기여하는지를 측정하는 방법

변수 X와 Y가 공유하는 정보의 양을 측정한다. 즉, 하나의 변수를 알면 다른 변수에 대한 불확실성이 얼마나 줄어드는지를 측정

1. mutual_info_classif

mutual_info_classif 함수는 이산형 목표 변수에 대한 상호 정보를 추정한다. 상호 정보는 두 랜덤 변수 간의 의존성을 측정하는 0 이상의 값이다. 상호 정보가 0이면 두 랜덤 변수가 독립적이라는 것을 의미하며, 값이 높을수록 두 변수 간의 의존성이 높다.

정리를 하면 다음과 같다. 단변량 특성 선택을 위한 방법으로 사용할 수 있다. 즉, 각 특성에 대해 상호 정보를 계산하여 목표 변수와의 상관관계가 높은 특성을 선택할 수 있다.

 

2. mutual_info_regression

mutual_info_regression 함수는연속형 목표 변수에 대한 상호 정보를 추정한다. 상호 정보는 두 랜덤 변수 간의 의존성을 측정하는 0 이상의 값이다. 상호 정보가 0이면 두 랜덤 변수가 독립적이라는 것을 의미하며, 값이 높을수록 두 변수 간의 의존성이 높다.

mutual_info_classif와 같다.

 

피셔 점수(Fisher Score, 카이제곱 구현)

scikit-learn에서 제공하는 카이제곱(chi-square) 구현으로 분류 작업에서 범주형 변수를 평가하는 데 사용된다. 즉, 범주형 변수를 가진 특성들이 목표 변수 Y가 다른 클래스들과 어떤 관계가 있는지 평가하는 데 적합하다. 쉽게 말해 특정 특성이 목표 변수 예측에 얼마나 유의미한지를 측정하는 것이다.

from sklearn.feature_selection import SelectKBest, chi2

chi2_selector = SelectKBest(chi2, k=2)
X_kbest = chi2_selector.fit_transform(X, y)

ex) 4 -> 2

 

ANOVA F-값을 이용한 특성 선택(ANOVA F-value For Feature Selection)

범주형 데이터는 카이제곱 통계를 통해 특성 간의 관계를 평가하고 연속형 데이터의 경우 각 특성과 목표 벡터 간의 ANOVA F-값을 계산한다. 즉, 특성 선택에서 양적 특성의 유의미성을 판단하는 데 사용한다.

ANOVA F-값은 목표 벡터로 수치형 특성을 그룹화했을 때 각 그룹의 평균이 유의미하게 다른지를 평가하는 지표로 F-값이 클수록, 그룹 간 평균 차이가 크다는 뜻이며, 이는 해당 특성이 목표 변수에 중요한 영향을 미친다는 것을 나타낸다.

from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import f_classif

fvalue_selector = SelectKBest(f_classif, k=2)
X_kbest = fvalue_selector.fit_transform(X, y)

ex) 4 -> 2

 

상관 행렬과 히트맵 (Correlation-Matrix with Heatmap)

correlation은 두 개 이상의 변수 간의 선형 관계를 측정하는 방법으로 상관을 통해 한 변수를 바탕으로 다른 변수를 예측할 수 있다.

상관관계가 높은 예측 변수들은 중복된 정보를 제공할 수 있으며, 변수들은 목표 변수와 상관관계를 가져야 하지만, 서로 간에는 상관관계가 없어야 한다.

상관관계를 통해 서로 상관된 특성을 찾아내고, 이러한 특성 중 어떤 것을 유지하고 어떤 것을 제거할지 결정할 수 있다.

 

피어슨 상관계수(Pearson Correlation)를 사용한 분석

상관계수 값은 -1에서 1 사이의 값을 가진다. 

  • 상관계수 0: 두 변수의 상관관계가 없음을 의미하며, 한 변수가 변해도 다른 변수에 영향을 미치지 않는다.
  • 상관계수 > 0: 한 변수의 값이 증가할 때 다른 변수의 값도 증가하는 경향이 있다. 1에 가까울수록 두 변수 간의 관계가 강해진다.
  • 상관계수 < 0: 한 변수의 값이 증가할 때 다른 변수의 값이 감소하는 경향이 있다. -1에 가까울수록 두 변수 간의 관계가 강해진다.

즉, 높은 상관관계를 가지는 변수들이 있다면, 하나의 변수만 유지하고 나머지 변수들은 제거하는 것이 좋으며, 이를 통해 중복된 정보를 제거하고 모델의 효율성을 높일 수 있다.

corr_matrix = df.corr()

plt.figure(figsize=(8,6))
plt.title('Correlation Heatmap')
a = sns.heatmap(corr_matrix, square=True, annot=True, fmt='.2f', linecolor='black')       
plt.show()

위의 heatmap은 필자가 최근에 진행했던 프로젝트에서 실제로 상관관계를 분석했던 것이다.

CURE END POSITION X Collect Result_Dam, CURE END POSITION Y Collect Result_Dam, CURE END POSITION Z Collect Result_Dam가 모드 상관관계가 1로 CURE END POSITION X Collect Result_Dam가 증가하면 다른 것도 똑같이 증가하는 특성을 보여준다. 따라서 세 개의 feature에서 하나만 남기는 방법도 있었으며, 필자는 세 개의 feature을 합쳐서 진행했다.


Wrapper Methods

Wrapper 방법은 feature의 일부만 사용해 모델을 훈련하는 것을 말한다. 이전 모델에서 얻은 추론을 바탕으로 피처를 추가하거나 제거하는 방법이다. 즉, 다양한 피처 조합을 탐색해야 하기 때문에 계산 비용이 많이 드는 방법이다. 

 

Wrapper 방법의 일반적인 예

  • 전진 선택(Forward selection)
  • 후진 제거(Backward elimination)
  • 전수 피처 선택(Exhaustive feature selection)
  • 재귀적 피처 제거(Recursive feature elimination)
  • 교차 검증을 통한 재귀적 피처 제거(Recursive feature elimination with cross-validation)

Wrapper 방법

Set of all Features -> Generate a Subset -> Learning Algorithm -> Performance -> Selecting the Best Subset

  1. 전체 피처 집합: 모든 가능한 feature
  2. 부분 집합 생성: 일부 피처를 선택해 부분 집합을 만들고 모델 학습에 사용
  3. 학습 알고리즘: 선택한 피처들로 성능 평가
  4. 성능: 성능이 좋으면 부분 집합 유지 또는 추가 조정
  5. 최적의 부분 집합 선택: 학습과 평가를 반복하며, 최적의 피처 집합 찾기

이 과정은 wrapper 방법이 반복적인 과정임을 보여준다.

 

전진 선택(Forward Selection)

반복적인 방법으로, 모델에 처음에는 피처(특성)가 하나도 포함되지 않은 상태에서 시작한다. 반복하며 모델의 성능을 가장 많이 개선하는 피처를 추가하며, 더 이상 새로운 변수를 추가해도 성능이 개선되지 않을 때까지 이 과정을 계속하는 방법이다.

피처가 없는 상태에서 시작하여 [축소된 피처 집합]을 만드는 것으로 원래 피처 중에서 가장 좋은 피처를 찾아 축소된 집합에 추가한다. 이후 반복에서는 남아 있는 원래 피처 중에서 가장 좋은 것을 찾아 집합에 추가하는 과정을 반복한다.

  1. 각 피처를 개별적으로 평가한 뒤, 미리 정해진 평가 기준에 따라 가장 성능이 좋은 알고리즘을 만드는 피처를 선택
  2. 선택된 피처와 두 번째 피처의 모든 가능한 조합을 평가하여, 동일한 기준에 따라 가장 성능이 좋은 알고리즘을 만드는 피처 쌍을 선택

전진 선택은 단일 피처, 두 개의 피처, 세 개의 피처 등 가능한 모든 조합을 평가하기 때문에 greedy 알고리즘이라 불린다. 따라서 계산 비용이 많이 들며, 피처 공간이 매우 클 경우 비현실적일 수 있다.

 

Python에서는 mlxtend을 통해 전진 선택을 할 수 있다. 원하는 개수의 피처가 선택될 때 탐색이 종료할 수 있다.

 

기존에 했었던 titanic 데이터를 이용해서 예시를 들어보겠다.

1. data load

from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score, confusion_matrix, precision_recall_curve, roc_curve, classification_report, roc_auc_score
from mlxtend.feature_selection import SequentialFeatureSelector as SFS
import pandas as pd
import numpy as np
import warnings
warnings.filterwarnings('ignore')


RANDOM_STATE = 110
pd.set_option('display.max_columns', None)

train_df = pd.read_csv("../../data/titanic/titanic_train.csv", encoding='latin-1')
test_df = pd.read_csv("../../data/titanic/test.csv", encoding='latin-1')

 

2. numeric feature select -> Survived을 따로 분리

numerics = ['int16', 'int32', 'int64', 'float16', 'float32', 'float64']
numerical_vars = list(train_df.select_dtypes(include=numerics).columns)
data = train_df[numerical_vars]

y = data['Survived']
X = data.drop(['Survived'], axis=1)
X.shape

 

3. train, test set split

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=0)
X_train.shape, X_test.shape

 

4. correlation > 0.8 drop

def correlation(dataset, threshold):
    col_corr = set()  # Set of all the names of correlated columns
    corr_matrix = dataset.corr()
    for i in range(len(corr_matrix.columns)):
        for j in range(i):
            if abs(corr_matrix.iloc[i, j]) > threshold: # we are interested in absolute coeff value
                colname = corr_matrix.columns[i]  # getting the name of column
                col_corr.add(colname)
    return col_corr

corr_features = correlation(X_train, 0.8)
print('correlated features: ', len(set(corr_features)) )


X_train.drop(labels=corr_features, axis=1, inplace=True)
X_test.drop(labels=corr_features, axis=1, inplace=True)
X_train.shape, X_test.shape

 

5. Forward Selection

sfs1 = SFS(RandomForestClassifier(), 
           k_features=5, 
           forward=True, 
           floating=False, 
           verbose=2,
           scoring='f1',
           cv=3)

sfs1 = sfs1.fit(np.array(X_train), y_train)

sfs1.k_feature_idx_

X_train.columns[list(sfs1.k_feature_idx_)]

SFS는 Sequential Feature Selector로 주어진 데이터셋에서 피처를 선택하는 방법이다. 위의 코드는 5개의 최적의 특징을 선택하는 것으로 결과는 아래와 같다.

[2024-09-10 13:37:28] Features: 1/5 -- score: 0.5261248766898202
[2024-09-10 13:37:29] Features: 2/5 -- score: 0.5093236932502362
[2024-09-10 13:37:30] Features: 3/5 -- score: 0.5590213548731862
[2024-09-10 13:37:30] Features: 4/5 -- score: 0.5644747531746127
[2024-09-10 13:37:31] Features: 5/5 -- score: 0.5503133766556585
(0, 1, 2, 4, 5)

Index(['PassengerId', 'Pclass', 'Age', 'Parch', 'Fare'], dtype='object')

결과는 위와 같다. 1개의 피처를 선택했을 때, 2개의 피처를 선택했을 때, ..., 5개의 피처를 선택했을 때의 F1 스코어를 보여주며, 피처가 4개일 때 F1 스코어가  가장 높았다는 것을 확인할 수 있다. 선택된 특성들의 인덱스는 0, 1, 2, 4, 5이며 각각 PassengerId, Pclass, Age, Parch, Fare인 것을 확인할 수 있다.

  • RandomForestClassifier(): 랜덤 포레스트 분류 모델을 사용하여 피처 선택을 수행합니다.
  • k_features=10: 10개의 피처를 목표로 설정합니다. 최종적으로 선택된 10개의 피처가 가장 좋은 성능을 내는 조합으로 만든다.
  • forward=True: 전진 선택(Forward Selection). 처음에는 피처가 없고, 매 반복에서 성능을 가장 많이 향상시키는 피처를 추가
  • floating=False: 한 번 선택된 피처가 이후 단계에서 제거되지 않는다. floating=True면 선택된 피처가 다른 피처가 추가될 때 제거
  • verbose=2: 처리 과정을 상세하게 출력하도록 설정됩니다. 이 옵션을 사용하면 피처 선택 과정에서 진행 상황이 출력됩니다.
  • scoring='f1': F1 스코어는 분류 문제에서 불균형한 클래스의 성능을 평가할 때 유용한 지표입니다. Precision(정밀도)과 Recall(재현율)의 조화 평균을 사용해, 특히 양성 클래스에 대한 예측 성능을 측정하는 데 적합합니다.
  • cv=3: 3-Fold 교차 검증을 사용하여 피처 선택 과정에서 데이터셋을 3개의 부분으로 나누어 교차 검증을 수행합니다. 이 방법은 과적합을 방지하고 모델의 일반화 성능을 높이기 위한 방법입니다.

후진 제거(Backward Elimination)

모든 feature를 포함한 상태에서 시작해, 각 반복마다 모델의 성능을 향상시키지 않는 피처를 제거하는 것으로 피처를 제거해도 더 이상 성능이 개선되지 않을 때까지 반복한다.

sfs1 = SFS(RandomForestClassifier(), 
           k_features=5, 
           forward=False, 
           floating=False, 
           verbose=2,
           scoring='f1'
           )

sfs1 = sfs1.fit(np.array(X_train), y_train)

sfs1.k_feature_idx_

X_train.columns[list(sfs1.k_feature_idx_)]

 

[2024-09-10 13:41:39] Features: 5/5 -- score: 0.578308199340857
(1, 2, 3, 4, 5)

Index(['Pclass', 'Age', 'SibSp', 'Parch', 'Fare'], dtype='object')

Backward Selection을 사용하여 5개의 최적 특성을 선택하는 과정이다. forward=False로 설정했기 때문에, 특성 제거 방식으로 최적의 특성을 찾는 것으로 선택된 특성들의 인덱스는 1, 2, 3, 4, 5로 각각 Pclass, Age, SibSp, Parch, Fare이다.

 

 

Exhaustive Feature Selection

주어진 머신 러닝 알고리즘의 특정 성능 지표를 최적화하는 방식으로 모든 가능한 피처 조합 중에서 최적의 피처 집합을 선택하는 방법이다.

예를 들어, 분류기가 로지스틱 회귀(Logistic Regression)이고, 데이터셋에 4개의 피처가 있다고 가정할 때, 이 알고리즘은 다음과 같이 15개의 피처 조합을 평가한다.

  • 1개의 피처로 가능한 모든 조합
  • 2개의 피처로 가능한 모든 조합
  • 3개의 피처로 가능한 모든 조합
  • 4개의 피처 조합

이후 로지스틱 회귀 분류기의 성능을 기준으로 가장 성능이 좋은 피처 조합을 선택하는 방법이다.

Forward Selection과 마찬가지로 greedy 알고리즘 중 하나로, 가능한 모든 피처 조합을 평가한다. 따라서 계산 비용이 매우 많이 들어 피처 공간이 매우 큰 경우에는 계산이 너무 많아 비현실적일 수 있다.

Python에서는 mlxtend을 통해 구현할 수 있다.

 

Recursive Feature Elimination (RFE)

최적의 특성 집합을 찾기 위한 greedy 최적화 알고리즘으로, 반복적으로 모델을 만들면서 성능이 가장 좋은 특성 혹은 성능에 덜 기여하는 특성을 선택하거나 제거하는 방법

  • 특성 선택을 위해 반복적으로 모델을 생성하며, 각 반복에서 가장 좋은 성능을 보이는 특성 또는 성능에 덜 기여하는 특성을 골라낸다.
  • 탐욕적 최적화 알고리즘의 일종으로, 최적의 특성 집합을 찾는 데 목표를 두고 있다.
  • 매 반복마다 모델을 생성한 후 가장 성능이 좋은 특성 또는 성능에 영향을 덜 미치는 특성을 따로 분리한다.
  • 남은 특성들을 사용해 다시 모델을 학습시키는 과정을 반복하고 이러한 과정은 모든 특성이 다 사용되거나 제거될 때까지 계속한다.
  • 이후, 특성이 제거된 순서에 따라 특성들의 중요도를 순위로 매긴다.
  • 만약 데이터셋에 N개의 특성이 있다면, 최악의 경우 RFE는 2N개의 특성 조합을 탐색하는 과정을 거치게 될 수 있다.

 

교차 검증을 통한 재귀적 피처 제거(RFECV, Recursive Feature Elimination with Cross-Validation)

모델을 여러 번 학습시키고, 각 단계에서 가장 성능에 미치는 영향이 작은 피처를 제거하는 방법

피처를 0개부터 N개까지 반복적으로 제거하면서 최적의 피처 집합을 선택하는 방법으로 모델의 정확도, 교차 검증 점수, 또는 ROC-AUC에 기반하여 최적의 피처 집합을 선택한다.

 

임베디드 방법(Embedded Methods)

반복적인 특성을 가지며, 각 반복 단계에서 모델 학습 과정 중 가장 중요한 피처를 신중하게 추출하는 방법이다. 

정규화(Regularization) 방법이 가장 많이 사용되는 임베디드 방법으로, 주어진 계수(특성의 중요도)에 대한 임계값을 기준으로 피처에 패널티를 부여한다. 따라서 정규화 방법을 패널티 방법이라고도 부르며, 이는 예측 알고리즘(예: 회귀 알고리즘)의 최적화 과정에 추가적인 제약을 도입하여 모델이 더 단순해지도록 유도한다.

대표적인 예로는 LASSO와 RIDGE 회귀가 있으며, 이들은 내장된 패널티 기능을 통해 과적합을 줄이는 데 도움을 준다.

 

1. LASSO 회귀(LASSO Regression)

L1 정규화(regularization)를 수행하며, 이때 모델의 계수(피처의 중요도) 크기의 절대값에 비례하는 패널티를 추가한다.

정규화는 머신 러닝 모델의 다양한 파라미터에 패널티를 추가하여 모델의 자유도를 줄이고, 과적합(overfitting)을 방지하는 데 목적이 있다.

선형 모델 정규화에서는 패널티가 각 예측 변수(피처)와 곱해지는 계수에 적용된다. Lasso(L1 정규화)는 특정 피처의 계수를 0으로 줄이는 특성을 가지고 있다. 즉, 특정 피처의 중요도가 낮다면, 그 피처를 모델에서 제거할 수 있다.

 

너무 높은 패널티를 설정해서 중요한 피처까지 제거하지 않도록 주의해야하며, 반대로 패널티가 너무 낮아 중요하지 않은 피처가 제거되지 않는 상황도 주의해야 한다. 만약 패널티가 너무 높아 중요한 피처가 제거되면, 알고리즘의 성능이 떨어지기 때문에 결과를 확인하며 조정해야 한다.

from sklearn.linear_model import Lasso
from sklearn.feature_selection import SelectFromModel
from sklearn.preprocessing import StandardScaler

scaler = StandardScaler()
scaler.fit(X_train.fillna(0))

sel_ = SelectFromModel(Lasso(alpha=100))
sel_.fit(scaler.transform(X_train.fillna(0)), y_train)


selected_feat = X_train.columns[(sel_.get_support())]

print('total features: {}'.format((X_train.shape[1])))
print('selected features: {}'.format(len(selected_feat)))
print('features with coefficients shrank to zero: {}'.format(np.sum(sel_.estimator_.coef_ == 0)))
total features: 164
selected features: 0
features with coefficients shrank to zero: 164

위와 같이 출력된다. Lasso 회귀모델에 의해 선택된 중요한 특성이 0개라는 것을 의미한다. 중요한 특성이 0인 이유는 alpha=100이라는 값은 Lasso의 정규화 강도가 매우 높으며, 데이터셋에 대해 더 많은 전처리가 필요할 수 있기 때문이다.

 

2. 랜덤 포레스트 중요도(Random Forest Importance)

랜덤 포레스트는 좋은 예측 성능, 낮은 과적합, 그리고 쉬운 해석 가능성을 제공한다. 특히, 해석 가능성은 각 feature가 의사결정 과정에 얼마나 기여했는지를 파악하기 쉽다. 랜덤 포레스트의 feature_importances_를 통해 쉽게 확인할 수 있다. 

아래는 필자가 게시한 타이타닉 생존자 예측 글에서 일부만 가져온 것으로 아래 그래프처럼 확인할 수 있다.

sns.barplot(x=best_rf.feature_importances_ , y=feature_names)

 

 

적절한 피처 선택 방법을 선택하는 방법

Numerical Input, Numerical Output

회귀 예측 모델링 문제로, 입력 변수와 출력 변수가 모두 숫자형으로 일반적으로 상관 계수(correlation coefficient)를 사용하는 것이다.

 

  • Pearson 상관계수 (선형 상관관계).
  • Spearman 순위 상관계수 (비선형 상관관계)

Numerical Input, Categorical Output

분류 예측 모델링 문제로, 입력 변수는 숫자형이고 출력 변수는 범주형으로 일반적으로 상관 기반 방법이지만, 이 경우 범주형 타겟을 고려해야 한다.

  • ANOVA 상관계수 (선형 상관관계).
  • Kendall 순위 상관계수 (비선형 상관관계).
    • Kendall은 범주형 변수가 서열형(ordinal)일 때 사용할 수 있습니다.

 

Categorical Input, Numerical Output

회귀 예측 모델링 문제로, 입력 변수가 범주형이고 출력 변수가 숫자형으로 Numerical Input, Categorical Output 방법을 역으로 이용할 수 있다.

 

Categorical Input, Categorical Output

분류 예측 모델링 문제로, 입력 변수와 출력 변수가 모두 범주형으로 일반적으로 카이제곱 검정(Chi-Squared test)을 사용한다. 또한, 정보 이론 분야에서 나온 상호 정보(Mutual Information) 방법도 사용할 수 있다.

  • 카이제곱 검정 (교차표 사용)
  • 상호 정보(Mutual Information)

 

Tips and tricks for feature selection

상관관계 통계

scikit-learn 라이브러리는 대부분의 유용한 통계 측정법을 구현하고 있다.

  • Pearson 상관계수: f_regression()
  • ANOVA: f_classif()
  • 카이제곱(Chi-Squared): chi2()
  • 상호 정보(Mutual Information): mutual_info_classif() 및 mutual_info_regression()

또한, SciPy 라이브러리는 Kendall’s tau (kendalltau) 및 Spearman 순위 상관(Spearman’s rank correlation) (spearmanr)과 같은 추가 통계 방법들을 제공한다.

선택 방법

scikit-learn은 통계값이 계산된 후 여러 필터링 방법을 제공하는데 그 중에서 많이 사용하는 두 가지 방법 아래와 같다.

  • 상위 k개의 변수를 선택: SelectKBest
  • 상위 백분위수 변수를 선택: SelectPercentile

변수 변환

변수를 변환하여 다양한 통계 방법을 적용해볼 수 있다. 예를 들어, 범주형 변수를 서열형으로 변환하여 새로운 결과를 얻을 수 있다.

숫자형 변수를 이산형(예: 구간화(bins))으로 변환하여 범주형 기반 측정을 시도할 수도 있다.

일부 통계 측정법은 변수의 특성을 가정한다. 예를 들어, Pearson 상관계수는 데이터가 **정규분포(Gaussian probability distribution)**를 따르고, 선형 관계가 있음을 가정한다. 데이터를 이러한 테스트의 기대에 맞게 변환하거나, 기대와 상관없이 테스트를 시도하여 결과를 비교할 수 있다.

 

최고의 방법은 무엇인가?

최고의 피처 선택 방법은 없다. 마찬가지로, 최고의 입력 변수 집합이나 최고의 머신 러닝 알고리즘도 존재하지 않는다. 대신, 체계적인 실험을 통해 특정 문제에 가장 잘 맞는 방법을 찾아야 한다.

다양한 통계 측정법을 사용하여 선택된 피처로 여러 모델을 테스트해보고, 특정 문제에 어떤 방법이 가장 효과적인지 확인해야 한다.

 

피처 선택의 4가지 최선의 방법

피처 선택에서 최상의 결과를 얻을 수 있는 4가지 실용적인 방법

  1. SelectKBest
  2. 재귀적 피처 제거(Recursive Feature Elimination)
  3. 상관행렬(correlation matrix) 및 히트맵
  4. 랜덤 포레스트 중요도(Random Forest Importance)

 

 

728x90