#!/usr/bin/env python3


feature selection based model(모델 기반 특성 선택)


0. 살펴보기

feature selection based model모델 기반 특성 선택지도 학습 machine learning 모델을 사용하여

1. 특성의 중요도를 평가

2. 가장 중요한 특성들만 선택함


특성 선택에 사용하는 지도 학습 모델은 최종적으로 사용할 지도 학습 모델과 같을 필요는 없음

특성 선택을 위한 모델은 각 특성의 중요도를 측정하여 순서를 매길 수 있어야


decision tree는 각 특성의 중요도가 담겨있는 feature_importances_를 제공

decision tree : [1]Decision Tree


선형 모델 계수의 절댓값도 특성의 중요도를 평가하는 데 사용할 수 있음

L1규제를 사용한 선형 모델은 일부 특성의 계수만 학습(Lasso)

이는 그 모델 자체를 위해 특성이 선택된다고 생각할 수 있지만,

다른 모델의 특성 선택을 위해 전처리 단계로 사용할 수도 있음


Lasso : Lasso



단변량 분석과는 반대로 feature selection based model

한 번에 모든 특성을 고려하므로(사용된 모델이 상호작용을 잡아낼 수 있다면)

상호작용 부분을 반영할 수 있음


SelectFromModel은 (지도 학습 모델로 계산된) 중요도가 지정한 임계치보다 큰 모든 특성을 선택

이는 매우 복잡한 모델이고 단변량분석보다 훨씬 강력한 방법



1. breast cancer 데이터를 통한 단변량 분석과 모델 기반 특성 선택의 비교

### library import

from sklearn.datasets import load_breast_cancer

from sklearn.feature_selection import SelectFromModel, SelectPercentile

from sklearn.ensemble import RandomForestClassifier

from sklearn.linear_model import LogisticRegression

from sklearn.model_selection import train_test_split

import matplotlib.pyplot as plt

import matplotlib

import numpy as np


### matplotlib 한글, 축 - 설정

matplotlib.rc('font', family='AppleGothic')

plt.rcParams['axes.unicode_minus'] = False


### datasets

cancer = load_breast_cancer()

# print(cancer.data.shape)


### noise

rnd = np.random.RandomState(seed=0)

noise = rnd.normal(size=(cancer.data.shape[0], 70))


### np.hstack

cancer_data_noise = np.hstack([cancer.data, noise])


### data 분할

x_train, x_test, y_train, y_test =\

  train_test_split(cancer_data_noise, cancer.target,

                   random_state=0, test_size=0.3)


### 특성을 고를 model 적용

randforest = RandomForestClassifier(n_estimators=100, random_state=0)

select_model = SelectFromModel(randforest, threshold='median').fit(x_train, y_train)


select_uni = SelectPercentile(percentile=50).fit(x_train, y_train)



### visualization

models = [select_uni, select_model]

_, axes = plt.subplots(3, 1)


ones = np.ones(x_train.shape[1], dtype=np.bool)

axes[0].matshow(ones.reshape(1, -1), cmap='gray')

axes[0].set_yticks([])

axes[0].set_title('full feature')


for model, ax in zip(models, [axes[1], axes[2]]):

    x_train_model = model.transform(x_train)

    x_test_model = model.transform(x_test)


    idx = model.get_support()

    ax.matshow(idx.reshape(1, -1), cmap='gray')

    ax.set_yticks([])

    ax.set_title('{}'.format(model.__class__.__name__))

plt.show()


특성의 전체 선택, 단변량 선택, 모델기반선택으로 선택한 특성



### 일반화

logreg = LogisticRegression().fit(x_train, y_train)

score = logreg.score(x_test, y_test)

print('total 특성의 정확도: {:.3f}'.format(score))

models = [select_uni, select_model]

names = ['univariate', 'model_based']

for model, name in zip(models, names):

    x_train_model = model.transform(x_train)

    x_test_model = model.transform(x_test)

    logreg = LogisticRegression().fit(x_train_model, y_train)

    score = logreg.score(x_test_model, y_test)

    print('{}의 정확도: {:.3f}'.format(name, score))

각 모델별 정확도


#!/usr/bin/env python3


univariate analysis(단변량 분석)


0.살펴보기

univariate analysis단변량 통계에서는

1. 개개의 특성target 사이에 중요한 통계적 관계가 있는지를 계산

2. 깊게 관련되어 있다고 판단되는 특성을 선택


분산분석 : 데이터를 클래스별로 나누어 평균을 비교하는 방법

분산분석으로 계산한 어떤 특성의 F-통계량이 높으면 그 특성은 클래스별 평균이 서로 다르다는 뜻

분류에서는 ANOVA, analysis of variance분산분석


사용하는 분포는 F-distribution

0. 기본적인 형태는 group(1) / group(2), 큰 값을 분자로 사용하여 최솟값을 1이 되게함

1. H0 = 클래스들의 평균과 분산이 같다

2. H0상태에서의 F-distribution 그래프를 그림

3. F-통계량이 1(좌측)에 가까운 수가 나올수록 두 집단은 비슷한 평균과 분산을 갖음

4. F-통계량이 1에 가까울수록 p-value의 값은 커짐 ==> target에 미치는 영향이 적다고 판단

5. p-value는 pvalues_에 저장됨

6. scikit-learn의 SelectBest, SelectPercentile에서 특성을 선택하는 기준은 F-통계값

7. F-통계값은 scores_에 저장됨


이 방법의 핵심 요소는 univariate, 즉 각 특성이 독립적으로 평가됨

==> 따라서 다른 특성과 깊게 연관된 특성은 선택되지 않을 것으로 예상 가능


이 방법의 특징은

1. 계산이 매우 빠르고 평가를 위해 모델을 만들 필요가 없음

2. 특성을 선택한 후 적용하려는 모델에 상관없이 사용 가능


scikit-learn에서 univariate로 특성을 선택하려면 

1. 분류에는 f_classif(default)를, 회귀에서는 f_regression을  선택하여 테스트

2. 계산한 p-value에 기초하여 특성을 제외하는 방식을 선택. 


이런 방식들은 매우 높은 p-value를 가진(target값과 연관성이 적은) 특성을 제외할 수 있도록 critical value를 조정하는 parameter를 사용

critical value를 계산하는 방법중 하나인 SelectKBest는 고정된 k개의 특성을 선택하고 SelectPercentile은 지정된 비율만큼 특성을 선택



1. cancer data에서 univariate analysis(단변량 분석)하기

### library import

from sklearn.datasets import load_breast_cancer

from sklearn.feature_selection import SelectPercentile

from sklearn.model_selection import train_test_split

import numpy as np

import matplotlib

import matplotlib.pyplot as plt


### matplotlib 한글출력, 축- 설정

matplotlib.rc('font', family='AppleGothic')

plt.rcParams['axes.unicode_minus'] = False


### dataload

cancer = load_breast_cancer()


### preprocessing

rng = np.random.RandomState(seed=0) # random seed

noise = rng.normal(size=(cancer.data.shape[0], 50)) # normal분포에서 cancer.data.shape[0]x50의 데이터추출

cancer_data_noise = np.hstack([cancer.data, noise]) # data 병합

print('cancer_data_noise.shape \n{}'.format(cancer_data_noise.shape)) # (569, 80)


### data 분할

x_train, x_test, y_train, y_test = \

  train_test_split(cancer_data_noise, cancer.target,

                   test_size=0.5, random_state=0)


### preprocessing 메소드 호출 및 적용

select = SelectPercentile(percentile=50).fit(x_train, y_train) # percentile: 50%만 선택

x_train_select = select.transform(x_train) # 적용

x_test_selected = select.transform(x_test)


print('x_train.shape \n{}'.format(x_train.shape))

print('x_train_select.shape \n{}'.format(x_train_select.shape))

합친 데이터와 선택된 데이터의 형태

>>  특성의 갯수가 80에서 40개로 줄음



2. 어떤 특성이 선택되었는지 확인


idx = select.get_support()[각주:1]

print('idx \n{}'.format(idx))

논리값으로 만들어진 idx


plt.matshow(idx.reshape(1, -1), cmap='gray_r')

plt.yticks([]) # 축눈금없애기

plt.xlabel('feature number')

plt.show()


SelectPercentile이 선택한 특성


>> 마스킹된 그래프에서 볼 수 있듯이 선택된 특성은 대부분 원본특성이며, 노이즈 특성은 거의 제거됨을 볼 수 있음




3. 전체 특성을 이용했을 때와 선택된 특성만 사용했을 때 로지스틱 회귀 성능 비교


Logistic Regression 링크 참조

[1]Logistic Regression[1], [2]Logistic Regression[2]


### library import

from sklearn.linear_model import LogisticRegression


### model 호출

lr = LogisticRegression()


### 전체특성을 사용했을 때 정확도

lr.fit(x_train, y_train)

print('전체 특성을 사용한 점수: \n{:.3f}'.format(lr.score(x_test, y_test))) # 0.937


### 일부특성을 사용했을 때 정확도

lr.fit(x_train_select, y_train)

print('선택된 특성을 사용한 점수 \n{:.3f}'.format(lr.score(x_test_selected, y_test))) # 0.951


>> 이 경우에는 일부 원본 특성이 없더라도 노이즈 특성을 제거한 쪽의 성능이 더 높음

이 예는 인위적으로 간단하게 만들었고 실제 데이터에서는 엇갈리는 경우도 많음

너무 많은 특성 때문에 모델을 만들기가 현실적으로 어려울 때 univariate를 사용하거나,

많은 특성들이 확실히 도움이 안된다고 생각할 때 사용

  1. get_support(): 선택된 특성을 논리값으로 표시 [본문으로]

#!/usr/bin/env python3


feature auto-selection --intro


새로운 특성을 만드는 방법이 많으므로 데이터의 차원이 원복 특성의 수 이상으로 증가

따라서 모델은 더 복잡해지고 overfitting될 가능성도 높아짐

새로운 특성을 추가하거나, 고차원 데이터셋을 사용할 때 가장 유용한 특성만 선택하여 차원을 줄이는 것이 좋음

이렇게 하면 모델이 간단해지고 일반화 성능이 올라감


어떤 특성이 좋은지 아는 방법에는 크게 3가지가 있음

1. univariate statics일변량통계

2. model-based selection모델기반선택

3. iterative selection반복적 선택


이 방법들은 모두 지도학습이므로 target값이 필요하며

train set에만 특성 선택에 사용해야함

+ Recent posts