입문자를 위한 머신러닝 - GBM
Page content
공지
- 본 소스코는 교재
파이썬 머신러닝 완벽 가이드
코드를 제 수업을 드는 학생들이 보다 편하게 구글 코랩에서 사용할 수 있도록 만든 예제입니다. - 책 구매하세요!
Gradient Boosting Machine
- 이제 GBM에 대해 학습하도록 합니다.
- GBM에 대해 이해하기 위해서는 경사하강법에 대해 배워야 합니다.
- 경사하강법은 쉽게 말하면 가장 적은 오차를 찾아가는 방법론 중이 하나입니다.
- 자세한 내용은 유투 강의를 들어주시기를 바랍니다. (Gradient Descent, Step-by-Step)
- 위 이론을
sklearn
에서 구현한 것이며, 이 이론을 기반으로 다양한 알고리즘이 개발 되어 있습니다.
데이터 불러오기
- 데이터를 불러오도록 합니다.
!wget https://archive.ics.uci.edu/ml/machine-learning-databases/00240/UCI%20HAR%20Dataset.zip
!unzip 'UCI HAR Dataset.zip'
!mv UCI\ HAR\ Dataset human_activity # 폴더 이름을 변경하는 터미널 명령어 입니다.
--2020-11-27 05:48:03-- https://archive.ics.uci.edu/ml/machine-learning-databases/00240/UCI%20HAR%20Dataset.zip
Resolving archive.ics.uci.edu (archive.ics.uci.edu)... 128.195.10.252
Connecting to archive.ics.uci.edu (archive.ics.uci.edu)|128.195.10.252|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 60999314 (58M) [application/x-httpd-php]
Saving to: ‘UCI HAR Dataset.zip’
UCI HAR Dataset.zip 100%[===================>] 58.17M 31.3MB/s in 1.9s
2020-11-27 05:48:05 (31.3 MB/s) - ‘UCI HAR Dataset.zip’ saved [60999314/60999314]
Archive: UCI HAR Dataset.zip
creating: UCI HAR Dataset/
inflating: UCI HAR Dataset/.DS_Store
creating: __MACOSX/
creating: __MACOSX/UCI HAR Dataset/
inflating: __MACOSX/UCI HAR Dataset/._.DS_Store
inflating: UCI HAR Dataset/activity_labels.txt
inflating: __MACOSX/UCI HAR Dataset/._activity_labels.txt
inflating: UCI HAR Dataset/features.txt
inflating: __MACOSX/UCI HAR Dataset/._features.txt
inflating: UCI HAR Dataset/features_info.txt
inflating: __MACOSX/UCI HAR Dataset/._features_info.txt
inflating: UCI HAR Dataset/README.txt
inflating: __MACOSX/UCI HAR Dataset/._README.txt
creating: UCI HAR Dataset/test/
creating: UCI HAR Dataset/test/Inertial Signals/
inflating: UCI HAR Dataset/test/Inertial Signals/body_acc_x_test.txt
creating: __MACOSX/UCI HAR Dataset/test/
creating: __MACOSX/UCI HAR Dataset/test/Inertial Signals/
inflating: __MACOSX/UCI HAR Dataset/test/Inertial Signals/._body_acc_x_test.txt
inflating: UCI HAR Dataset/test/Inertial Signals/body_acc_y_test.txt
inflating: __MACOSX/UCI HAR Dataset/test/Inertial Signals/._body_acc_y_test.txt
inflating: UCI HAR Dataset/test/Inertial Signals/body_acc_z_test.txt
inflating: __MACOSX/UCI HAR Dataset/test/Inertial Signals/._body_acc_z_test.txt
inflating: UCI HAR Dataset/test/Inertial Signals/body_gyro_x_test.txt
inflating: __MACOSX/UCI HAR Dataset/test/Inertial Signals/._body_gyro_x_test.txt
inflating: UCI HAR Dataset/test/Inertial Signals/body_gyro_y_test.txt
inflating: __MACOSX/UCI HAR Dataset/test/Inertial Signals/._body_gyro_y_test.txt
inflating: UCI HAR Dataset/test/Inertial Signals/body_gyro_z_test.txt
inflating: __MACOSX/UCI HAR Dataset/test/Inertial Signals/._body_gyro_z_test.txt
inflating: UCI HAR Dataset/test/Inertial Signals/total_acc_x_test.txt
inflating: __MACOSX/UCI HAR Dataset/test/Inertial Signals/._total_acc_x_test.txt
inflating: UCI HAR Dataset/test/Inertial Signals/total_acc_y_test.txt
inflating: __MACOSX/UCI HAR Dataset/test/Inertial Signals/._total_acc_y_test.txt
inflating: UCI HAR Dataset/test/Inertial Signals/total_acc_z_test.txt
inflating: __MACOSX/UCI HAR Dataset/test/Inertial Signals/._total_acc_z_test.txt
inflating: __MACOSX/UCI HAR Dataset/test/._Inertial Signals
inflating: UCI HAR Dataset/test/subject_test.txt
inflating: __MACOSX/UCI HAR Dataset/test/._subject_test.txt
inflating: UCI HAR Dataset/test/X_test.txt
inflating: __MACOSX/UCI HAR Dataset/test/._X_test.txt
inflating: UCI HAR Dataset/test/y_test.txt
inflating: __MACOSX/UCI HAR Dataset/test/._y_test.txt
inflating: __MACOSX/UCI HAR Dataset/._test
creating: UCI HAR Dataset/train/
creating: UCI HAR Dataset/train/Inertial Signals/
inflating: UCI HAR Dataset/train/Inertial Signals/body_acc_x_train.txt
creating: __MACOSX/UCI HAR Dataset/train/
creating: __MACOSX/UCI HAR Dataset/train/Inertial Signals/
inflating: __MACOSX/UCI HAR Dataset/train/Inertial Signals/._body_acc_x_train.txt
inflating: UCI HAR Dataset/train/Inertial Signals/body_acc_y_train.txt
inflating: __MACOSX/UCI HAR Dataset/train/Inertial Signals/._body_acc_y_train.txt
inflating: UCI HAR Dataset/train/Inertial Signals/body_acc_z_train.txt
inflating: __MACOSX/UCI HAR Dataset/train/Inertial Signals/._body_acc_z_train.txt
inflating: UCI HAR Dataset/train/Inertial Signals/body_gyro_x_train.txt
inflating: __MACOSX/UCI HAR Dataset/train/Inertial Signals/._body_gyro_x_train.txt
inflating: UCI HAR Dataset/train/Inertial Signals/body_gyro_y_train.txt
inflating: __MACOSX/UCI HAR Dataset/train/Inertial Signals/._body_gyro_y_train.txt
inflating: UCI HAR Dataset/train/Inertial Signals/body_gyro_z_train.txt
inflating: __MACOSX/UCI HAR Dataset/train/Inertial Signals/._body_gyro_z_train.txt
inflating: UCI HAR Dataset/train/Inertial Signals/total_acc_x_train.txt
inflating: __MACOSX/UCI HAR Dataset/train/Inertial Signals/._total_acc_x_train.txt
inflating: UCI HAR Dataset/train/Inertial Signals/total_acc_y_train.txt
inflating: __MACOSX/UCI HAR Dataset/train/Inertial Signals/._total_acc_y_train.txt
inflating: UCI HAR Dataset/train/Inertial Signals/total_acc_z_train.txt
inflating: __MACOSX/UCI HAR Dataset/train/Inertial Signals/._total_acc_z_train.txt
inflating: __MACOSX/UCI HAR Dataset/train/._Inertial Signals
inflating: UCI HAR Dataset/train/subject_train.txt
inflating: __MACOSX/UCI HAR Dataset/train/._subject_train.txt
inflating: UCI HAR Dataset/train/X_train.txt
inflating: __MACOSX/UCI HAR Dataset/train/._X_train.txt
inflating: UCI HAR Dataset/train/y_train.txt
inflating: __MACOSX/UCI HAR Dataset/train/._y_train.txt
inflating: __MACOSX/UCI HAR Dataset/._train
inflating: __MACOSX/._UCI HAR Dataset
import pandas as pd
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('./human_activity/features.txt',sep='\s+',
header=None,names=['column_index','column_name'])
# 중복된 피처명을 수정하는 get_new_feature_name_df()를 이용, 신규 피처명 DataFrame생성.
new_feature_name_df = get_new_feature_name_df(feature_name_df)
# DataFrame에 피처명을 컬럼으로 부여하기 위해 리스트 객체로 다시 변환
feature_name = new_feature_name_df.iloc[:, 1].values.tolist()
# 학습 피처 데이터 셋과 테스트 피처 데이터을 DataFrame으로 로딩. 컬럼명은 feature_name 적용
X_train = pd.read_csv('./human_activity/train/X_train.txt',sep='\s+', names=feature_name )
X_test = pd.read_csv('./human_activity/test/X_test.txt',sep='\s+', names=feature_name)
# 학습 레이블과 테스트 레이블 데이터을 DataFrame으로 로딩하고 컬럼명은 action으로 부여
y_train = pd.read_csv('./human_activity/train/y_train.txt',sep='\s+',header=None,names=['action'])
y_test = pd.read_csv('./human_activity/test/y_test.txt',sep='\s+',header=None,names=['action'])
# 로드된 학습/테스트용 DataFrame을 모두 반환
return X_train, X_test, y_train, y_test
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.metrics import accuracy_score
import pandas as pd
import time
import warnings
warnings.filterwarnings('ignore')
# 결정 트리에서 사용한 get_human_dataset( )을 이용해 학습/테스트용 DataFrame 반환
X_train, X_test, y_train, y_test = get_human_dataset()
print("## 학습 피처 데이터 정보 ##")
print(X_train.info())
## 학습 피처 데이터 정보 ##
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 7352 entries, 0 to 7351
Columns: 561 entries, tBodyAcc-mean()-X to angle(Z,gravityMean)
dtypes: float64(561)
memory usage: 31.5 MB
None
(옵션 체크) 구글 코랩 개발환경 확인
- 간단하게 구글 코랩 개발환경을 확인한다.
!cat /proc/cpuinfo
processor : 0
vendor_id : GenuineIntel
cpu family : 6
model : 79
model name : Intel(R) Xeon(R) CPU @ 2.20GHz
stepping : 0
microcode : 0x1
cpu MHz : 2200.000
cache size : 56320 KB
physical id : 0
siblings : 2
core id : 0
cpu cores : 1
apicid : 0
initial apicid : 0
fpu : yes
fpu_exception : yes
cpuid level : 13
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc rep_good nopl xtopology nonstop_tsc cpuid tsc_known_freq pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch invpcid_single ssbd ibrs ibpb stibp fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm rdseed adx smap xsaveopt arat md_clear arch_capabilities
bugs : cpu_meltdown spectre_v1 spectre_v2 spec_store_bypass l1tf mds swapgs taa
bogomips : 4400.00
clflush size : 64
cache_alignment : 64
address sizes : 46 bits physical, 48 bits virtual
power management:
processor : 1
vendor_id : GenuineIntel
cpu family : 6
model : 79
model name : Intel(R) Xeon(R) CPU @ 2.20GHz
stepping : 0
microcode : 0x1
cpu MHz : 2200.000
cache size : 56320 KB
physical id : 0
siblings : 2
core id : 0
cpu cores : 1
apicid : 1
initial apicid : 1
fpu : yes
fpu_exception : yes
cpuid level : 13
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc rep_good nopl xtopology nonstop_tsc cpuid tsc_known_freq pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch invpcid_single ssbd ibrs ibpb stibp fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm rdseed adx smap xsaveopt arat md_clear arch_capabilities
bugs : cpu_meltdown spectre_v1 spectre_v2 spec_store_bypass l1tf mds swapgs taa
bogomips : 4400.00
clflush size : 64
cache_alignment : 64
address sizes : 46 bits physical, 48 bits virtual
power management:
GBM 모형 학습
- GBM 수행 시간 측정을 위해 시작 시간을 설정합니다.
# GBM 수행 시간 측정을 위함. 시작 시간 설정.
start_time = time.time()
gb_clf = GradientBoostingClassifier(n_estimators=10, # 기본값은 100이지만, 수업 시간을 고려하여 10으로 지정하였음
validation_fraction=0.2,
n_iter_no_change=5, tol=0.01, verbose = 1,
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 정확도: {0:.4f}'.format(gb_accuracy))
print("GBM 수행 시간: {0:.1f} 초 ".format(time.time() - start_time))
Iter Train Loss Remaining Time
1 8274.1239 48.73s
2 6858.4625 46.31s
3 5818.7911 41.54s
4 4981.6935 35.95s
5 4331.9874 30.14s
6 3790.2625 24.27s
7 3336.1237 18.25s
8 2960.1395 12.17s
9 2626.5821 6.10s
10 2341.0659 0.00s
GBM 정확도: 0.8907
GBM 수행 시간: 61.1 초
하이퍼 파라미터 및 튜닝
- 튜닝이란, 모형이 가지고 있는 여러 조건들을 변형 시키는 것
- 대표적인 파라미터 소개
- n_estimators:
weak learner
의 개수 지정, 디폴트는 100개이며, 많이 설정할수록 좋은 성능 기대 가능, 그러나 시간도 오래 소요됨 - max_features: 최적의 분할을 위해 고려할 피처의 개수
int
형으로 지정 시, 대상 피처의 개수,float
형으로 지정 시, 대상 피처의 퍼센트- 만약 전체 피처가 16개라면 분할 위해 4개 참조
- max_depth: 트리의 최대 깊이 규정
- min_samples_split: 자식 규칙 노드를 분할해 만들기 위한 최소한의 샘플 데이터 개수
- min_samples_leaf: 말단 노드(Leaf)가 되기 위한 최소한의 샘플 데이터 수
- loss: 경사 하강법에서 사용할 비용 함수 지정
- learning_rate: GBM이 학습 진행 시 마다의 학습률.
Weak Learner
가 순차적으로 - subsample:
weak learner
가 학습에 사용하는 데이터의 샘플링 비율, 기본값은 1이며, 이는 전체학습 데이터를 기반으로 학습한다는 의미.
- n_estimators:
그리드 서치
- GridSearchCV API를 활용하여 모형에 사용되는 하이퍼 파라미터를 순차적으로 입력하며서 편리하게 최적의 파라미터를 도출할 수 있는 방안 제공
- 즉, 랜덤포레스트의 파라미터를 순차적으로 변경 및 조정하면서 모형을 학습시키는 방법
- 이를 통해, 머신러닝 모형 개발자의 코드량을 줄여주는 매우 편리한 기법
- estimator: 머신러닝 모형의 객체가 온다.
- param_grid: 딕셔너리 형태로 조정하며,
estimator
의 튜닝을 위해 파라미터명과 사용될 여러 파라미터 값 지정, 이 부분은 각 머신러닝 모형의Manual
을 참조한다. - scoring: 예측 성능을 측정할 평가 방법 지정하지만, 대개 별도의 성능 평가 지표 함수 활용
- cv: 교차 검증을 위해 분할되는 학습/테스트 세트의 개수 지정
- 이 때에는 시간이 다소 소요될 수 있다. (5-10분)
from sklearn.model_selection import GridSearchCV
start_time = time.time()
params = {
'n_estimators':[10, 20], # 원 코드 100, 500
'learning_rate' : [ 0.05, 0.1]
}
grid_cv = GridSearchCV(gb_clf , param_grid=params , cv=2 ,verbose=1, n_jobs = -1)
grid_cv.fit(X_train , y_train)
print('최적 하이퍼 파라미터:\n', grid_cv.best_params_)
print('최고 예측 정확도: {0:.4f}'.format(grid_cv.best_score_))
print("GBM 수행 시간: {0:.1f} 초 ".format(time.time() - start_time))
Fitting 2 folds for each of 4 candidates, totalling 8 fits
[Parallel(n_jobs=-1)]: Using backend LokyBackend with 2 concurrent workers.
[Parallel(n_jobs=-1)]: Done 8 out of 8 | elapsed: 4.2min finished
Iter Train Loss Remaining Time
1 8274.1239 1.75m
2 6858.4625 1.78m
3 5818.7911 1.72m
4 4981.6935 1.63m
5 4331.9874 1.54m
6 3790.2625 1.44m
7 3336.1237 1.34m
8 2960.1395 1.24m
9 2626.5821 1.14m
10 2341.0659 1.04m
20 940.8021 0.00s
최적 하이퍼 파라미터:
{'learning_rate': 0.1, 'n_estimators': 20}
최고 예측 정확도: 0.8921
GBM 수행 시간: 380.2 초
드
# GridSearchCV를 이용하여 최적으로 학습된 estimator로 predict 수행.
gb_pred = grid_cv.best_estimator_.predict(X_test)
gb_accuracy = accuracy_score(y_test, gb_pred)
print('GBM 정확도: {0:.4f}'.format(gb_accuracy))
GBM 정확도: 0.9077
소결
- 학습 시간의 속도면에서 타 알고리즘보다 매우 느리기 때문에, 경진대회 및 현업에서 사용하는 것을 추천하지는 않습니다.
- 다만, 간단한 개념에 대한 이해 정도로 위 포스트를 학습하는 것을 추천하며, 향후에는
LightGBM
또는XGBoost
를 학습하는 것을 추천합니다.