Wrapper feature selection

~.~·2022년 6월 27일
0

ML

목록 보기
1/5

Feature selection

feature selection 은 크게 다음과 같이 나뉜다.

  • filter방법
    : chi2, fisher, mrmr 등의 통계적 방법을 통하여 feature를 추출.
    model 에 dependency 하지 않고 전체 data의 연관정도를 봄

  • model dependency 를 통한 방법
    1) wrapper feature selecion : 하나씩 제거하거나, 추가하여 모델에 영향을 주는 feature 선택
    이와 같이 하나씩

    2) embedded feature selection : 모델 내 feature importance 이용하여 feature selection. 이때 LASSO와 같은 정규화 제한이 들어감.

sklearn에서는 filter 는 기본으로 여러 model을 기반으로 한 feature selection 을 제공한다.

Sklearn 의 Sequential feature selection 작동원리

sequential feature selection 은 wrapper 방식으로 0개부터 하나씩 feature를 추가하면서 모델의 성능을 높이는 (scoring) 변수를 탐색한다.

자세히 보면 아래와 같은데,

Concretely, we initially start with zero feature and find the one feature that maximizes a cross-validated score when an estimator is trained on this single feature

하나씩 feature 추가하면서 교차 검증을 수행 한 후 교차 검색 점수를 최대화하는 feature를 찾으며, 이 때의 교차 검색 점수는 평균 score 로 계산된다.

즉,

하나씩 넣어보고 -> score 계산 ( 이 때 cv 이므로 fold set 개수만큼 수행된다) -> feature 추가
의 과정을 거친다.

select from model의 경우 모델 내에서 feature importance 계산 후 일정 threshold이상의 feature 만 select 하는데 이에 비해서 당연히 오랜 시간이 걸린다.

--

추가적으로 recursive feature elimination 도 sklearn.feature_selection.RFE 를 통해 제공하는데, sfs 와 다르게 전체 feature 에서 feature 의 수를 줄여가며 주요 feature 를 계산한다.

마찬가지로 estimator를 이용하여 가장 높은 score (acc, recall, ... )을 가지는 feature를 남겨준다.

parameter

  • estimator
    sklearn에서 제공하는 classifier, regressor

  • n feature to select
    디폴트는 auto이며 tol에 따라 추출 개수가 다르다.
    tol 지정 시 : tol에서 지정한 횟수 동안 score 향상이 없을 때까지 선택
    지정 안할시에는 feature의 절반까지 ssf 진행

    아니면 추출할 feature 개수를 정해주거나 (int) , 비율을 정해줄 수 있다. (0 ~ 1)

  • tol
    early stopping 의 tolerance 같은 parameter

  • direction
    forward or backward
    디폴트는 forward

  • scoring
    improvement 판단의 기준.
    acc, recall, f1등을 선택 가능 (https://scikit-learn.org/stable/modules/model_evaluation.html#scoring-parameter 참고)
    혹은 metrics에서 본인이 정한 score를 지장할 수 도 있는듯.

일단은 acc를 기준으로 두고 sfs가 이뤄져야 한다. recall은 그 다음에 확인할 것.

  • cv
    cross validation 할 fold 지정.
    디폴트는 5이다.
    이번에는 10으로 설정하여 견고성을 확보

Attribute

  • n feature in_
  • feature name in_
  • n features to select_
  • support_

다 보면 추출된 feature의 개수, 이름 등에 대한 정보를 제공한다.

한꺼번에 추출했을때의 결과가 아닌 추출 n 개에 따른 성능 지표를 확인할 수 있으면 좋을듯,,-> mlxtend 사용

사용법

간단하게 estimator 정해서 fit 하면 된다.
그 후 transform 하면 선택된 feature로 데이터를 축소한다.

자체적으로 fit 기준 - scoring값을 알려주지는 않는 듯 함.

보려면 train set에서 성능을 봐야하나,,

아래는 추출된 feature로 testset predict 했다.

from sklearn.feature_selection import SequentialFeatureSelector
from sklearn.metrics import recall_score, accuracy_score

def wrapper(gender, scaling, model):
    _, train, test = load_dataframe(gender, scaling = scaling)
    x_train, y_train = train.iloc[:,1:], train.iloc[:,0]
    x_test, y_test = test.iloc[:,1:], test.iloc[:,0]

    selector = SequentialFeatureSelector(estimator = model, cv = 10, scoring='accurcy', n_features_to_select='auto',tol = 5, n_jobs=-1)
    
    selector.fit(x_train, y_train)
    model.fit(selector.transform(x_train), y_train)
    pred = model.predict(selector.transform(x_test))
    recall = recall_score(y_test, pred)
    accuracy = accuracy_score(y_test, pred)
    print(f'sensitivity  : {recall:.2f} , accuracy : {accuracy:.2f}, feature_num : {n_features}')
    

feature를 하나씩 추가했을 때의 결과를 보기 위해 tol 대신에 for문을 사용.

for n_features in range(1, 50):
    selector = SequentialFeatureSelector(estimator = model, cv = 10, scoring='accurcy', n_features_to_select=n_features, n_jobs=-1)
    selector.fit(x_train, y_train)
    model.fit(selector.transform(x_train), y_train)
    pred = model.predict(selector.transform(x_test))
    recall = recall_score(y_test, pred)
    accuracy = accuracy_score(y_test, pred)
    print(f'sensitivity  : {recall:.2f} , accuracy : {accuracy:.2f}, feature_num : {n_features}')

wrapper로 추출된 feature 이용 시 estimator는 고정하고, hyper parameter 튜닝이 이뤄져야 한다.

왜냐하면 모델 특이적 feature 기 때문.

이 때 Auto hyper parameter 기능을 이용.

.
.
.

extend ml을 이용하면 추출 n값당의 score를 볼 수 있는 듯 하다.

mlxtend

mlxtend : sklearn 기반 확장 패키지
sklearn의 classifier , regressor와 같이 쓸 수 있으며 hyper parameter optimization 과 feature selection , 시각화 등을 지원.

sequential feature selection은 이렇게 지원된다.

  1. Sequential Forward Selection (SFS)
  2. Sequential Backward Selection (SBS)
  3. Sequential Forward Floating Selection (SFFS)
  4. Sequential Backward Floating Selection (SBFS)

floting 기능은 아래와같다.

일반 sfs의 경우 empty set에서 시작해서 1) feature를 하나씩 추가하면서 2) citerion function 을 최대화 하는, 즉 classifier 의 best performance를 보이는 feature를 찾아 3) subset에 추가한다. 4) 이를 k번 (우리가 설정한 feature 개수) 수행하여 마친다. sffs의 경우는 sfs 에서 step2 를 거친다. step2 는 sfs에서 feature를 1개 추가한 후(step1) subset중에 하나씩을 제거해 보고 모델 performance가 향상되는지 확인하는 절차로, 이 때 제거 했을 때 성능이 좋아지면 제거 후 step1로 돌아가고(k = k-1) 그런 feature를 못찾으면 그냥 step1로 가서 다음 feature를 찾는다.

mlxtend SFS parameters

  • estimator : sklearn classifier or regressor
  • k_features : (default = 1) select할 feature 개수.
    1) int : 개수
    2) tuple : min, max 범위 . (1, 50)일 경우 1개 이상 50개 미만의 feature subsets 반환
    3) str : 'best' - cv 성능중 가장 좋은 feature subset // 'parsimonious' - 성능 오차 범위 내에서 가장 작은 개수의 feature subset
  • fixed_features : feature index로 꼭 포함될 feature 명시. 수가 k보다 작아야함.
def sfs_feature (model):
    X, y = data.iloc[:,1:] , data.iloc[:,0]

    sfs = SFS(model, 
           k_features=(1, 50), 
           forward=True,  
           verbose=1,
           scoring='accuracy',
           cv=10)
    sfs = sfs.fit(X, y)
    dic = sfs.subsets_
    return dic

mlxtend는 subsets_ 을 제공하여 feature 추가마다의 cv_score와 그때 추가되는 feature를 알 수 있다.

{1: {'feature_idx': (3,),
  'cv_scores': array([0.96]),
  'avg_score': 0.96,
  'feature_names': ('3',)},
 2: {'feature_idx': (2, 3),
  'cv_scores': array([0.97333333]),
  'avg_score': 0.9733333333333334,
  'feature_names': ('2', '3')},
 3: {'feature_idx': (1, 2, 3),
  'cv_scores': array([0.97333333]),
  'avg_score': 0.9733333333333334,
  'feature_names': ('1', '2', '3')}}

확인을 위해 json에 저장하였는데 , numpy 변환이 필요함

class NpEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, np.integer):
            return int(obj)
        if isinstance(obj, np.floating):
            return float(obj)
        if isinstance(obj, np.ndarray):
            return obj.tolist()
        return json.JSONEncoder.default(self, obj)
        
json.dump(dic,f,indent=4, sort_keys=True, cls=NpEncoder)

http://rasbt.github.io/mlxtend/user_guide/feature_selection/SequentialFeatureSelector/

feature selection예제 코드랑 설명이 상세함.

0개의 댓글