Feature Engineering(2) - 피쳐선택

고은서·2023년 12월 17일
0

Data Preprocessing

목록 보기
8/10

피처 선택은 타겟(목표값, Target)과 가장 관련이 높은 변수만을 선정하여 피쳐의 수를 줄이는 방법으로, 관련이 없거나 중복되는 피쳐들을 필터링하고 간결한 부분집합을 구성하는 과정이다. 이는 모델을 단순화해주고, 훈련 시간을 축소해주며 차원의 저주를 방지, 과적합을 줄여 일반화해주는 장점이 있다.

3. Feature Selection

피쳐 선택기법의 종류

종속변수의 활용여부에 따라

Supervised: 종속변수를 활용하여 선택한다.
Unsupervised: 종속변수를 활용하지 않고 선택한다.

선택 방법론에 따라서

Filter: 통계적 방법을 활용하여 선택
Wrapper: 모델을 활용하여 선택
Embedded: 모델 훈련과정에서 자동적으로 선택
Hybrid: Filter와 Wrapper 방식을 혼합

3.1 필터 기법(Filter Method)

모든 필터 배정 -> 최적의 부분집합 선택 -> 학습 알고리즘 -> 성능평가

  • 데이터의 통계적 측정방법으로 변수들의 상관관계를 알아냄
  • 계산속도가 빠르고 변수들의 상관관계를 알아내는데에 적합한 방법
  • 특정 모델링 기법에 의존하지 않고 데이터의 통계적 특성으로 변수 선택하는 방법

3.1.1 필터기법의 종류

  1. 분산 기반 선택(Variance-based Selection)
    • 분산이 낮은 변수를 제거하는 방법
  2. 정보 소득(Information Gain)
    • 가장 정보 소득이 높은 속성을 선택하여 데이터를 더 잘 구분하게 되는 것
  3. 카이제곱 검정(Chi-Square Test)
    • 카이제곱 분포에 기초한 통계적 방법으로 관찰된 빈도가 기대되는 빈도와 의미있게 다른지 여부를 검증하기 위해 사용되는 검증 방법
  4. 피셔 스코어(Fisher Score)
    • 최대 가능성 방정식을 풀기 위해 통계에 사용되는 뉴턴(Newton)의 방법
  5. 상관계수(Correlation Coefficient)
    • 두 변수 사이의 통계적 관계를 표현하기 위해 특정한 상관관계의 정도를 수치적으로 나타낸 계수

3.1.2 분산기반선택

from sklearn import datasets
from sklearn.feature_selection import VarianceThreshold

# iris 데이터셋을 로드
iris = datasets.load_iris()

X = iris.data # iris 데이터셋의 피쳐들
y = iris.target # iris 데이터셋의 타겟
X_names = iris.feature_names # iris 데이터셋의 피쳐 이름
y_names = iris.target_names # iris 데이터셋의 타겟 이름

# 분산이 0.2 이상인 피쳐들만 선택하도록 학습
sel = VarianceThreshold(threshold=0.2).fit(X)
print(f'{sel.variances_ = }') # 각 피쳐의 분산 확인

# 분산이 0.2 이상인 피쳐들만 선택 적용
X_selected = sel.transform(X) # 분산이 0.2 이상인 피쳐들만 선택
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]])

# Scikit-Learn 제공 피쳐 선택 메서드

- SelectKBest(): 고정된 k개의 피쳐 선택기
- SelectPercentile(): 분위수 기반 선택기
- SelectFpr(): False positive rate 기반 선택기
- SelectFdr(): 추정된 False discovery rate 기반 선택기
- SelectFwe(): familiy-wise error rate 기반 선택기
- GenericUnivariateSelect(): 단변량 피쳐 선택기
# Scikit-Learn 제공 피쳐 선택 기준

- f_classif: ANOVA F-value 분류
     - F-value: 두 모집단(확률변수)의 분산의 비율을 나타내는 값
- mutual_info_classif: 상호정보량(mutual information) 분류
    - 상호정보량: 하나의 확률변수가 다른 하나의 확률변수에 대해 제공하는 정보의 양
    - 두 확률변수가 공유하는 엔트로피
        - 두 확률변수가 독립이라면, 상호정보량은 0
        - 두 확률변수의 상관관계가 강할수록 상호정보량이 커짐
- chi2: 카이제곱 분류
    - 범주형 데이터에서 두 요인간 독립성 검정에서 사용
    - 카이제곱 value가 크면 두 요인간 독립이 아니라는 의미(즉, 상관관계가 있음)
- f_regression: F-value 회귀
- mutual_info_regression: 상호정보량(mutual information) 회귀
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import f_classif, f_regression, chi2

# k개의 베스트 피쳐를 선택
sel_fc = SelectKBest(f_classif, k=2).fit(X, y)
print('f_classif: ')
print(f'{sel_fc.scores_ = }')
print(f'{sel_fc.pvalues_ = }')
print(f'{sel_fc.get_support() = }')
print('Selected features: ', [X_names[i] for i in sel_fc.get_support(indices=True)]) # 선택된 피쳐들의 이름

sel_fr = SelectKBest(f_regression, k=2).fit(X, y)
print('\nf_regression: ')
print(f'{sel_fr.scores_ = }')
print(f'{sel_fr.pvalues_ = }')
print(f'{sel_fr.get_support() = }')
print('Selected features: ', [X_names[i] for i in sel_fr.get_support(indices=True)]) # 선택된 피쳐들의 이름

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)]) # 선택된 피쳐들의 이름

fclassif:
sel_fc.scores
= array([ 119.26450218, 49.16004009, 1180.16118225, 960.0071468 ])
selfc.pvalues = array([1.66966919e-31, 4.49201713e-17, 2.85677661e-91, 4.16944584e-85])
sel_fc.get_support() = array([False, False, True, True])
Selected features: ['petal length (cm)', 'petal width (cm)']

fregression:
sel_fr.scores
= array([ 233.8389959 , 32.93720748, 1341.93578461, 1592.82421036])
selfr.pvalues = array([2.89047835e-32, 5.20156326e-08, 4.20187315e-76, 4.15531102e-81])
sel_fr.get_support() = array([False, False, True, True])
Selected features: ['petal length (cm)', 'petal width (cm)']

chi2:
selchi2.scores = array([ 10.81782088, 3.7107283 , 116.31261309, 67.0483602 ])
selchi2.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)']

3.2 래퍼기법 (Wrapper Method)

모든 피쳐 배정 -> 부분집합 형성 -> 학습 알고리즘- > 성능평가
반복하여 최적의 부분집합을 찾는다.

  • 예측 정확도 측면에서 가장 좋은 성능을 보이는 하위집합을 선택하는 기법
  • 모델의 성능을 기반으로 특성을 제거하거나 선택하는 기법
  • 특성 부분 집합을 만들고 평가하며 최적의 특성 집합을 찾으려고 한다.

래퍼기법 특징

  1. 검색 가능한 방법으로 하위 집합을 반복해서 선택 및 테스트 하는 방법으로 Greedy Algorithm 에 속하는 방법이다.
  2. 반복하여 진행하는 방법으로 시간이 오래 걸림
  3. 부분집합의 수가 많아져 과적합의 위험이 있음
  4. 일반적으로 래퍼기법은 필터기법보다 정확도가 높음

변수 선택을 위한 알고리즘

  1. 전진 선택법(Foward Selection): 모형을 가장 많이 향상시키는 변수를 점진적으로 하나씩 추가한다.
  2. 후진 선택법(Backward Selection): 모두 포함된 상태에서 영향력이 큰 변수를 하나씩 추가한다.
  3. 단계적 방법(Stepwise Method): 전진 선택법과 후진 선택법이 결합된 방법으로 각 단계에서 최상의 속성을 선택하고, 최악의 속성은 제거한다.
  4. 의사결정나무

3.2.1 RFE(Recursive Feature Elimination)

- SVM(Support Vector Machine)을 사용하여 재귀적으로 제거하는 방법
- 전진 선택, 후진 제거, 단계적 방법 사용
  • 작동방식
    1. 모든 특성을 사용하여 모델을 학습
    2. 특성 중요도 또는 가중치를 기준으로 가장 중요하지 않은 특성을 제거
    3. 제거된 특성을 제외한 나머지 특성으로 모델을 재학습
    4. 목표한 특성의 개수에 도달할 때까지 2-3 단계를 반복
# RFE(Recursive Feature Elimination) 적용
from sklearn.datasets import load_iris
from sklearn.feature_selection import RFE, RFECV, SelectFromModel, SequentialFeatureSelector
from sklearn.svm import SVC, SVR

# iris 데이터셋 로드
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_)

# rank가 1인 피쳐들만 선택
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_)

# rank가 1인 피쳐들만 선택
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]])

3.2.2 SFS(Sequential Feature Selection)

- 그리디 알고리즘(Greedy Algorithm)으로 빈 부분 집합에서 특성 변수를 하나씩 추가하는 방법
- 전진 선택, 후진 제거 사용
# SFS(Sequential Feature Selector) : 순차적으로 특성을 선택하는 방법

from sklearn.feature_selection import SequentialFeatureSelector
from sklearn.neighbors import KNeighborsClassifier
from sklearn.datasets import load_iris

# 데이터를 로드하고, 분류기를 초기화한 후 SFS를 적용
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]])

3.3 임베디드 기법

모든 피쳐 배정 -> 부분집합 형성 -> 학습 알고리즘- > 성능평가
반복하여 최적의 부분집합을 찾는다.

  • 임베디드 기법은 모델의 정확도에 기여하는 변수를 학습한다.

임베디드 기법의 종류

  • SelectFromModel
    • 의사결정나무 기반 알고리즘에서 변수를 선택하는 기법
from sklearn.feature_selection import SelectFromModel
from sklearn import tree
from sklearn.datasets import load_iris

# 데이터를 로드하고, 분류기를 초기화한 후 SFS를 적용
X, y = load_iris(return_X_y=True)
clf = tree.DecisionTreeClassifier()
sfm = SelectFromModel(estimator=clf)

# 모형 구조 확인 및 출력을 pandas로 설정
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()
profile
cities and data

0개의 댓글

관련 채용 정보