* 본 포스트는 개인연구/학습 기록 용도로 작성되고 있습니다.


[Python] 보루타 알고리즘을 통한 변수선택


보루타알고리즘랜덤포레스트(RandomForest)를 기반으로하는 변수선택기법이다.
랜덤포레스트는 다수의 의사결정나무를 앙상블 배깅하는 모델로, 분류작업을 위한 모든 의사결정나무들은 정확도 손실 계산의 평균과 표준편차를 갖는다. 이를 활용한 Z-score값은 변수선택에 있어 직접적인 통계적유의성을 갖지는 않는다. 더구나 변수의 중요는 0~1의 분포를 갖지도 않는다.

하지만 보루타 알고리즘에서는 Z-score를 변수 중요도 판단 요소로 사용하게 된다. 대신, Z-score를 직접 사용하지 않고 외부 요소를 더해 활용한다.

특정 변수가 중요한지 여부를 판단할때 그에 대한 임의의 변동, 즉 데이터를 복제 후 항목들을 임의의 값으로 섞는다. 이러한 무작위성을 통해 새로운 속성 데이터를 확보(‘shadow 속성’)한 후 분류를 수행한다.

‘shadow 속성’의 중요도 여부는 본래의 속성의 여부를 파악하기 위한 참조값으로 활용된다. 판단은 변수의 ‘shadow 속성’의 최대 Z-score보다 높은 Z-score가 있는지 여부로 결정된다.

통계적으로 유의한 결과를 얻기 위해 위의 작업을 셔플링 후 반복 수행하게된다.

쉽게 이해해 보자면, 결국 어떠한 속성이 있고 그 변수 혹은 조합을 통한 변수를 ‘파생변수’생성하듯 ‘Shadow’변수를 만들어내 모든 변수를 대상으로 앙상블하고 loss를 줄여나가는 최적의 변수를 찾아낸다.

결과값은 랭킹으로 반환된다.


동작 과정


  1. 모든 피쳐들을 복사해서 새로운 칼럼을 생성한다.
  2. 복사한 피쳐들 (섀도우 피쳐) 각각을 따로 섞는다.
  3. 섀도우 피쳐들에 대해서 랜덤 포레스트를 실행하고, Z score를 얻는다.
  4. 얻은 Z score 중에서 최댓값인 MSZA를 찾는다. (MSZA, Max Z-score among shadow attributes)
  5. 기존 피쳐들에 대해서 랜덤 포레스트를 실행하여 Z score를 얻는다. 각각의 기존 피쳐들에 대해서 Z-score > MSZA 인 경우 히트 수를 올린다.
  6. Z-score <= MSZA인 경우, MSZA에 대해서 two-side equality test를 수행한다.
  7. 통계적으로 유의한 수준에서 Z-score < MSZA인 경우, 해당 피쳐를 중요하지 않은 피쳐로 드랍한다.
  8. 통계적으로 유의한 수준에서 Z-score > MSZA인 경우, 해당 피쳐를 중요한 변수로 둔다.
  9. 모든 피쳐들의 중요성이 결정되거나 최대 반복 회수에 도달할 때까지 Step 5부터 반복한다.

Boruta 알고리즘의 시간 복잡도는 O(P⋅N)이다.

P : 피쳐의 개수 N : 데이터의 행



파이썬 코드

# load X and y
# NOTE BorutaPy accepts numpy arrays only, hence the .values attribute
X = pd.read_csv('examples/test_X.csv', index_col=0).values
y = pd.read_csv('examples/test_y.csv', header=None, index_col=0).values
y = y.ravel()

# define random forest classifier, with utilising all cores and
# sampling in proportion to y labels
rf = RandomForestClassifier(n_jobs=-1, class_weight='balanced', max_depth=5)

# define Boruta feature selection method
feat_selector = BorutaPy(rf, n_estimators='auto', verbose=2, random_state=1)

# find all relevant features - 5 features should be selected
feat_selector.fit(X, y)

# check selected features - first 5 features are selected
feat_selector.support_

# check ranking of features
feat_selector.ranking_

# call transform() on X to filter it down to selected features
X_filtered = feat_selector.transform(X)



Reference


Tags:


Back to blog