4주차 후기
이전까지 훈련 세트와 테스트 세트로 데이터를 나누고, 테스트 세트의 결정 계수로 적합도를 판단하는 것이 무언가 찝찝했는데 이번 장에서 교차 검증을 배워서 그 찝찝함이 조금은 해소되었다.
인터넷에 교차 검증을 검색해보니 사이킷런 문서에 교차 검증에 대하여 영어로 상세히 설명되어 있는 것을 찾을 수 있었다. 그래서 사이킷런 User Guide를 살펴보았는데, 그동안 책에서 배웠던 내용들이 많이 설명되어 있었다. 여태 API 문서만 봤었는데 앞으로 공부하면서 이해가 잘 안되면 여기서도 내용을 더 읽어봐야 겠다.
앞선 장에서 하이퍼파라미터라는 개념을 공부하면서 우리의 예제에서는 어떤 값이 최적의 하이퍼파라미터인지 여러 값을 넣어 for문을 돌리고, 내 눈으로 직접 최적의 값을 찾았었다. 그때 들었던 생각이 "현업에서도 이렇게 찾는건가...??"라는 생각을 했었다. 그런데 그리드 서치를 보면서 "역시 뭔가 다른 방법이 있었군"이라는 생각이 들었다. 그리고 이거보다 더 나은 방법도 있지 않을까 생각했다.
마지막으로 앙상블은 지난주에 공부했던 경사 하강법처럼 이해하기 좀 어려웠다.
그래서 인터넷을 검색해보니 앙상블 기법이 voting, bagging, boostring으로 나눠지며 우리 책에서 공부한 것들이 bagging 방식 알고리즘이란 것을 알게 되었다.
한 챕터씩 넘어가며 어려운 개념이 계속해서 나와 인터넷을 찾아보고 있는데, 좀 더 정리된 방식으로 보고 싶어서 핸즈온 머신러닝 3판을 구매했다. 하지만 내가 기대한 느낌의 책은 아니였다. 그래도 올해는 머신러닝 관련 공부를 해보기로 마음 먹었으니, 혼공머신 스터디가 끝나면 이 책으로 좀 더 깊게 공부해봐야 겠다.
4주차 과제
기본 미션
교차 검증을 그림으로 설명하기
먼저 전체 데이터에서 20~30% 정도를 테스트 세트로 떼어놓는다.
테스트 세트는 맨 마지막에 딱 한 번 최종 점수를 평가하는데 사용한다.
전체 데이터에서 테스트 세트를 뺀 나머지 훈련 세트를 K개로 나눈다. (그림에서 Fold 1 ~ 5)
위 그림은 5-fold-cross-validation 예제이다.
처음에는 Fold 2 ~ 5를 훈련 세트로 사용하고, Fold 1을 검증 세트로 사용하여 모델을 평가한다.
그 다음 Fold 1과 Fold 3 ~ 5를 훈련 세트로 사용하고, Fold 2를 검증 세트로 사용하여 모델을 평가한다.
그 다음 Fold 1 ~ 2와 Fold 4 ~5를 훈련 세트로 사용하고, Fold 3을 검증 세트로 사용하여 모델을 평가한다.
이런 방식으로 Fold 4, Fold 5도 검증 세트로 사용하여 모델 평가를 반복한다.
각 Split에서 나온 검증 점수의 평균으로 _최종 검증 점수_를 얻는다.
선택 미션
Ch.05(05-3) 앙상블 모델 손코딩 코랩 화면 인증하기
본 문서 하단에 포함한 코드와 코랩 실행 결과 스크린샷으로 대체합니다.
결정 트리
예제 문제
- 알코올 도수, 당도, pH 값으로 레드 와인인지 화이트 와인인지 분류하기
###
# 알코올 도수, 당도, pH값으로 레드와인과 화이트와인 분류하기
###
# 와인 데이터 불러오기
import pandas as pd
wine = pd.read_csv('https://bit.ly/wine_csv_data')
# 불러온 데이터 확인하기
print(f"""
# 와인 데이터 첫 5개 (class 0: 레드 / 1: 화이트)
{wine.head()}
""")
print("# info() 메서드로 데이터프레임 각 열의 타입과 누락된 데이터 존재여부 확인")
print(f"{wine.info()}\n")
print("# describe() 메서드로 각 열에 대한 간략한 통계 출력")
print(wine.describe())
print("=> 알코올 도수, 당도, pH값의 스케일이 다르기 때문에 표준화가 필요하다.\n")
# numpy 배열로 변환
data = wine[['alcohol', 'sugar', 'pH']].to_numpy()
target = wine['class'].to_numpy()
# 훈련 세트, 테스트 세트
from sklearn.model_selection import train_test_split
train_input, test_input, train_target, test_target = train_test_split(data, target, test_size=0.2, random_state=42)
print(f"""# 훈련 세트와 테스트 세트의 크기 확인
훈련 세트 크기 : {train_input.shape}
테스트 세트 크기 : {test_input.shape}
""")
# 표준화 전처리
from sklearn.preprocessing import StandardScaler
ss = StandardScaler()
ss.fit(train_input)
train_scaled = ss.transform(train_input)
test_scaled = ss.transform(test_input)
# 분류를 위한 로지스틱 회귀 모델 훈련
from sklearn.linear_model import LogisticRegression
lr = LogisticRegression()
lr.fit(train_scaled, train_target)
print(f"""# 훈련 세트와 테스트 세트의 결정계수
훈련 세트 : {lr.score(train_scaled, train_target)}
테스트 세트 : {lr.score(test_scaled, test_target)}
=> 훈련세트와 테스트세트 점수가 모두 낮아 '과소적합' 된 것 같다.
""")
print(f"""# 로지스틱 회귀가 학습한 계수와 절편
계수 : {lr.coef_}
절편 : {lr.intercept_}
""")
결정 트리 (Decision Tree)
- 결정 트리 모델은 "스무고개"처럼 데이터를 구분할 수 있는 질문을 계속해서 추가하여 분류 정확도를 높일 수 있다.
- 다른 머신러닝 모델에 비해 비전문가에세 설명하기 쉬운 모델을 만든다.
- 결정 트리는 많은 앙상블 학습 알고리즘의 기반이 된다.
- 사이킷런의
DecisionTreeClassifier 클래스
를 사용할 수 있다. - 장점
- 결정 트리 알고리즘은 특성값의 스케일에 영향을 받지 않기 때문에 표준화 전처리를 할 필요가 없다.
- 특성 중요도를 활용하면 결정 트리 모델을 특성 선택에 활용할 수 있다.
###
# 결정 트리
###
# 결정 트리 모델 훈련
from sklearn.tree import DecisionTreeClassifier
dt = DecisionTreeClassifier(random_state=42)
dt.fit(train_scaled, train_target)
print(f"""# 결정 트리 모델로 훈련한 훈련 세트와 테스트 세트 결정계수
훈련 세트 : {dt.score(train_scaled, train_target)}
테스트 세트 : {dt.score(test_scaled, test_target)}
=> 훈련 세트에 비해 테스트 세트가 조금 낮은 "과대적합"된 모델이다.
""")
# plot_tree()로 결정 트리를 그림으로 그리기
import matplotlib.pyplot as plt
from sklearn.tree import plot_tree
plt.figure(figsize=(10,7))
plot_tree(dt)
print("# 결정 트리 출력")
plt.show()
print()
print("# 결정 트리의 깊이를 제한하여 일부만 확대 출력")
plot_tree(dt, max_depth=1, filled=True, feature_names=['alcohol', 'sugar', 'pH'])
plt.show()
print()
확대 출력된 결정 트리 동작 방식
- Root 노드 : 당도(sugar)가 -0.239 이하인가?
- -0.239 이하(YES) : 왼쪽 Leaf 노드로 이동
- -0.239 초과(NO) : 오른쪽 Leaf 노드로 이동
- samples=5197 : 루트 노드의 총 샘플 수는 5197개
- [1258, 3939]
- 음성 클래스(레드 와인) 1258개, 양성 클래스(화이트 와인) 3939개
- 만약 마지막 Leaf 노드라면 두 값 중에서 개수가 더 많은 클래스로 예측한다.
- gini : 불순도
불순도 (Gini Impurity)
- 결정 트리가 최적의 질문을 찾기 위한 기준
- DecisionTreeClassifier 클래스는 노드에서 데이터를 분할할 기준을 정하는
criterion 매개변수
의 기본값은gini
이다. - 지니 불순도 계산법
$$
지니,불순도 = 1;-;(음성,클래스,비율^2;+;양성,클래스,비율^2)
$$ criterion='entropy'
를 지정하여엔트로피 불순도
를 사용할 수 있다.- 엔트로피 불순도 계산법
$$
엔트로피,불순도;=;-음성,클래스,비율;\times;\log_2(음성,클래스,비율);-;양성,클래스,비율);\times;\log_2(양성,클래스,비율)
$$
정보 이득 (Information Gain)
- 부모 노드(Parent Node)와 자식 노드(Child Node)의 불순도 차이를
정보 이득
이라고 부른다. - 결정 트리 모델은 정보 이득이 최대가 되도록 데이터를 나눈다.
- 정보 이득 계산법
$$
정보,이득;=;부모의,불순도;-;(왼쪽,노드,샘플,수,/,부모의,샘플,수);\times;왼쪽,노드,불순도;-;(오른쪽,노드,샘플,수,/,부모의,샘플,수);\times;오른쪽,노드,불순도
$$
가지치기
- 결정 트리의 가지치기를 해야 무한정 자라나는 트리가 만들어지지 않는다.
- 가지치기를 통한 일반화를 하여 훈련 세트와 테스트 세트에 모두 맞는 모델을 만들수 있다.
- 결정 트리를 제한 없이 성장하면 훈련 세트에 과대적합되기 쉽다.
특성 중요도
- 결정 트리에 사용된 특성이 불순도를 감소하는데 기여한 정도
# max_depth=3 으로 훈련
dt = DecisionTreeClassifier(max_depth=3, random_state=42)
dt.fit(train_scaled, train_target)
print(f"""# max_depth=3 으로 훈련한 훈련 세트와 테스트 세트 결정계수
표준화 데이터 훈련 세트 : {dt.score(train_scaled, train_target)}
표준화 데이터 테스트 세트 : {dt.score(test_scaled, test_target)}
=> 훈련 세트 성능은 낮아지고, 테스트 세트의 성능은 그대로이다.
""")
plt.figure(figsize=(20,15))
plot_tree(dt, filled=True, feature_names=['alcohol', 'sugar', 'pH'])
plt.show()
# 표준화 전 데이터로 출력
dt = DecisionTreeClassifier(max_depth=3, random_state=42)
dt.fit(train_input, train_target)
print(f"""# 표준화 전 데이터를 사용한 훈련 세트와 테스트 세트 결정계수
표준화 전 데이터 훈련 세트 : {dt.score(train_input, train_target)}
표준화 전 데이터 테스트 세트 : {dt.score(test_input, test_target)}
=> 표준화 전/후의 결정계수가 동일하다.
""")
plt.figure(figsize=(20,15))
plot_tree(dt, filled=True, feature_names=['alcohol', 'sugar', 'pH'])
plt.show()
print("=> 특성값을 표준점수로 바꾸지 않았기 때문에 오히려 이해하기가 더 쉽다.")
# 가장 유용한 특성을 나타내는 특성 중요도 계산
for index in range(0,3):
print(f"특성 {index + 1} : {wine.columns[index]}, \t중요도 : {dt.feature_importances_[index]}")
# https://scikit-learn.org/stable/modules/generated/sklearn.tree.DecisionTreeClassifier.html#sklearn.tree.DecisionTreeClassifier.feature_importances_
dt = DecisionTreeClassifier(min_impurity_decrease=0.0005, random_state=42)
dt.fit(train_input, train_target)
print(dt.score(train_input, train_target))
print(dt.score(test_input, test_target))
plt.figure(figsize=(20,15), dpi=300)
plot_tree(dt, filled=True, feature_names=['alcohol', 'sugar', 'pH'])
plt.show()
교차 검증과 그리드 서치
그동안 수행한 모델 평가의 문제점
- 지금까지 "훈련 세트"에서 모델을 훈련하고, "테스트 세트"에서 모델을 평가했다.
- 계속 "테스트 세트"로 성능을 확인하면, 점점 테스트 세트에 맞추게 된다.
- "테스트 세트"는 가능한 모델을 만들고 나서 마지막에 딱 한 번만 사용하는 것이 좋다.
검증 세트 (Validation Set)
- 훈련 세트에서 일부 데이터를 떼어
검증 세트
로 사용한다.- AS-IS : 훈련 세트 80%, 테스트 세트 20%
- TO-BE : 훈련 세트 60%, 검증 세트 20%, 테스트 세트 20%
- 예를 들면 다음과 같이 사용할 수 있다.
- 모델 훈련 및 검증 방법
- 훈련 세트로 모델을 훈련
- 검증 세트로 모델을 평가
- 마지막에 테스트 세트로 최종 점수를 평가
# 데이터 불러오기
import pandas as pd
wine = pd.read_csv('https://bit.ly/wine_csv_data')
data = wine[['alcohol', 'sugar', 'pH']].to_numpy()
target = wine['class'].to_numpy()
# 훈련 세트, 테스트 세트 만들기
# - test_size 파라미터로 0.2를 전달 -> 테스트 세트로 20% 사용
from sklearn.model_selection import train_test_split
train_input, test_input, train_target, test_target = train_test_split(data, target, test_size=0.2, random_state=42)
# 훈련 세트(sub)에서 검증 세트(val) 분리하기
sub_input, val_input, sub_target, val_target = train_test_split(train_input, train_target, test_size=0.2, random_state=42)
# 훈련 세트와 검증 세트의 크기 확인
print(f"""# 훈련 세트와 검증 세트 크기 확인
전체 데이터 크기 : {data.shape}
검증 세트 분리 전 훈련 세트 크기 : {train_input.shape}
테스트 세트 크기 : {test_input.shape}
훈련 세트 크기 : {sub_input.shape}
검증 세트 크기 : {val_input.shape}
""")
# 결정 트리 모델 훈련
from sklearn.tree import DecisionTreeClassifier
dt = DecisionTreeClassifier(random_state=42)
dt.fit(sub_input, sub_target)
print(f"""# 훈련 세트와 검증 세트의 결정 계수
훈련 세트 : {dt.score(sub_input, sub_target)}
검증 세트 : {dt.score(val_input, val_target)}
=> 훈련 세트에 과대적합 되어 있다.
""")
교차 검증 (Cross Validation)
- 교차 검증은 검증 세트를 떼어 내어 평가하는 과정을 여러 번 반복한다. 그리고 나서 이 점수의 평균을 최종 검증 점수로 얻는다.
- k-폴드 교차 검증 (k-fold cross validation)
- "k-겹 교차 검증"이라고도 부른다.
- 훈련 세트를 k개로 나눠서 교차 검증을 수행한다.
- 예를 들어 훈련 세트를 세 부분으로 나눠서 교차 검증을 수행하면 "3-폴드 교차 검증"이라고 한다.
- 보통 5-폴드 교차 검증이나 10-폴드 교차 검증을 많이 사용한다.
- 사이킷런에
cross_validate()
라는 교차 검증 함수가 있다.
# 교차 검증
from sklearn.model_selection import cross_validate
from sklearn.model_selection import StratifiedKFold
import numpy as np
splitter = StratifiedKFold(n_splits=10, shuffle=True, random_state=42)
scores = cross_validate(dt, train_input, train_target, cv=splitter)
print(f"""
* cross_validate() 함수는 기본적으로 5-폴드 교차 검증을 수행한다.
따라서 각 키마다 5개의 숫자가 담겨 있다.
# 모델을 훈련하는 시간
fit_time : {scores['fit_time']}
# 모델을 검증하는 시간
score_time : {scores['score_time']}
# 교차 검증의 최종 점수
test_score : {scores['test_score']}
test_score 평균값 : {np.mean(scores['test_score'])}
""")
하이퍼파라미터 튜닝
- 모델 파라미터 : 머신러닝 모델이 학습하는 파라미터
- 하이퍼파라미터 : 머신러닝 모델이 학습할 수 없어서 사용자가 지정해야 하는 파라미터 (사용자 지정 파라미터)
- 튜닝 방법
- 먼저 라이브러리 기본값을 사용해 모델을 훈련한다.
- 검증 세트 점수 or 교차 검증을 통해 매개변수를 바꿔가며 훈련하여 최적값을 찾는다.
- 주의할 점
- 튜닝 할 매개변수를 동시에 바꿔가며 최적의 값을 찾아야 한다.
- 한 매개변수의 최적값을 찾았더라도 다음 매개변수의 값이 바뀌면 최적값이 달라지기 때문이다.
그리드 서치(Grid Search)
- 사이킷런에서는 최적의 하이퍼파라미터를 찾기 위해
그리드 서치
를 제공한다. GridSearchCV 클래스
는 하이퍼파라미터 탐색과 교차 검증을 한 번에 수행한다.- 기본적으로 교차 검증을 수행하기 때문에 cross_validate() 함수를 호출할 필요가 없다.
- cv 매개변수 기본값은 5이다. 따라서 기본적으로 5-폴드 교차 검증을 수행한다.
best_estimator_
속성을 통해 최적의 하이퍼파라미터를 사용하여 자동으로 모델을 다시 훈련한다.
from sklearn.model_selection import GridSearchCV
###
# 간단한 그리드 서치 실습
###
# 탐색할 매개변수와 값 목록
params = {'min_impurity_decrease': [0.0001, 0.0002, 0.0003, 0.0004, 0.0005]}
# 그리드 서치 객체 생성
# - n_jobs : 사용할 CPU 코어 개수. -1은 모든 코어 사용
gs = GridSearchCV(DecisionTreeClassifier(random_state=42), params, n_jobs=-1)
# 결정 트리 모델의 min_impurity_descrease 파라미터 값을 바꿔가며 총 5번 실행
gs.fit(train_input, train_target)
# 최적의 하이퍼파라미터로 모델 훈련
dt = gs.best_estimator_
print(f"""# 그리드 서치를 활용한 최적의 하이퍼파라미터 탐색
최적의 하이퍼파라미터 사용 시 결정계수 : {dt.score(train_input, train_target)}
최적의 매개변수 : {gs.best_params_}
각 매개변수 별 교차 검증 평균 점수 : {gs.cv_results_['mean_test_score']}
""")
###
# 복잡한 그리드 서치 실습
###
# 교차 검증 횟수 : 1350개(9 * 15 * 10) * 5(5-폴드 교차 검증) = 모델 수 총 6750개
params = {
'min_impurity_decrease': np.arange(0.0001, 0.001, 0.0001),
'max_depth': range(5, 20, 1),
'min_samples_split': range(2, 100, 10)
}
# 그리드 서치
gs = GridSearchCV(DecisionTreeClassifier(random_state=42), params, n_jobs=-1)
gs.fit(train_input, train_target)
# 결과
print(f"""
최상의 매개변수 조합 : {gs.best_params_}
최상의 교차 검증 점수 : {np.max(gs.cv_results_['mean_test_score'])}
""")
랜덤 서치(Random Search)
- 매개변수 값의 목록을 전달하지 않고, 매개변수를 샘플링 할 수 있는 확률 분포 객체를 전달한다.
RandomizedSearchCV 클래스
를 사용한다.- 언제 사용할까?
- 매개변수의 값이 수치여서 값의 범위, 간격을 정하기 어려울 때
- 매개변수 조건이 너무 많아서 그리드 서치 수행시간이 오래 걸릴 때
파이썬의 scipy 라이브러리
- 파이썬의 핵심 과학 라이브러리 중 하나
- 적분, 보간, 선형 대수, 확률 등을 포함한 수치 계산 전용 라이브러리
from scipy.stats import uniform, randint
###
# 난수 생성 테스트
###
# randint로 0~10 사이의 정수값 샘플링
rgen = randint(0, 10)
np.unique(rgen.rvs(10000), return_counts=True)
# uniform으로 0~1 사이의 실수값 샘플링
ugen = uniform(0, 1)
ugen.rvs(10)
###
# 랜덤 서치
###
from sklearn.model_selection import RandomizedSearchCV
params = {
'min_impurity_decrease': uniform(0.0001, 0.001),
'max_depth': randint(20, 50),
'min_samples_split': randint(2, 25),
'min_samples_leaf': randint(1, 25)
}
# params에 정의된 매개변수 범위에서 총 100번(n_iter) 샘플링하여 교차 검증을 수행하여 최적의 매개변수 조합 찾기
rs = RandomizedSearchCV(DecisionTreeClassifier(random_state=42, splitter='best'), params, n_iter=100, n_jobs=-1, random_state=42)
rs.fit(train_input, train_target)
print(f"""
최상의 매개변수 조합 : {rs.best_params_}
최상의 교차 검증 점수 : {np.max(rs.cv_results_['mean_test_score'])}
""")
# 최적 모델로 훈련하여 테스트 세트 성능 확인
dt = gs.best_estimator_
print(f"테스트 세트 성능 : {dt.score(test_input, test_target)}")
트리의 앙상블
정형 데이터와 비정형 데이터
- 정형 데이터(structured data)
- 어떤 구조로 되어 있는 데이터
- CSV, Excel, Database 등
앙상블 학습(ensemble learning) 알고리즘
을 사용할 수 있다.
- 비정형 데이터(unstructured data)
- Database나 Excel로 표현하기 어려운 데이터
- 책의 글과 같은 텍스트 데이터, 디지털카메라로 찍은 사진, 핸드폰으로 듣는 음악 등
신경망 알고리즘
을 사용할 수 있다.
앙상블(Ensemble)
- 여러가지 알고리즘들을 종합해서 결과를 내는 모델링 방식
- 대표적인 앙상블 기법
- Voting : 서로 다른 알고리즘을 사용해 예측한 결과를 다수결이나 평균으로 결정
- Bagging : 같은 알고리즘을 사용하되, 데이터를 무작위로 추출해 다양한 서브 데이터셋을 생성하고, 이를 병렬적으로 학습한 결과를 다슈결이나 평균으로 결정
- Boostring : 같은 알고리즘을 사용하면서 앞서 학습한 결과를 가지고 다음 학습기가 순차적으로 학습하면서 오차를 줄여나가는 방식
- 참고자료 : SUPERB AI - [3분 알고리즘] 랜덤 포레스트
랜덤 포레스트(Random Forest)
- 대표적인 앙상블 학습 방법
- Bagging 방식 알고리즘
- 동작 방식
- 부트스트랩(Bootstrap)을 통해 다양한 서브 데이터셋을 생성
- 여러 개의 의사결정나무가 각각의 데이터셋을 학습하고 결과를 취합
- 부트스트랩(Bootstrap) 방식
- 데이터 세트에서 중복을 허용하여 데이터를 샘플링하는 방식
- N개의 샘플 중에서 1개를 뽑은 후 다시 넣는다. 따라서 중복된 샘플을 뽑을 수도 있다.
- 부트스트랩 방식으로 만들어진 샘플을
부트스트랩 샘플(bootstrap sample)
이라고 부른다.
- 노드 분할 및 훈련
- 전체 특성 중에서 일부 특성을 무작위로 고른 다음, 이 중에서 최선의 분할을 찾고, 사이킷런의 랜덤 포레스트는 기본적으로 100개의 결정 트리를 훈련한다.
- 분류 모델(RandomForestClassifier)
- 전체 특성의 제곱근 만큼 특성 선택
- 각 트리의 클래스별 확률을 평균하여 가장 높은 확률을 가진 클래스를 예측으로 삼는다.
- 회귀 모델(RandomForestRegressor)
- 전체 특성 선택
- 각 트리의 예측을 평균한다.
- 장점
- 랜덤하게 선택한 샘플과 특성을 사용하기 때문에 훈련 세트에 과대적합 되는 것을 막을 수 있다.
- 검증 세트와 테스트 세트에서 안정적인 성능을 얻을 수 있다.
# 데이터를 불러와 훈련 세트와 테스트 세트로 나누기
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
wine = pd.read_csv('https://bit.ly/wine_csv_data')
data = wine[['alcohol', 'sugar', 'pH']].to_numpy()
target = wine['class'].to_numpy()
train_input, test_input, train_target, test_target = train_test_split(data, target, test_size=0.2, random_state=42)
# 랜덤 포레스트 분류 - 교차 검증
from sklearn.model_selection import cross_validate
from sklearn.ensemble import RandomForestClassifier
rf = RandomForestClassifier(oob_score=True, n_jobs=-1, random_state=42)
scores = cross_validate(rf, train_input, train_target, return_train_score=True, n_jobs=-1)
print(f"""# 랜덤 포레스트 분류 - 교차 검증 결과
훈련 세트 점수 : {np.mean(scores['train_score'])}
테스트 세트 점수 : {np.mean(scores['test_score'])}
""")
rf.fit(train_input, train_target)
print(f"""# 랜덤 포레스트 분류 - 특성 중요도
{rf.feature_importances_}
=> <결정 트리> 예제에서 생성된 특성 중요도랑 비교해보면
하나의 특성에 과도하게 집중하지 않고 고르게 특성들이 훈련에 기여한다.
""")
# 부트스트램 샘플에 포함되지 않은 OOB(Out Of Bag) 샘플로 결정 트리 평가
print(f"""# OOB 샘플로 교차 검증을 대신하여 결정 트리 평가
OOB 점수 : {rf.oob_score_}
=> 교차 검증에서 나온 점수와 비슷하다.
""")
엑스트라 트리(Extra Tree)
- 랜덤 포레스트와는 달리 부트스트램 샘플을 사용하지 않는다.
- 즉, 결정 트리를 만들 때 전체 훈련 세트를 사용한다.
- 무작위로 노드 분할을 한다.
- 앞선 예제에서
splitter='random'
지정해 사용했는데, 엑스트라 트리가 사용하는 결정 트리가 splitter='random' 인 결정 트리다. - 성능은 낮은 반면 많은 트리를 앙상블하기 때문에 과대적합을 막고, 검증 세트의 점수를 높이는 효과가 있다.
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(f"""# 엑스트라 트리 분류 - 교차 검증 결과
훈련 세트 점수 : {np.mean(scores['train_score'])}
테스트 세트 점수 : {np.mean(scores['test_score'])}
""")
et.fit(train_input, train_target)
print(f"""# 엑스트라 트리 분류 - 특성 중요도
{et.feature_importances_}
""")
그레이디언트 부스팅(Gradient Boosting)
- 깊이가 얕은 결정 트리를 사용하여 이전 트리의 오차를 보완하는 방식으로 앙상블 하는 방법
- 사이킷런의
GradientBoostingClassifier
은 기본적으로 깊이가 3인 결정 트리 100개를 사용한다.
- 사이킷런의
- 깊이가 옅은 결정 트리를 사용하기 때문에 과대적합에 강하고, 높은 일반화 성능을 가진다.
- 경사 하강법을 사용하여 트리를 앙상블에 추가한다.학습률 매개변수로 속도를 조절한다.
- 결정 트리를 계속해서 추가하면서 가장 낮은 곳으로 이동한다.
- 분류 : 로지스틱 손실 함수 사용 / 회귀 : 평균 제곱 오차 함수 사용
- 일반적으로 그레이디언트 부스팅이 랜덤 포레스트보다 더 높은 성능을 가지지만, 순서대로 트리를 추가하기 때문에 훈련 속도가 느리다.
# 그레이디언트 부스팅 - 교차 검증
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(f"""# 그레이디언트 부스팅 분류 - 교차 검증 결과 (결정 트리 개수 : 100 / 학습률 : 0.1)
훈련 세트 점수 : {np.mean(scores['train_score'])}
테스트 세트 점수 : {np.mean(scores['test_score'])}
""")
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(f"""# 그레이디언트 부스팅 분류 - 교차 검증 결과 (결정 트리 개수 : 500 / 학습률 : 0.2)
훈련 세트 점수 : {np.mean(scores['train_score'])}
테스트 세트 점수 : {np.mean(scores['test_score'])}
""")
gb.fit(train_input, train_target)
print(f"""# 그레이디언트 부스팅 분류 - 특성 중요도
{gb.feature_importances_}
""")
히스토그램 기반 그레이디언트 부스팅(Histogram-based Gradient Boosting)
- 정형 데이터를 다루는 머신러닝 알고리즘 중에 가장 인기가 높은 알고리즘
- 동작 방식
- 입력 특성을 256개 구간으로 나눈다.
- 노드를 분할할 때, 최적의 분할을 매우 빠르게 찾을 수 있다.
- 256개 구간 중에서 하나를 떼어 놓고 누락된 값을 위해서 사용한다.
- 따라서 입력에 누락된 특성이 있더라도 따로 전처리 할 필요가 없다.
- 입력 특성을 256개 구간으로 나눈다.
- 히스토그램 기반 그레이디언트 부스팅 알고리즘을 구현한 라이브러리
- 사이킷런
- XGBoost
- LightGBM
from sklearn.ensemble import HistGradientBoostingClassifier
hgb = HistGradientBoostingClassifier(random_state=42, max_iter=100, learning_rate=0.1)
scores = cross_validate(hgb, train_input, train_target, return_train_score=True)
print(f"""# 히스토그램 기반 그레이디언트 부스팅 분류 - 교차 검증 결과 (반복 횟수 : 100 / 학습률 : 0.1)
훈련 세트 점수 : {np.mean(scores['train_score'])}
테스트 세트 점수 : {np.mean(scores['test_score'])}
""")
from sklearn.inspection import permutation_importance
# 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(f"""# 히스토그램 기반 그레이디언트 부스팅 분류 - 훈련 세트 특성 중요도
특성 중요도 : {result.importances}
평균 : {result.importances_mean}
표준 편차 : {result.importances_std}
""")
# permutation_importance() - 테스트 세트
result = permutation_importance(hgb, test_input, test_target, n_repeats=10, random_state=42, n_jobs=-1)
print(f"""# 히스토그램 기반 그레이디언트 부스팅 분류 - 테스트 세트 특성 중요도
특성 중요도 : {result.importances}
평균 : {result.importances_mean}
표준 편차 : {result.importances_std}
""")
# 테스트 세트 성능
print(f"테스트 세트 성능 : {hgb.score(test_input, test_target)}")
# 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']))
# 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']))
'프로그래밍 > AI' 카테고리의 다른 글
[혼공머신 11기] 6주차 스터디 및 과제 (0) | 2024.02.18 |
---|---|
[혼공머신 11기] 5주차 스터디 및 과제 (1) | 2024.02.03 |
[혼공머신 11기] 3주차 스터디 및 과제 (0) | 2024.01.20 |
[혼공머신 11기] 2주차 스터디 및 과제 (1) | 2024.01.13 |
[혼공머신 11기] 1주차 스터디 및 과제 (1) | 2024.01.07 |