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 을 제공한다.
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를 남겨준다.
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은 그 다음에 확인할 것.
다 보면 추출된 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 : sklearn 기반 확장 패키지
sklearn의 classifier , regressor와 같이 쓸 수 있으며 hyper parameter optimization 과 feature selection , 시각화 등을 지원.
sequential feature selection은 이렇게 지원된다.
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를 찾는다.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예제 코드랑 설명이 상세함.