본문 바로가기

Lecture ML

머신러닝 강좌 #17] GBM(Gradient Boost Machine)

반응형

부스팅 알고리즘은 여러 개의 약한 학습기를 순차적으로 학습-예측하면서 잘못 예측한 데이터에 가중치 부여를 통해 오류를 개선해 나가면서 학습하는 방식입니다. 부스팅의 대표적인 구현은 AdaBoost(Adaptive Boosting)와 그래디언트 부스트가 있습니다. 에이다 부스트(AdaBoost)는 오류 데이터에 가중치를 부여하면서 부스팅을 수행하는 대표적인 알고리즘입니다. 

 

GBM(Gradient Boost Machine)도 에이다부스트와 유사하나, 가중치 업데이트를 경사 하강법(Gradient Descent)을 이용하는 것이 큰 차이입니다. 이 경사 하강법은 머신러닝에서 중요한 기법 중 하나이며 여기에서는 '반복 수행을 통해 오류를 최소화할 수 있도록 가중치의 업데이트 값을 도출하는 기법' 정도로 이해 바랍니다.

 

GBM은 CART기반의 다른 알고리즘과 마찬가지로 분류는 물론이고, 회귀도 가능합니다. 

 

from sklearn.ensemble import GradientBoostingClassifier
import time
import pandas as pd
from sklearn.metrics import accuracy_score
import warnings
warnings.filterwarnings('ignore')

def get_new_feature_name_df(old_feature_name_df):
    feature_dup_df = pd.DataFrame(data=old_feature_name_df.groupby('column_name').cumcount(), columns=['dup_cnt'])
    feature_dup_df = feature_dup_df.reset_index()
    new_feature_name_df = pd.merge(old_feature_name_df.reset_index(), feature_dup_df, how='outer')
    new_feature_name_df['column_name'] = new_feature_name_df[['column_name', 'dup_cnt']].apply(lambda x : x[0]+'_'+str(x[1])
                                                                                           if x[1] >0 else x[0] ,  axis=1)
    new_feature_name_df = new_feature_name_df.drop(['index'], axis=1)
    return new_feature_name_df

def get_human_dataset():
    # 각 데이터 파일들은 공백으로 분리되어 있으므로 read_csv에서 공백문자를 sep으로 할당
    feature_name_df = pd.read_csv('dataset/UCI HAR Dataset/features.txt', sep='\s+', header=None, names=['column_index', 'column_name'])
    # 데이터프레임에 피처명을 컬럼으로 뷰여하기 위해 리스트 객체로 다시 반환

    new_feature_name_df = get_new_feature_name_df(feature_name_df)
    feature_name = new_feature_name_df.iloc[:, 1].values.tolist()

    # 학습 피처 데이터세트와 테스트 피처 데이터를 데이터프레임으로 로딩
    # 컬럼명은 feature_name 적용
    X_train = pd.read_csv('dataset/UCI HAR Dataset/train/X_train.txt', sep='\s+', names=feature_name)
    X_test = pd.read_csv('dataset/UCI HAR Dataset/test/X_test.txt', sep='\s+', names=feature_name)

    # 학습 레이블과 테스트 레이블 데이터를 데이터 프레임으로 로딩, 컬럼명은 action으로 부여
    y_train = pd.read_csv('dataset/UCI HAR Dataset/train/y_train.txt', sep='\s+', names=['action'])
    y_test = pd.read_csv('dataset/UCI HAR Dataset/test/y_test.txt', sep='\s+', names=['action'])

    # 로드된 학습/테스트용 데이터프레임을 모두 반환
    return X_train, X_test, y_train, y_test

X_train, X_test, y_train, y_test = get_human_dataset()
gb_clf = GradientBoostingClassifier(random_state=0)
gb_clf.fit(X_train, y_train)
gb_pred = gb_clf.predict(X_test)
gb_accuracy = accuracy_score(y_test, gb_pred)

print('GBM accurracy : {0:.4f}'.format(gb_accuracy))

정확도를 보면 랜덤 포레스트보다 낳은 예측 성능을 나타냈니다. 그렇지 않은 경우도 있겠지만, 일반적으로 GBM이 랜덤 포레스트보다는 예측 성능이 조금 뛰어난 경우가 많습니다. 그러나 수행 시간이 오래 걸리고, 하이퍼 파라미터 튜닝 노력도 더 필요합니다. 

 

하지만 속도가 매우 느린데요. 사이킷런의 GBM 라이브러리는 약한 학습기의 순차적인 예측 오류 보정을 통해 학습을 수행하므로 멀티 CPU코어 시스템을 사용하더라도 병렬 처리가 지원되지 않아서 대용량 데이터의 경우 학습에 매우 많은 시간이 필요합니다. 반면에 랜덤 포레스트의 경우 상대적으로 빠른 수행 시간을 보장해주기 때문에 더 쉽게 예측 결과를 도출할 수 있습니다. 

 

GBM 하이퍼 파라미터 및 튜닝

  • loss: 경사 하강법에서 사용할 비용 함수를 지정합니다. 기본값은 'deviance'를 그대로 적용합니다.
  • learning_rate: GBM이 학습을 진행할 때마다 적용하는 학습률입니다. weak_learner가 순차적으로 오류 값을 보정해 나가는 데 적용하는 계수입니다.
  • n_estimators: weak learner의 개수입니다. weak learner가 순차적으로 오류를 보정하므로 개수가 많을수록 예측 성능이 일정 수준까지는 좋아질 수 있습니다. 하지만 개수가 많을수록수행 시간이 오래 걸립니다.
  • subsample: weak learner가 학습에 사용하는 데이터의 샘플링 비율립니다. 기본값은 1이며, 이는 전체 학습 데이터를 기반으로 학습한다는 의미입니다. 
from sklearn.model_selection import GridSearchCV
params = {
    'n_estimators':[100, 500],
    'learning_rate':[0.05,0.1]
}
grid_cv = GridSearchCV(gb_clf, param_grid=params, cv=2, verbose=1)
grid_cv.fit(X_train, y_train)
print('Best Parameter : ', grid_cv.best_params_)
print('Best Accuracy : ', grid_cv.best_score_)

gb_pred = grid_cv.best_estimator_.predict(X_test)
gb_accuracy = accuracy_score(y_test, gb_pred)
print('GBM Accuracy:', gb_accuracy)

 

GBM이후 이를 기반으로 한 알고리즘이 많이 생성이 되었는데요. 가장 각광을 받고 있는 것이 바로 그래디언트 부스팅 기반 ML패키지인 XGBoost, LightGBM입니다.

반응형