4 분 소요

🍖 정형 데이터와 비정형 데이터

  • 정형 데이터 : 어떤 구조로 되어 있는 형태, CSV, 데이터베이스, 엑셀
  • 비정형 데이터 : 데이터베이스나 엑셀로 표현하기 어려운 것, 텍스트 데이터, 사진, 음악 등

지금까지 배운 머신러닝 알고리즘은 정형 데이터에 잘 맞았다. 그중에 정형 데이터를 다루는 데 가장 뛰어난 성과를 내는 알고리즘이 앙상블 학습 이다. 앙상블 학습 하기 전에 일단 데이터부터 정리해 놓자!

import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split

# 1. 데이터 불러와
wine = pd.read_csv('https://bit.ly/wine_csv_data')

# 2. target과 데이터 분리
data = wine[['alcohol', 'sugar', 'pH']].to_numpy()
target = wine['class'].to_numpy()

# 트리는 전처리 필요 없으므로 pass
# 3. 훈련 세트와 테스트 세트 분리
train_input, test_input, train_target, test_target = train_test_split(data, target, test_size=0.2, random_state=42)


✨ 앙상블 학습

🔮 랜덤 포레스트

랜덤 포레스트는 결정 트리를 랜덤하게 만들어 결정 트리의 숲을 만든다. 각 결정 트리의 예측을 사용해 최종 예측을 만든다.

📍 학습 방법

  1. 각 트리를 훈련하기 위한 데이터를 랜덤으로 만든다. 훈련 데이터에서 랜덤하게 샘플 추출 -> 훈련 데이터를 만듬(중복 허용)
    • 1000개의 샘플 중 100개의 샘플을 뽑는다고 할 때, 여기서 한번에 100개의 샘플을 뽑는게 아니라 1000개 중에 한 개를 뽑고, 다시 넣고, 또 1000개 중에 한 개뽑고,, 이런 식으로 100번 진행 = 이렇게 만들어진 샘플을 부트스트랩 샘플 이라고 부른다.
  2. 이렇게 만들어진 부트스트랩 샘플을 가지고 각각의 결정 트리를 훈련 시킨다.
  3. 분류 과정일 때는 각 트리의 클래스별 확률을 평균하여 가장 높은 확률을 가진 클래스를 예측으로 삼는다. 회귀일 때는 각 트리의 예측을 평균한다.

📍 훈련 세트 점수, 검증 세트 점수 구하기

from sklearn.model_selection import cross_validate
from sklearn.ensemble import RandomForestClassifier
rf = RandomForestClassifier(n_jobs=-1, random_state=42)
scores = cross_validate(rf, train_input, train_target, return_train_score=True, n_jobs=-1)
print(np.mean(scores['train_score']), np.mean(scores['test_score']))

>>> 0.9973541965122431 # 훈련 세트 점수
    0.8905151032797809 # 검증 세트 점수
  • RandomForestClassifier : 랜덤 포레스트 클래스에 적용해보는 분류 문제, 기본적으로 100개의 결정 트리를 사용(default)
  • rf : 랜덤 포레스트 객체 생성
    • n_jobs=-1 : 모든 CPU 코어 사용할 것
  • cross_validate(estimator, X, Y=None, scoring=None, cv=None, n_jobs=None, vaerbose=0, ) : 교차 검증 수행 -> ❓ 교차 검증을 통해서 뽑은 훈련 세트와 검증 세트를 1개의 결정 트리에 훈련을 시킨다는 말인가? ㅇㅇㅇ 이거를 100번해서 각 트리의 클래스별 확률을 구해서 예측한다는 거? ㅇㅇㅇ💡
    • estimator : 평가하려는 모델
    • x : 훈련 데이터
    • y : 타깃
    • cv : 교차 검증 분할 수
    • n_jobs : CPU 코어 사용 개수
    • return_train_score : 훈련 점수 포함 여부(검증 점수뿐만 아니라 훈련 세트의 점수도 같이 반환)

📍 특성 중요도 & OOB 샘플

  • 특성 중요도

    rf.fit(train_input, train_target)
    print(rf.feature_importances_)
    >>> 0.8934000384837406
    

    앞 장에서 했던 결정 트리 한 개의 특성 중요도와 랜덤 포레스트 클래스를 통한 특성 중요도는 조금 차이가 있다. 랜덤 포레스트는 애초에 샘플을 뽑을 때, 부트스트랩 샘플을 뽑아서 하나의 특성에 과도하게 집중하지 않고 좀 더 많은 특성이 훈련할 기회를 준다. = 과대적합을 줄이고 일반화할 수 있다.

  • OOB 샘플

rf = RandomForestClassifier(oob_score=True, n_jobs=-1, random_state=42)
rf.fit(train_input, train_target)
print(rf.oob_score_)

OOB 샘플은 부트스트랩 샘플에 포함되지 않고 남는 샘플로 검증 세트의 역할을 한다.

🔮 엑스트라 트리

랜덤 포레스트와 비슷하지만 부트스트랩 샘플을 사용하지 않는다는 차이점이 있다. 즉, 각 결정 트리를 만들 떼, 전체 훈련 세트를 사용한다. 대신 무작위로 노드 결정!

📍 훈련 세트 점수, 검증 세트 점수 구하기

from sklearn.ensemble import ExtraTreesClassifier
et = ExtraTreesClassifier(n_jobs=-1, random_state=42)
scores = cross_validate(et, train_input, train_target, return_train_score=True, n_jobs=-1)
print(np.mean(scores['train_score']), np.mean(scores['test_score']))

>>>
0.9974503966084433 # 훈련 세트 점수
0.8887848893166506 # 검증 세트 점수

특성이 많지 않아 두 모델의 차이가 크지 않지만 보통 엑스트라 트리가 무작위성이 좀 더 크기 때문에 랜덤 포레스트보다 더 많은 결정 트리를 훈련해야 된다. 장 : 랜덤하게 노드를 분할 -> 계산 속도 빠름

📍 특성 중요도

et.fit(train_input, train_target)
print(et.feature_impotances+)

>>> [0.20183568 0.52242907 0.27573525]

엑스트라 트리의 회귀 버전 : ExtraTreesRegressor 클래스

🔮 그레이디언트 부스팅

깊이가 얕은 결정 트리를 사용하여 이전 트리의 오차를 보완하는 방식으로 앙상블 하는 방법이다. -> ❓ 앙상블한다는게 뭔데 ㅋㅋㅋㅋ 도대체,,뭔가 샘플들을 섞어서 결과를 예측하고 그 결과의 평균이든 확률이든 을 구하는 건가?

📍 학습 방법

GradientBoosingClassifier 는 기본적으로 깊이가 3인 결정 트리를 100개 사용한다. 4장에서 배웠던 경사 하강법을 사용하여 트리를 앙상블에 추가하는데 분류에서는 로지스틱 손실 함수를 사용하고, 회귀에서는 평균 제곱 오차 함수를 사용한다.

📍 훈련 세트 점수, 검증 세트 점수 구하기

from sklearn.ensemble import GradientBoostingClassifier
gb = GradientBoostingClassifier(random_state=42)
scores = cross_validate(gb, train_input, train_target, return_train_score=True, n_jobs=-1)
print(np.mean(scores['train_score']), np.mean(scores['test_score']))

>>>
0.8881086892152563 # 훈련 세트 점수
0.8720430147331015 # 검증 세트 점수

결정 트리의 개수는 기본적으로 100개이다. 이를 n_estimators를 통해서 500개로 늘려도 과대 적합을 잘 억제하고 있다.

gb = GradientBoostingClassifier(n_estimators=500, learning_rate=0.2, random_state=42)
scores = cross_validate(gb, train_input, train_target, return_train_score=True, n_jobs=-1)
print(np.mean(scores['train_score']), np.mean(scores['test_score']))

>>>
0.9464595437171814
0.8780082549788999

📍 특성 중요도

gb.fit(train_input, train_target)
print(gb.feature_importances_)

>>>
[0.15872278 0.68010884 0.16116839]

🔮 히스토그램 기반 그레이디언트 부스팅

그냥 그레이던트 부스팅의 경우 트리를 순서대로 추가하면서 훈련하는 것이기 때문에, 훈련 속도가 느리다. 여기서 속도와 성능을 더욱 개선한 거싱 히스토그램 기반 그레이디언트 부스팅 이다. 정형 데이터를 다루는 머신러닝 알고리즘 중 가장 인기가 높은 알고리즘이다.

정형 데이터를 다루는 머신 러닝 알고리즘 중에 가장 인기가 높은 알고리즘이다. 입력 특성을 256개의 구간으로 나누고 노드를 분할할 때 최적의 분할을 매우 빠르게 찾을 수 있다.

📍 훈련 세트 점수, 검증 세트 점수 구하기

from sklearn.experimental import enable_hist_gradient_boosting
from sklearn.ensemble import HistGradientBoostingClassifier
hgb = HistGradientBoostingClassifier(random_state=42)
scores = cross_validate(hgb, train_input, train_target, return_train_score=True)
print(np.mean(scores['train_score']), np.mean(scores['test_score']))

>>>
0.9321723946453317
0.8801241948619236

📍 특성 중요도

히스토그램 기반 그레이디언트 부스팅의 특성 중요도를 계산하기 위해 permutationimportance() 함수를 사용하겠다. (다른 트리들은 객체.feature_importances를 통해서 중요도 확인)

from sklearn.inspection import permutation_importance

hgb.fit(train_input, train_target)
result = permutation_importance(hgb, train_input, train_target, n_repeats=10, random_state=42, n_jobs=-1)
print(result.importances_mean)

>>> [0.08876275 0.23438522 0.08027708]
  • n_repeats : 랜덤하게 섞을 횟수 지정

  • result.importances : 특성 중요도
  • result.importances_mean : 특성 중요도 평균
  • result.importances_std : 특성 중요도의 표준 편차

히스토그램 기반 그레이디언트 부스팅의 회귀 버전 : HistGradientBoostingRegressor 클래스

📍 사이킷런 외의 히스토그램 기반 그레이디언트 부스팅 알고리즘을 구현한 라이브러리

  • XGBoost

    from xgboost import XGBClassifier
    xgb = XGBClassifier(tree_method='hist', random_state=42)
    scores = cross_validate(xgb, train_input, train_target, return_train_score=True)
    print(np.mean(scores['train_score']), np.mean(scores['test_score']))
    
    >>>
    0.8824322471423747
    0.8726214185237284
    

    사이킷런의 cross_validate() 함수와 함께 사용할 수 있다. tree_method를 ‘his’로 지정하면 XGBoost가 아닌 히스토그램 기반 그레이디언트 부스팅을 사용할 수 있다.

  • LightGBM

    from lightgbm import LGBMClassifier
    lgb = LGBMClassifier(random_state=42)
    scores = cross_validate(lgb, train_input, train_target, return_train_score=True, n_jobs=-1)
    print(np.mean(scores['train_score']), np.mean(scores['test_score']))
    
    >>>
    0.9338079582727165
    0.8789710890649293
    

댓글남기기