Post

[혼자 공부하는 ML + DL] 5. 트리 알고리즘

아래 내용은 “혼자 공부하는 머신러닝+딥러닝” 책을 공부하며 정리한 내용입니다.

Chapter 05. 트리 알고리즘

1. 결정트리

알코올 도수, 당도, PH값으로 와인 종류(레드, 화이트)를 구분해야 한다.

어떤 방법이 있을까? 같이 한 번 확인해보자.

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

먼저 품질관리팀에서 보내온 6,497개의 와인 샘플 데이터로 기존에 사용하던 로지스틱 회귀 모델을 사용하여 분류해보자.

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

wine = pd.read_csv('https://bit.ly/wine_csv_data')

# 처음 5개 샘플 확인
display(wine.head())

# 각 열의 데이터 타입과 누락값 확인
print(wine.info())

# 각 열의 간략한 통계
print(wine.describe())

와인 데이터 요약와인 데이터 요약

처음 3개의 열(alcohol, sugar, PH)는 각각 알코올 도수, 당도, PH값을 나타낸다. 네 번째 열인 class는 타깃값으로 0이면 레드와인, 1이면 화이트와인이다.

레드/화이트 와인을 구분하는 이진 분류이며 화이트와인(1)을 골라내는 문제라고 할 수 있다.

info() 메서드를 통해 각 열의 데이터 타입과 결측값을 확인할 수 있는데 총 6,497개 샘플이 있고 모든 열은 실수값이며 결측값이 없는 것을 알 수 있다.

와인 데이터 통계량와인 데이터 통계량

각 열에 대한 간략한 통계를 출력해주는 describe() 메서드를 살펴보면 최소(min), 최대(max), 평균(mean), 표준편차(std), 1사분위수(25%), 중간값(50%), 3사분위수(75%) 값을 알려주고 있다.

기본적인 로지스틱 모델을 학습해보자.

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
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(train_input.shape, test_input.shape)
 (5197, 3) (1300, 3)

# 표준화
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

학습/테스트셋 분할시 train_test_split() 함수에 설정값을 지정하지 않으면 default값으로 25%로 지정한다. 샘플 개수가 충분히 많기 때문에 20%를 테스트셋으로 나누었다.

학습셋 정확도 0.78, 테스트셋 정확도 0.77로 점수가 그리 높진 않다.

해당 모델을 설명하기 위해 로지스틱 회귀 모델이 학습 계수와 절편을 출력해서 보고서를 작성하였는데 이는 이해하기가 조금 어렵다.

순서도처럼 쉽게 설명 할 수 있는 방법이 있을까?

결정트리

설명하기 쉬운 모델로 결정트리(Decision Tree) 모델이 있다.

사이킷런 tree 라이브러리에서 DecisionTreeClassifier 클래스를 사용하여 모델을 학습하고 평가해보자.

1
2
3
4
5
6
7
8
9
10
11
# 결정트리
from sklearn.tree import 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

로지스틱 회귀보다 훈련셋과 테스트셋의 평가 점수가 높아졌다.

모델을 plot_tree() 함수를 이용하여 그림으로 표현해보자.

1
2
3
4
5
6
7
# 결정트리 시각화
import matplotlib.pyplot as plt
from sklearn.tree import plot_tree

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

와인데이터 결정트리 그림와인데이터 결정트리 그림

나무(tree) 모양과는 반대로 위에서부터 아래로 거꾸로 자라는 모습의 트리 그림이다. 맨 위의 노드(node)를 루트 노드(root node)라고 부르고 맨 아래 끝에 달린 노드를 리프 노드(leaf node)라고 한다.

현재 그림이 너무 복잡하니 트리의 깊이를 제한해서 출력해보자. max_depth 매개변수를 1로 주면 루트 노드를 제외하고 하나의 노드를 확장해서 그린다. 또 filled 매개변수에서 클래스에 맞게 노드의 색을 칠할 수 있고, feature_names 매개변수에는 특성의 이름을 전달할 수 있다.

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

와인데이터 결정트리, 깊이 1와인데이터 결정트리 그림, 깊이 1

첫 번째 루트노드는 당도(sugar)가 -0.239 이하인지 질문한다. 어떤 샘플의 당도가 -0.239와 같거나 작으면 왼쪽 가지로 가고 그렇지 않으면 오른쪽 가지로 이동한다. 즉 왼쪽이 Yes, 오른쪽이 No이다. 루트 노드의 총 샘플 수는 5,197개로 음성클래스(레드와인) 1,258개, 양성클래스(화이트와인)은 3,939개이다.

두번째 줄에서 왼쪽 노드를 해석해보자.

당도가 -0.802와 같거나 낮다면 다시 왼쪽으로 그렇지 않으면 오른쪽 가지로 이동한다. 이 노드에서 음성 클래스와 양성클래스의 샘플 개수는 각각 1,177개와 1,745개다. 루트 노드보다 양성 클래스(화이트와인)의 비율이 크게 줄었다. 이유는 오른쪽 노드를 보면 알 수 있다.

오른쪽 노드는 음성 클래스 81개, 양성클래스 2,194개로 대부분의 화이트와인 샘플이 이 노드로 이동했다. 노드의 바탕 색깔을 유심히 보면 루트노드보다 오른쪽 노드 색이 진하고 왼쪽 노드는 더 연해졌다. plot_tree() 함수에서 filled=True로 지정하면 클래스마다 색깔을 부여하고, 어떤 클래스의 비율이 높아지면 점점 진한 색으로 표시한다.

불순도(Impurity)

criterion 매개변수는 노드에서 데이터를 분할할 기준을 정하는 것이다.

결정트리 클래스의 criterion 매개변수의 기본값은 ‘gini’이다.

0.5가 되면 최악, 0이 되면 최적.

불순도가 0인 노드를 순수 노드 라고 한다.

Gini Impurity = 1 - (음성클래스 비율2 + 양성클래스 비율2) ex> 루트노드의 불순도 = 1 - ((1258 / 5197)2 + (3939 / 5197)2) = 0.367

결정트리 모델 알고리즘은 부모노드와 자식노드의 불순도 차이(정보이득)가 가능한 크도록 트리를 만든다.

즉, 정보이득이 최대가 되도록 노드를 분할한다.

부모와 자식노드의 불순도 차이(정보이득) = 부모의 불순도 - (왼쪽 노드 총 샘플 수 / 부모의 총 샘플 수) × 왼쪽 노드 불순도 - (오른쪽 노드 총 샘플수 / 부모의 총 샘플 수) × 오른쪽 노드 불순도

결정트리 알고리즘은 특성의 값들의 영향을 받지 않는다. 따라서 표준화 전처리 할 필요가 없다.

가지치기

과수원에서 열매를 잘 맺기 위해 가지치기를 하는 것처럼 결정 트리도 가지치기를 해야한다. 그렇지 않으면 끝까지 자라나는 트리가 만들어지는데 훈련셋에는 잘 맞지만 테스트셋에서는 잘 맞지 않을 것이다. 이를 두고 일반화가 잘 안될 것 같다고 말한다.

결정 트리에서 가지치기를 하는 가장 간단한 방법은 자라날 수 있는 트리의 최대 깊이를 지정하는 것이다.

DecisionTreeClassifier 클래스의 max_depth 매개변수를 3으로 지정하여 모델을 만들어보자

1
2
3
4
5
6
7
8
dt = DecisionTreeClassifier(max_depth = 3, random_state = 42)
dt.fit(train_scaled, train_target)

print(dt.score(train_scaled, train_target))
 0.8454877814123533

print(dt.score(test_scaled, test_target))
 0.8415384615384616

훈련셋의 성능은 낮아졌지만 테스트셋의 성능은 거의 그대로이다. plot_tree() 함수로 그려보자.

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

와인데이터 결정트리, 깊이 3와인데이터 결정트리 그림, 깊이 3

노드를 나누는 기준을 보면 특성값을 어떤 음수값을 기준으로 나누고 있는 노드가 보인다.

잎이 불순도를 기준으로 샘플을 나누고 불순도는 클래스별 비율을 가지고 계산하기 때문에 특성값의 스케일에 영향을 미치지 않는다. 따라서 표준화 전처리를 할 필요가 없는 결정 트리 알고리즘의 장점 중 하나이다.

전처리 하기 전의 데이터로 다시 학습하고 트리를 그려보자

1
2
3
4
5
6
7
8
9
10
11
12
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()

전처리전 와인데이터 결정트리, 깊이 3전처리전 와인데이터 결정트리 그림, 깊이 3

결과도 동일하고 특성값을 표준점수로 바꾸지 않은 데이터라 이해하기 훨씬 쉽다.

당도가 1.625보다 크고 4.325보다 작은 와인 중에 알코올 도수가 11.025와 같거나 작은 것은 레드와인으로 분류된다.

마지막으로 결정 트리는 어떤 특성이 가장 유용한지 나타내는 특성 중요도를 계산해준다. 이 트리의 루트 노드와 깊이 1에서 당도를 사용했기 때문에 아마도 당도(sugar)가 가장 유용한 특성 중 하나일 것이다.

특성 중요도는 결정 트리 모델의 feature_importances_속성에 저장되어 있다.

1
2
print(dt.feature_importances_)
 [0.12345626 0.86862934 0.0079144 ]

두번째 특성인 당도가 0.87정도로 특성 중요도가 가장 높습다. 그 다음 알코올 도수, pH 순이다. 이 값을 모두 더하면 1이 되고 특성 중요도는 각 노드의 정보 이득과 전체 샘플에 대한 비율을 곱한 후 특성별로 더하여 계산된다.

2. 교차 검증과 그리드 서치

검증 세트

검증 세트검증 세트

  • 테스트 세트를 사용하지 않고 모델이 과대적합인지, 과소적합인지 판단하는 방법.

  • 보통 전체 데이터중 20%를 테스트 세트로 80%를 훈련세트로 만든 뒤, 이 훈련 세트중 20%를 다시 떼어내서 검증세트로 만든다.

  • 많은 데이터를 훈련할수록 좋은 모델이 생기지만, 검증 세트를 너무 적게 때면 검증 점수가 들쭉 날쭉해질 것이다.

교차 검증

검증 세트를 떼어내는 과정을 여러번 반복 하는 것.

3-폴드 교차 검증3-폴드 교차 검증

  • 사이킷런에는 cross_validate라는 교차 검증 함수가 있다.

  • 평가할 모델 객체를 첫번째 매개변수로 넣고, 두번째 매개변수로는 훈련세트 전체를 집어 넣는다.

1
2
3
4
5
6
from sklearn.model_selection import cross_validate

scores = cross_validate(dt, train_input, train_target)
print(scores)

 {'fit_time': array([0.00725031, 0.00697041, 0.00710249, 0.00712824, 0.00681305]), 'score_time': array([0.00077963, 0.00055647, 0.0005784 , 0.00052595, 0.00059152]), 'test_score': array([0.86923077, 0.84615385, 0.87680462, 0.84889317, 0.83541867])}
  • fit_time(모델 훈련 시간), score_time(검증 시간),test_score(검증 폴드의 점수 != 테스트 점수)를 반환한다.

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

  • cross_validate()는 훈련 세트를 섞어 폴드를 나누지 않는다 => 훈련 세트를 섞으려면 분할기(splitter) 필요

분할기

교차 검증에서 폴드를 어떻게 나눌지 결정해준다.

기본적으로 회귀모델에서는 KFold분할기를, 분류모델일 경우에는 StratifiedKFold를 사용한다.

1
2
3
4
5
6
7
8
9
10
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 : 폴드의 수
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']))

하이퍼파라미터 튜닝

[하이퍼파라미터를 튜닝하는 과정]

1) 라이브러리가 제공하는 기본값을 그대로 사용해 모델을 훈련

2) 검증세트의 점수나 교차 검증을 통해서 매개변수를 조금씩 바꿔본다.

하지만 이럴 경우, 매개변수가 많아지면 각 값을 하나씩 변경하여 무한히 많이 반복을 돌려야 하므로 일일이 구하기 어려울 수 있다.

  • AutoML : 사람의 개입 없이 하이퍼파라미터튜닝을 자동으로 수행하는 기술

  • 이를 해결하는 도구 중 하나가 그리드서치(GridSearch)이다.

그리드서치

1
2
3
4
5
6
7
8
9
10
#GridSearchCV를 임포트
from sklearn.model_selection import GridSearchCV

#찾고자 하는 매개변수의 최적값 리스트를 딕셔너리로 변경
params = {'min_impurity_decrease': [0.0001, 0.0002, 0.0003, 0.0004, 0.0005]}

#GridSearchCV클래스에 탐색 대상 모델과 params 변수를 전달하여 그리드 서치 객체를 만든다.
gs = GridSearchCV(DecisionTreeClassifier(random_state=42), params, n_jobs=-1)

gs.fit(train_input, train_target)

GridSearchCV의 cv 매개변수 기본값은 5이다, 따라서 찾고자 하는 매개변수의 값마다 5-폴드 교차검증을 수행한다.

즉, 총 25개의 모델을 훈련하는 것이다.

많은 모델을 훈련하기 때문에 n_jobs매개변수를 사용해 병렬실행에 사용할 CPU코어수를 정할 수 있다. 이떄 n_jobs를 ‘-1’로 지정하면 모든 코어를 사용하게 된다.

1
2
3
4
dt = gs.best_estimator_
print(dt.score(train_input, train_target))

print(gs.best_params_)

그리드 서치는 훈련이 끝나면 검증 점수가 가장 높은 모델의 매개변수 조합으로 지정해 전체 훈련세트에서 자동으로 다시 훈련한다. 이때 사용되는 매개변수는 best_estimator_에 저장되어 있다.

그리드 서치로 찾은 최적의 매개변수는 best_params_에 저장되어 있다.

1
2
dt = gs.best_estimator_
print(dt.score(train_input, train_target))

매개변수는 하나가 아니라 여러개를 사용해서 사용이 가능하다.

1
2
3
4
5
6
7
8
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_)

[그리드 서치 과정 정리]

1) 탐색할 매개변수 목록 지정

2) 훈련 세트에서 그리드서치를 수행하여 최상의 평균 검증 점수가 나오는 매개변수 조합을 찾음 => 이 매개변수 조합은 그리드 서치 객체에 저장됨

3) 저장된 최상의 매개변수로 교차검증에 사용한 훈련세트가 아닌 전체 훈련 세트를 사용해 최종모델 훈련 => 이 역시 그리드 서치 객체에 저장됨

렌덤서치

개변수를 샘플링할 수 있는 확률 분포 객체를 전달해 최적의 매개변수를 찾는 과정이다.

매개변수의 값이 수치일때 값의 범위나 간격을 미리 정하기 어려울 수 있다. 또 너무 많은 매개변수가 있을 경우 그리드 서치가 수행시간이 더 오래걸릴 수 있다. 이럴때 랜덤서치를 사용하는 것이 좋다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from scipy.stats import uniform, randint

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_)

dt = gs.best_estimator_

print(dt.score(test_input, test_target))

3. 트리의 앙상블

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

  • 정형 데이터 : 구조가 정해져 있고 가지런히 정리된 데이터

  • 비정형 데이터 : 데이터베이스나 엑셀로 표현하기 어려운 것들. 텍스트, 사진, 음성파일등이 해당된다.

앙상블 학습

  • 다양한 분류 알고리즘(주로 결정 트리를 기반)을 합쳐서 학습을 진행하는 방법

  • 랜덤 포레스트, 엑스트라 트리, 그레이디언트 부스팅 등이 있다.

랜덤 포레스트

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

랜덤 포레스트는 각 트리를 훈련하기 위한 데이터를 랜덤하게 만드는게 이때 부트스트랩 샘플을 사용한다.

랜덤 포레스트랜덤 포레스트

부트스트랩 샘플

전체 세트에서 뽑았던 샘플을 다시 넣어서 복원 추출을 하게 하는 것. 이 경우 중복이 적용된다.

보통 부트 스트랩 방식이라고 한다.

부트스트랩 샘플

또한 각 노드를 분할할때 전체 특성 중 일부 특성을 무작위로 고른 다음 이 중에서 최선의 분할을 찾는다.

분류 모델인 RandomForestClassifier는 기본적으로 전체 특성 개수의 제곱근 만큼 특성을 선택한다.

RandomForestClassifier

1
2
3
4
5
6
7
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']))

코드의 사용방법은 다른 학습모델과 큰 차이가 없다.

랜덤 포레스트는 결정 트리의 앙상블이기 때문에 특성 중요도를 계산해서 출력할 수 있다.

1
2
3
# 특성 중요도 계산
rf.fit(train_input, train_target)
print(rf.feature_importances_)

RandomForestClassifier에는 자체적으로 모델을 평가하는 점수를 얻을 수 있다.

부트스트래핑을 할때,부트스트랩 샘플에 포함되지 않고 남은 샘플(=OOB샘플)로 훈련한 결정트리를 평가할 수 있다.(이때 OOB샘플은 검증 세트의 역할을 하는 셈이다) 이 점수를 얻으려면 매개변수 oob_score를 True로 지정해야 한다.

1
2
3
4
rf = RandomForestClassifier(oob_score=True, n_jobs=-1, random_state=42)

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

엑스트라 트리

랜덤 포레스트와 비슷하게 동작하지만, 엑스트라 트리는 부트스트랩 샘플을 사용하지 않고 결정트리를 만들때 전체 훈련 세트를 사용한다.

대신 노드를 분할할때 무작위로 분할하게 된다(spliter=random)

성능은 낮아질 수 있지만 많은 트리를 앙상블 하기 때문에 과대적합을 막고 검증세트의 점수를 높이는 효과가 있다.

사이킷런에서 제공하는 엑스트라 트리는 ExtraTreesClassifier이다.

그 외 매개변수는 랜덤포레스트와 거의 동일하다.

1
2
3
4
5
6
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']))

그레이디언트 부스팅

깊이가 얕은 결정 트리를 사용하여 이진트리의 오차를 보완하는 방식으로 앙상블 하는 방법

경사하강법을 사용하여 트리를 앙상블에 추가하며, 분류에서는 로지스틱 손실 함수를, 회귀에서는 평균 제곱 오차 함수를 사용한다.

일반적으로 그레이디언트 부스팅이 랜덤 포레스트보다 조금 더 높은 성능을 얻을 수 있다. 하지만 순서대로 트리를 추가하기 때문에 훈련 속도가 느리다.(그래서 GradientBoostingClassifier에는 n_jobs가 없다.)

사이킷런에서 제공하는 그레이디언트 부스팅 클래스는 GradientBoostingClassifier이다.

1
2
3
4
5
6
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']))

결정 트리에는 아래와 같은 매개변수들이 있다.

1) n_estimators : 사용할 결정 트리의 개수, 기본값은 100이다.

2) learning_rate: 학습률, 기본값은 0.1이다.

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

입력 특성을 256개의 구간으로 나누고, 그 구간중에서 하나를 떼어놓고 누락된 값을 위해서 사용한다.

사이킷런에서 제공하는 히스토그램 기반 그레이디언트 부스팅 클래스는 HistGradientBoostingClassifier이다.

1
2
3
4
5
6
7
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']))

히스토그램 기반 그레이디언트 부스팅의 회귀버전은 HistGradientBoostingRegressor에 구현되어 있다.

사이킷런 말고도 히스토그램 기반 그레이디언트 부스팅 알고리즘을 구현한 라이브러리로 XGBoost, LightGBM등이 있다.

XGBoost

1
2
3
4
5
6
from xgboost import XGBClassifier

xgb = XGBClassifier(tree_method='hist', random_state=42)
scores = cross_validate(xgb, train_input, train_target, return_train_score=True, n_jobs=-1)

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

여러개의 Decision Tree를 조합해서 사용하는 Ensemble 알고리즘

XGBoost에서 tree_method를 hist로 지정하면 히스토그램 기반 그레이디언트 부스팅 알고리즘을 쓸 수 있다.

LightGBM

1
2
3
4
5
6
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']))

LightGBM의 경우에는 최대 손실값을 가지는 노드를 중심으로 계속해서 분할하는 ‘리프 중심 트리 분할(leaf-wise)’ 방식을 사용한다.

따라서 트리가 깊어지기위해 소요되는 시간과 메모리를 많이 절약할 수 있다.

다만 적은 데이터에 대한 과적합(overfitting)이 발생하기 쉽다.

This post is licensed under CC BY 4.0 by the author.