PP-feature engineering

장지백·2023년 12월 16일
0

prepreocessing(by python)

목록 보기
8/10

개요

1. 피처 엔지니어링이란?

1) 피처의 개념

  • 데이터 모델(인공지능)에서 예측을 수행하는 데 사용되는 입력변수
  • 통계학에서는 독립 변수라고 부름

2) 피처의 유형

  • 속성에 따라 -> 범주형 / 수치형
  • 인과관계에 따라 -> 독립변수(x값) / 종속변수(y값)
  • 머신러닝에서 명명 -> 입력(예측변수) / 출력(타겟)

3) 피처 엔지니어링 개념

  • 머신러닝 알고리즘의 성능을 향상시키기 위하여 변수를 조합하거나 새로
    운 변수를 만드는 과정(데이터에 대한 도메인 지식 필요)

4) 피처 엔지니어링 종류

  • 피쳐 추출(feature extraction)
  • 피쳐들 사이에 내재한 특성이나 관계를 분석하여 이들을 잘 표현할 수
    있는 새로운 선형 혹은 비선형 결합 변수를 만들어 데이터를 줄이는 방법
  • 고차원의 원본 피쳐 공간을 저차원의 새로운 피쳐 공간으로 투영
  • PCA(주성분 분석) / LDA(선형 판별 분석)
  • 피쳐 선택(feature selection)
  • 피쳐 중 타겟에 가장 관련성이 높은 피쳐만을 선정하여 피쳐의 수를
    줄이는 방법
  • 관련없거나 중복되는 피쳐들을 필터링하고 간결한 부분집합을 생성
  • 모델 단순화 / 훈련 시간 축소 / 차원의 저주 방지 / 과적합 축소
  • 과적합을 축소 : 데이터를 일반화해주는 장점을 지님
  • Filter / Wrapper /Embedded 기법5) 참고자료(순서대로 지도학습 / 비지도학습)
  • 지도학습
  • 비지도학습

피처 엔지니어링

1. 피처 추출(Feature Extraction) - PCA/LDA

1) 주성분 분석(Principal Component Analysis, PCA) 개념 및 특징

  • 가장 널리 사용되는 차원 축소 기법 중 하나
  • 원 데이터의 분산을 최대한 보존하면서 서로 직교하는 새 기저를 찾아
    고차원 공간의 표본 -> 선형 연관성이 없는 저차원 공간으로 변환
  • PCA는 기존의 변수를 조합하여 서로 연관성이 없는 새로운 변수인
    주성분들을 만들어 냄
  • 주성분의 개수를 증가시킴에 따라 원 데이터의 분산의 보존수준이 높아짐
  • 타겟값을 사용하지 않으므로 비지도학습임

2) 주성분 분석(Principal Component Analysis, PCA) 방식

  • 학습 데이터셋에서 분산이 최대인 축 찾기
  • 첫번째 축과 직교하면서 분산이 최대인 두 번째 축을 찾기
  • 첫번째 축과 두번째 축에 직교, 분산을 최대한 보존하는 세번째 축 찾기
  • 위와 같은 방법으로 데이터셋의 차원(피처의 개수)만큼의 축을 찾음

3) 선형판별분석(Linear Discriminant Analysis, LDA) 개념 및 특징

  • 입력 데이터 세트를 저차원 공간으로 투영해 차원을 축소함
  • 데이터의 타겟값(클래스)끼리 최대한 분리할 수 있는 축을 찾음
  • 지도학습임을 의미함

4) 선형판별분석(Linear Discriminant Analysis, LDA) 방식

  • 특정 공간상에서 클래스 분리를 최대화하는 축을 찾기 위해
    클래스 간 분산과 클래스 내부 분산의 비율을 최대화하도록 차원을 축소
  • 서포트 벡터 머신과같은 다른 분류 알고리즘을 적용하기 이전에 차원을
    축소시키는 데 사용

5) 코드(scikit-learn사용함)

  • 사전작업
# 필요한 라이브러리(클래스 / 함수) 가져오기
from sklearn import datasets
from sklearn.decomposition import PCA
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis

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

# iris 데이터셋의 피쳐(x) / 타겟(y)
X = iris.data 
y = iris.target

# iris 데이터셋의 타겟 이름 지정(list함수 사용)
target_names = list(iris.target_names)

# 결과확인
print(f'{X.shape = }, {y.shape = }') # 150개 데이터, 4 features
print(f'{target_names = }')  
  • PCA 적용
# PCA의 객체를 생성, 차원은 2차원으로 설정(현재는 4차원)
pca = PCA(n_components=2)

# PCA를 수행 / PCA는 비지도 학습 -> y값 포함 x
pca_fitted = pca.fit(X)

# 주성분 벡터 / 분산 비율 확인
print(f'{pca_fitted.components_ = }')
print(f'{pca_fitted.explained_variance_ratio_ = }')

# fit 해놓은 주성분 벡터로 데이터를 변환(transform)
X_pca = pca_fitted.transform(X)

# 결과 확인
print(f'{X_pca.shape = }')  
# +) 4차원 데이터가 2차원 데이터로 변환(축소)됨
  • LDA 적용
# LDA 객체 생성 / 차원 -> 2차원으로 설정(현재 4차원)
lda = LinearDiscriminantAnalysis(n_components=2)

# LDA를 수행 / LDA는 지도학습 -> y값 포함 o
lda_fitted = lda.fit(X, y)

# LDA의 계수 / LDA의 분산에 대한 설명 확인
print(f'{lda_fitted.coef_=}')
print(f'{lda_fitted.explained_variance_ratio_=}')

# 데이터 변환(transform)
X_lda = lda_fitted.transform(X)
print(f'{X_lda.shape = }')  
# +) 4차원 데이터 -> 2차원 데이터로 변환됨
  • 시각화하여 확인
# 필요한 라이브러리 가져오기
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd

# Seaborn을 이용하기 위해 데이터프레임으로 변환(seaborn은 df와 궁합)
df_pca = pd.DataFrame(X_pca, columns=['PC1', 'PC2'])
df_lda = pd.DataFrame(X_lda, columns=['LD1', 'LD2'])
y = pd.Series(y).replace({0:'setosa', 1:'versicolor', 2:'virginica'})

# subplot으로 시각화 / 시각화는 메인주제가 아니므로, 설명 생략함
fig, ax = plt.subplots(1, 2, figsize=(10, 4))

sns.scatterplot(df_pca, x='PC1', y='PC2', hue=y, style=y, ax=ax[0], palette='Set1')
ax[0].set_title('PCA of IRIS dataset')

sns.scatterplot(df_lda, x='LD1', y='LD2', hue=y, style=y, ax=ax[1], palette='Set1')
ax[1].set_title('LDA of IRIS dataset')

plt.show()

2. 피처 선택(feature selection)

1) 피쳐 선택 기법(종류)

  • Filter: 통계적인 방법사용 -> 선택
  • Wrapper: 모델 활용 -> 선택
  • Embedded: 모델 훈련 과정 -> 자동선택
  • Hybrid: Filter + Wrappe

2) 필터 기법(Filter Method)

  • 데이터의 통계적 측정 방법을 사용 -> 변수들의 상관관계를 알아냄
  • 계산속도가 빠름 / 변수 간 상관관계를 알아내는 데 적합
    -> 래퍼기법 사용 전, 전처리하는데 이용
  • 특정 모델링 기법에 의존 X / 데이터의 통계적 특성으로부터 변수선택
  • 필터기법 종류
  • 분산 기반 선택 : 분산이 낮은 변수를 제거하는 방법
  • 정보 소득 : 가장 정보 소득이 높은 속성을 선택(데이터 구분력 상승)
  • 추가) 카이제곱 검정 / 피셔 스코어 / 상관계수 ...
  • 코드(분산 기반 선택(Variance-based Selection)방식)
# 필요한 라이브러리(클래스 / 함수)가져오기
from sklearn import datasets
from sklearn.feature_selection import VarianceThreshold

# iris 데이터셋을 로드(테스트시 사용위함)
iris = datasets.load_iris()

# iris 데이터셋의 피처, 타겟 저장 / 피처,타겟 이름 저장
X = iris.data
y = iris.target
X_names = iris.feature_names
y_names = iris.target_names


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


# 적용(transform)시키기(분산이 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] = }')

+) 추가 : scikit-learn에서 피처선택 메서드 이용

  • SelectKBest(): 고정된 k개의 피쳐 선택기
  • f_classif(ANOVA F-value 분류 기법)
  • f_regression(F-value 회귀)
  • chi2(카이제곱 분류)
  • 코드
# 필요 라이브러리(클래스/ 함수)가져오기
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import f_classif, f_regression, chi2

# k개의 베스트 피쳐를 선택(SelectKBest)

# f_classif(ANOVA F-value 분류 기법) 사용
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)])

# f_regression(F-value 회귀) 사용
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)])

# 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)])

3) 래퍼 기법(Wrapper Method)

  • 가장 좋은 예측 정확도를 보이는 하위 집합을 선택하는 기법
  • 검색 가능한 방법으로 하위 집합을 반복해서 선택 후 테스트
    -> 탐욕 알고리즘이라고 불림
  • 반복하여 선택하는 방법으로 시간이 오래 걸리고 부분집합의 수가 기하
    급수적으로 늘어 과적합의 위험 발생가능
  • 일반적으로 래퍼 방법은 필터 방법보다 예측 정확도가 높음
  • 래퍼기법 종류
  • RFE(Recursive Feature Elimination)
  • 서포트 벡터 머신을 사용하여 재귀적으로 제거하는 방법
  • SFS(Sequential Feature Selection)
  • 그리디알고리즘 / 빈 부분 집합에서 특성변수를 하나씩 추가하는 기법
  • 코드
  • 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(서포트 벡터 머신)객체 생성 
svc = SVR(kernel="linear", C=3) # 선형분류 / 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)
# 데이터셋에 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] = }')
  • 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] = }')

4) 임베디드 기법(Embedded Method)

  • 임베디드 기법은 모델의 정확도에 기여하는 변수를 학습하는 기법
  • 임베디드 기법의 종류
  • SelectFromModel
  • 의사결정나무 기반 알고리즘에서 변수를 선택하는 기법
  • 코드
# 필요 라이브러리(클래스 / 함수) 가져오기
from sklearn.feature_selection import SelectFromModel
from sklearn import tree
from sklearn.datasets import load_iris

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

# 모형 구조 확인
sfm.set_output(transform='pandas') #  출력 -> 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
Data Scientist

0개의 댓글