image

기본 숙제

교차 검증을 그림으로 설명하기

image

교차 검증의 장점

  • 모든 데이터 활용: 모든 데이터가 훈련과 테스트에 모두 사용됨
  • 신뢰성 향상: 여러 번 검증하여 더 안정적인 성능 평가
  • 과적합 방지: 특정 데이터 분할에 의존하지 않음

내용 정리

결정 트리

결정 트리(Decision Tree)는 데이터를 분류하거나 예측하는 머신러닝 알고리즘입니다.

캔에 와인 이름 표기가 안돼 있어서 캔에 인쇄된 알코올 도수, 당도, pH 값으로 와인 종류를 구별해야합니다.

결정 트리의 장점은 해석하기 쉽고 직관적이라는 점이고, 단점은 과적합되기 쉽고 데이터가 조금만 바뀌어도 트리 구조가 크게 달라질 수 있다는 점입니다.

로지스틱 회귀로 와인 분류하기

1
2
3
4
5
6
7
8
9
import pandas as pd

# 6,497개의 와인 샘플 데이터
wine = pd.read_csv('https://bit.ly/wine_csv_data')

# 기본 5개만 보기
wine.head(5)

# 타깃 클래스 0이면 레드와인, 1이면 화이트 와인
indexalcoholsugarpHclass
09.41.93.510.0
19.82.63.20.0
29.82.33.260.0
39.81.93.160.0
49.41.93.510.0

판다스에서 제공하는 info() 메서드는 데이터프레임의 각 열의 데이터 타입과 누락된 데이터가 있는지 확인하는데 유용합니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
wine.info()

# 결과 값값
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 6497 entries, 0 to 6496
Data columns (total 4 columns):
 #   Column   Non-Null Count  Dtype
---  ------   --------------  -----
 0   alcohol  6497 non-null   float64
 1   sugar    6497 non-null   float64
 2   pH       6497 non-null   float64
 3   class    6497 non-null   float64
dtypes: float64(4)
memory usage: 203.2 KB

describe() 메서드는 열에 대한 간략한 통계를 출력해 줍니다. 최소, 최대, 평균값등을 확인할 수 있습니다.

1
wine.describe()
indexalcoholsugarpHclass
count6497.06497.06497.06497.0
mean10.491805.44323533.21850.7538
std1.1927114.75780370.16070.4307
min8.00.62.720.0
25%9.51.83.111.0
50%10.33.03.211.0
75%11.38.13.321.0
max14.965.84.011.0

위와 같이 평균, 표준편차, 최소, 최대, 중간값, 1사분위수, 3사분위수를 알 수 있습니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 넘파이 배열로 바꾸기
data = wine[['alcohol', 'sugar', 'pH']].to_numpy()
target = wine['class'].to_numpy()

from sklearn.model_selection import train_test_split

# 훈련 세트와 테스트 세트 나누기(결과값 고정(42))
train_input, test_input, train_target, test_target = train_test_split(
    data, target, test_size=0.2, random_state=42)

print(train_input.shape, test_input.shape) # 훈련 세트 (5197, 3), 테스트 세트 (1300, 3)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
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(lr.score(train_scaled, train_target)) # 0.7808350971714451
print(lr.score(test_scaled, test_target)) # 0.7776923076923077

점수가 높지 않네요. 모델이 과소적합된 경향이 있습니다.
대부분의 머신러닝 모델은 이렇게 학습의 결과를 설명하기 어렵습니다.

이를 해결하기 위해서 결정 트리 모델을 쓰면 조금 더 설명하기 쉽다고 합니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
from sklearn.tree import DecisionTreeClassifier

# 사이킷런의 DecisionTreeClassifier 클래스를 사용
dt = DecisionTreeClassifier(random_state=42)
dt.fit(train_scaled, train_target)

# 훈련 세트
print(dt.score(train_scaled, train_target)) # 0.996921300750433
# 테스트 세트
print(dt.score(test_scaled, test_target)) # 0.8592307692307692

import matplotlib.pyplot as plt
from sklearn.tree import plot_tree

plt.figure(figsize=(10,7))
plot_tree(dt)
plt.show()

훈련 세트에 대한 점수가 0.996 정도로 매우 높게 나왔습니다. 테스트 세트의 성능은 그에 비해 낮게 나온 것을 확인할 수 있습니다.

이러한 유형을 과대적합된 모델이라고 합니다.

아래는 plot_tree() 함수를 이용하여 생성된 트리 이미지입니다. 가장 위는 루트 노트 가장 아래는 리프 노드라고 합니다. 흠..

image

결정 트리 알고리즘에서는 특성값의 스케일이 계산에 영향을 미치지 않습니다. 따라서 표준화 전처리를 할 필요가 없습니다.

1
2
3
plt.figure(figsize=(10,7))
plot_tree(dt, max_depth=1, filled=True, feature_names=['alcohol', 'sugar', 'pH'])
plt.show()

image

결정 트리를 보는 방법은 다음과 같습니다.

박스의 값을 순서대로 보면 아래와 같습니다.

테스트 조건(sugar)
불순도(gini)
총 샘플 수(samples)
클래스별 샘플 수(value)

위와 같이 조건에 맞으면 왼쪽 맞지 않으면 오른쪽으로 계속하여 트리가 내려갑니다.

지니 불순도(Gini Impurity)는 결정 트리에서 노드의 “불순한 정도"를 측정하는 지표입니다.

한 노드에 여러 클래스의 데이터가 섞여 있을수록 불순도가 높고, 한 클래스로만 구성되어 있으면 불순도가 낮습니다.

뭐 공식이 있긴 한데.. 그냥 결정 트리에서는 각 분할에서 지니 불순도를 최대한 낮추는 방향으로 데이터를 나누는 것이 좋다고 생각하면 됩니다.

또한 결정 트리는 표준화 전처리 과정이 필요 없기 때문에 아래처럼 바로 값을 확인하고 색상에 대한 구별로 클래스를 구분할 수 있습니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
dt = DecisionTreeClassifier(max_depth=3, random_state=42)
# 바로 값을 넣어도 됨(표준화 전처리 과정이 필요 없음)
dt.fit(train_input, train_target)

print(dt.score(train_input, train_target)) # 0.8454877814123533
print(dt.score(test_input, test_target)) # 0.8415384615384616

plt.figure(figsize=(20,15))
plot_tree(dt, filled=True, feature_names=['alcohol', 'sugar', 'pH'])
plt.show()

image

그림을 보면 당도가 1.625보다 크고 4.325보다 작은 와인 중에 알코올 도수가 11.025와 같거나 작은 것이 레드 와인이라고 판단했습니다.

1
2
3
print(dt.feature_importances_)
# alcohol | sugar | pH
# [0.12345626 0.86862934 0.0079144 ]

feature_importances_를 통해 특성 중요도를 보면 2번째 특성인 당도가 0.87로 특성 중요도가 가장 높습니다.
또한 값을 모두 더하면 1이 됩니다.

결정 트리는 깊이가 너무 깊지 않다면 비교적 설명하기 쉽습니다. 근데 실무에서는 더 복잡할 것 같네요..

교차 검증과 그리드 서치

테스트 세트로 일반화 성능을 올바르게 예측하려면 가능한 한 테스트 세트를 사용하지 말아야 합니다. 테스트 세트를 사용해 자꾸 성능을 확인하다 보면 점점 테스트 세트에 맞추게 되는 문제가 있습니다.

모델을 만들고 마지막에 1번만 하는게 좋다고 하네요.

검증 세트

테스트 세트를 사용하지 않으면 모델이 과대적합인지 과소적합인지 판단하기 어렵습니다. 테스트 세트를 사용하지 않고 이를 특정하는 간단한 방법은 훈련 세트를 또 나눠서 검증 세트를 만드는 것입니다.

훈련 세트: 약 60%, 검증 세트: 약 20%, 테스트 세트 약 20%..

보통 위와 같은 비율로 나누지만 훈련 데이터가 아주 많다면 테스트 세트와 검증 세트를 조금만 넣어도 문제가 없습니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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()

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)
# 훈련 세트, 검증 세트 만들기 테스트 사이즈 20%
sub_input, val_input, sub_target, val_target = train_test_split(
    train_input, train_target, test_size=0.2, random_state=42)

print(sub_input.shape, val_input.shape) # (4157, 3) (1040, 3)
# 훈련 세트 4157, 검증 세트 1040 나눠짐

from sklearn.tree import DecisionTreeClassifier

dt = DecisionTreeClassifier(random_state=42)
dt.fit(sub_input, sub_target)

print(dt.score(sub_input, sub_target)) # 0.9971133028626413
print(dt.score(val_input, val_target)) # 0.864423076923077

교차 검증

교차 검증은 검증 세트를 떼어 내어 평가하는 과정을 여러 번 반복합니다. 그 다음 이 점수를 평균하여 최종 검증 점수를 얻습니다.

보통 이러한 방법을 n-폴드 교차 검증이라고 하는데 보통 5-폴드 교차 검증이나 10-폴드 교차 검증을 많이 사용합니다.

이렇게 하면 데이터의 80~90%까지 훈련에 사용할 수 있다고 합니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
from sklearn.model_selection import cross_validate

# cv값으로 폴드 교차 검증 수를 변경할 수 있음
scores = cross_validate(dt, train_input, train_target, cv=5)
print(scores)
#{
#'fit_time': array([0.01962185, 0.0133481 , 0.01217628, 0.01221108, 0.0117507 ]),
#'score_time': array([0.00242043, 0.00203443, 0.00241065, 0.00196838, 0.00201941]),
#'test_score': array([0.86923077, 0.84615385, 0.87680462, 0.84889317, 0.83541867])
#}

import numpy as np

print(np.mean(scores['test_score'])) # 0.855300214703487

cross_validate() 함수는 기본적으로 5-폴드 교차 검증을 수행합니다. cv 매개변수에서 폴드 수를 바꿀 수도 있습니다.

검증 폴드의 점수는 test_score라고 합니다.

사이킷런의 분할기는 교차 검증에서 폴드를 어떻게 나눌지 결정해 줍니다. StratifiedKFold를 사용하여 앞서 수행한 교차 검증과 동일한 결과를 볼 수 있습니다.

1
2
3
4
5
6
7
8
9
from sklearn.model_selection import StratifiedKFold

scores = cross_validate(dt, train_input, train_target, cv=StratifiedKFold())
print(np.mean(scores['test_score'])) # 0.855300214703487

# n_splits 매개변수는 몇(k) 폴드 교차 검증을 할지 정함
splitter = StratifiedKFold(n_splits=10, shuffle=True, random_state=42)
scores = cross_validate(dt, train_input, train_target, cv=splitter)
print(np.mean(scores['test_score'])) # 0.8574181117533719

하이퍼파라미터 튜닝

모델이 학습할 수 없어서 사용자가 지정해야만 하는 파라미터를 하이퍼파라미터라고 합니다.

사이킷런의 GridSearchCV 클래슨느 하이퍼파라미터 탐색과 교차 검증을 한 번에 수행합니다.
또한, 훈련이 끝나면 모델 중에서 검증 점수가 가장 높은 모델의 매개변수 조합으로 전체 훈련 세트에서 자동으로 다시 모델을 훈련합니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
from sklearn.model_selection import GridSearchCV

params = {'min_impurity_decrease': [0.0001, 0.0002, 0.0003, 0.0004, 0.0005]}

gs = GridSearchCV(DecisionTreeClassifier(random_state=42), params, n_jobs=-1)

gs.fit(train_input, train_target)

dt = gs.best_estimator_
print(dt.score(train_input, train_target)) # 0.9615162593804117
# 그리드 서치로 찾은 최적의 매개변수 값
print(gs.best_params_) # {'min_impurity_decrease': 0.0001}

# 5번의 교차 검증으로 얻은 점수 출력
print(gs.cv_results_['mean_test_score']) # [0.86819297 0.86453617 0.86492226 0.86780891 0.86761605]

# 가장 큰 값의 인덱스 출
best_index = np.argmax(gs.cv_results_['mean_test_score'])
print(gs.cv_results_['params'][best_index]) # {'min_impurity_decrease': 0.0001}

위와 같이 최적의 매개변수를 가져오는 방법을 실습합니다.

조금 더 복잡한 매개변수 조합을 아래와 같습니다. 결정 트리에서 min_impurity_decrease는 노드를 분할하기 위한 불순도 감소 최소량을 지정합니다. max_depth로 트리의 깊이를 제한하고 min_samples_split로 노드를 나누기 위한 최소 샘플수 를 고릅니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
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(gs.best_params_) # {'max_depth': 14, 'min_impurity_decrease': np.float64(0.0004), 'min_samples_split': 12}

print(np.max(gs.cv_results_['mean_test_score'])) # 0.8683865773302731

넘파일 arange() 함수는 첫 번째 매개변수 값에서 시작하여 두 번째 매개변수에 도달할 떄까지 세 번째 매개변수를 계속 더한 배열을 만듭니다.

아래와 같이 매개변수를 만들어서 총 9 _ 15 _ 10 = 1350개에. 5-폴드 교차 검증을 수행하므로 6750개의 모델이 생성됩니다.

min_impurity_decrease: pythonnp.arange(0.0001, 0.001, 0.0001)

[0.0001, 0.0002, 0.0003, 0.0004, 0.0005, 0.0006, 0.0007, 0.0008, 0.0009]: 총 9개 값

max_depth: pythonrange(5, 20, 1)

[5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]: 총 15개 값

min_samples_split: pythonrange(2, 100, 10)

[2, 12, 22, 32, 42, 52, 62, 72, 82, 92]: 총 10개 값

이 값을 통해 최상의 매개변수 조합을 확인할 수 있으며, 최상의 교차 검증 점수도 확인할 수 있습니다.

랜덤 서치

매개변수의 값이 수치일 떄 값의 범위나 간격을 미리 정하기 어려울 수 있습니다. 이럴 때는 랜덤 서치를 사용하면 좋습니다.

확률 분포로 파라미터 정의하는 방식입니다. 싸이파이 라이브러리를 이용해서 예제를 실습합니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
from scipy.stats import uniform, randint

rgen = randint(0, 10) # 0~9 사이 정수를 균등하게 선택
rgen.rvs(10)

np.unique(rgen.rvs(1000), return_counts=True)

ugen = uniform(0, 1) # 0~1 사이 실수를 균등하게 선택
ugen.rvs(10)

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),
          }

from sklearn.model_selection import RandomizedSearchCV

gs = RandomizedSearchCV(DecisionTreeClassifier(random_state=42), params,
                        n_iter=100, n_jobs=-1, random_state=42)
gs.fit(train_input, train_target)

print(gs.best_params_) # {'max_depth': 39, 'min_impurity_decrease': np.float64(0.00034102546602601173), 'min_samples_leaf': 7, 'min_samples_split': 13}

print(np.max(gs.cv_results_['mean_test_score'])) # 0.8695428296438884

dt = gs.best_estimator_ # 최적 모델 가져오기

print(dt.score(test_input, test_target)) # 0.86

최종 검증 점수는 모든 폴드의 검증 점수를 평균하여 계산합니다.

트리의 앙상블

가장 좋은 알고리즘이 있다고 해서 다른 알고리즘을 배울 필요가 없는 것은 아닙니다.

보편적으로 성능이 좋아 널리 사용되는 알고리즘이 있지만 문제마다 다를 수 있습니다.

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

정형 데이터: CSV나 데이터베이스 혹은 엑셀로 저장하기 쉬운 데이터 비정형 데이터: 텍스트 데이터, 사진, 디지털 음악 등, NoSQL 같은 데이터

정형 데이터를 다루는데 가장 뛰어난 성과를 내는 알고리즘은 앙상블 학습입니다.

비정형 데이터는 신경망 알고리즘이 좋다고 합니다.

랜덤 포레스트

랜덤 포레스트(Random Forest)는 여러 개의 결정 트리를 합쳐서 더 강력한 모델을 만드는 앙상블 기법입니다. 핵심 아이디어는 나무 한 그루보다는 숲이 더 안정적이듯이, 결정 트리 하나보다는 여러 개를 합치면 더 좋은 성능을 낼 수 있습니다.

  • 부트스트랩 샘플링: 원본 데이터에서 중복을 허용해서 여러 개의 서로 다른 훈련 세트를 만듦
  • 특성 랜덤 선택: 각 노드에서 전체 특성 중 일부만 랜덤하게 선택해서 분할 기준을 정함
  • 여러 트리 훈련: 각각 다른 데이터와 다른 특성으로 여러 개의 결정 트리를 훈련
  • 투표로 결정: 예측할 때 모든 트리의 결과를 종합 (분류: 다수결, 회귀: 평균)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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

# -1로 하면 모든 CPU  코어를 사용함
rf = RandomForestClassifier(n_jobs=-1, random_state=42)
# return_train_score true로 지정하면 검증 점수뿐만 아니라 훈련 세트에 대한 점수도 같이 반환
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

rf.fit(train_input, train_target)
# 결정 트리의 특성 중요도 출력(합은 1)
# [알코올 도수, 당도, ph]
print(rf.feature_importances_) # [0.23167441 0.50039841 0.26792718]

# oob_score true로 지정하여 OOB(Out Of Bag) 점수를 출력
rf = RandomForestClassifier(oob_score=True, n_jobs=-1, random_state=42)

rf.fit(train_input, train_target)
print(rf.oob_score_) # 0.8934000384837406

RandomForestClassifier는 기본적으로 100개의 결정 트리를 사용합니다.

랜덤 포레스트의 경우는 특성 중요도가 5장 1절에서 만든 결정 트리의 특성 중요도가 다르게 나왔습니다.

다르게 나온 이유는 랜덤 포레스트가 특성의 일부를 랜덤하게 선택하여 결정 트리를 훈련하기 때문입니다. 그 결과 하나의 특성에 과도하게 집중하지 않고 좀 더 많은 특성이 훈련에 기여할 기회를 얻습니다.

엑스트라 트리

엑스트라 트리는 랜덤 포레스트와 매우 비슷하게 동작합니다.

랜덤 포레스트와 엑스트라 트리의 차이점은 부트스트랩 샘플을 사용하지 않는다는 점입니다. 즉각 결정 트리를 만들 때 전체 훈련 세트를 사용합니다.

엑스트라 트리가 무작위성이 좀 더 크기 때문에 랜덤 포레스트보다 더 많은 결정 트리를 훈련해야 합니다. 하지만 랜덤하게 노드를 분할하기 때문에 빠른 계산 속도가 엑스트라 트리의 장점입니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
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)
# [알코올 도수, 당도, ph]
# [0.20183568 0.52242907 0.27573525]
print(et.feature_importances_)

그레이디언트 부스팅

그레이디언트 부스팅 (Gradient Boosting)은 약한 모델들을 순차적으로 학습시켜서 이전 모델의 오차를 보정하는 방식

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
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

# 결정 트리 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)
# [알코올 도수, 당도, ph]
# [0.15887763 0.6799705  0.16115187]
print(gb.feature_importances_)

랜덤 포레스트와 달리 순차적 학습(병렬화 어려움) 합니다. 그레이디언트 부스팅이 랜덤 포레스트보다 조금 더 높은 성능을 얻읈 수 있습니다. 하지만 순서대로 트리를 추가하기 때문에 훈련 속도가 느립니다.

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

정형 데이터를 다루는 머신러닝 알고리즘 중에 가장 인기가 높은 알고리즘입니다.

입력 특성을 256개의 구간으로 나눠서 진행하기 때문에 노드를 분할할 때 최적의 분할을 매우 빠르게 찾을 수 있습니다.

기존 그레이디언트 부스팅 대비 10-20배 빠르면서도 비슷하거나 더 좋은 성능을 보여줘서 현재 가장 인기 있는 방법 중 하나입니다.

permutation_importance() 함수가 반환하는 객체는 반복하여 얻은 특성 중요도, 평균, 표준 편차를 담고 있습니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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, n_jobs=-1)

print(np.mean(scores['train_score']), np.mean(scores['test_score']))

# permutation_importance는 특성을 하나씩 랜덤하게 섞어서 모델의 성능이 변화하는지를 관찰하여 어떤 특성이 중요한지를 계산함
from sklearn.inspection import permutation_importance

hgb.fit(train_input, train_target)
# n_repeats 매개변수는 랜덤하게 섞을 횟수를 지정 기본값은 5
result = permutation_importance(hgb, train_input, train_target, n_repeats=10, random_state=42, n_jobs=-1)
# [알코올 도수, 당도, ph]
# [0.08876275 0.23438522 0.08027708]
print(result.importances_mean)
#print(result.importances)
#print(result.importances_std)

result = permutation_importance(hgb, test_input, test_target, n_repeats=10, random_state=42, n_jobs=-1)
# [알코올 도수, 당도, ph]
# [0.05969231 0.20238462 0.049     ]
print(result.importances_mean)

hgb.score(test_input, test_target) # 0.8723076923076923 (87% 정확도)

이외에도 XGBoost 라이브러리를 이용하여 와인 데이터의 교차 검증 점수를 확인할 수 있습니다.

1
2
3
4
5
6
7
8
from xgboost import XGBClassifier

# hist 히스토그램 기반 그레이디언트 부스팅 사용
xgb = XGBClassifier(tree_method='hist', random_state=42)
scores = cross_validate(xgb, train_input, train_target, return_train_score=True, n_jobs=-1)

# 0.9567059184812372 0.8783915747390243
print(np.mean(scores['train_score']), np.mean(scores['test_score']))

마이크로소프트에서 만든 LightGBM으로도 확인할 수 있습니다..!

1
2
3
4
5
6
7
from lightgbm import LGBMClassifier

lgb = LGBMClassifier(random_state=42)
scores = cross_validate(lgb, train_input, train_target, return_train_score=True, n_jobs=-1)

# 0.935828414851749 0.8801251203079884
print(np.mean(scores['train_score']), np.mean(scores['test_score']))

여러 앙상블 학습을 배웠으며, 히스토그램 기반 그레이디언트 부스팅 알고리즘이 제일.. 좋아 보이네요.