결정 트리 만들기

이 단원에서는 YDF (Yggdrasil 결정 포레스트) 라이브러리 트레인을 사용하고 결정 트리를 해석합니다.

이 단원은 🧭 YDF 시작하기 튜토리얼에서 영감을 받았습니다.

예비 과정

데이터 세트를 연구하기 전에 다음을 수행합니다.

  1. Colab 노트북을 만듭니다.
  2. 새 Colab 노트북에 다음 코드 줄을 배치하고 실행하여 YDF 라이브러리를 설치합니다.
    !pip install ydf -U
    
  3. 다음 라이브러리를 가져옵니다.
    import ydf
    import numpy as np
    import pandas as pd
    

파머펭귄 데이터 세트

이 Colab에서는 세 가지 펭귄 종의 크기 측정치가 포함된 Palmer Penguins 데이터 세트를 사용합니다.

  • 턱끈
  • 젠투
  • 아델리

이 문제는 팔머의 펭귄 데이터 세트의 데이터를 기반으로 펭귄의 종을 예측하는 문제인 분류 문제입니다. 다음은 펭귄입니다.

세 종류의 펭귄 종입니다.

그림 16. 세 가지의 서로 다른 펭귄 종입니다. 이미지 제공: @allisonhorst

 

다음 코드는 pandas 함수를 호출하여 파머 펭귄 데이터 세트를 메모리에 로드합니다.

path = "https://storage.googleapis.com/download.tensorflow.org/data/palmer_penguins/penguins.csv"
dataset = pd.read_csv(path)
label = "species"

# Display the first 3 examples.
dataset.head(3)

다음 표는 Palmer Penguins 데이터 세트의 처음 3개 예시의 형식을 지정합니다.

표 3. 파머 펭귄스의 처음 세 가지 예

bill_length_mm bill_depth_mm flipper_length_mm body_mass_g sex
0 아델리 토르게르센 3,910만 18.7 181.0 3,750.0 남성 2007
1 아델리 토르게르센 39.5리라 17.4 186.0 3,800.0 여성 2007
2 아델리 토르게르센 40,300원 18.0 195.0 3,250.0 여성 2007

전체 데이터 세트에는 숫자 (예: bill_depth_mm), 범주형 (예: island), 누락된 특성이 혼합되어 있습니다. 신경망과 달리 결정 포레스트는 기본적으로 이러한 모든 특성 유형을 지원하므로 원-핫 인코딩, 정규화 또는 추가 is_present 특성을 수행할 필요가 없습니다.

다음 코드 셀은 데이터 세트를 학습 세트 및 테스트 세트로 분할합니다.

# Use the ~20% of the examples as the testing set
# and the remaining ~80% of the examples as the training set.
np.random.seed(1)
is_test = np.random.rand(len(dataset)) < 0.2

train_dataset = dataset[~is_test]
test_dataset = dataset[is_test]

print("Training examples: ", len(train_dataset))
# >> Training examples: 272

print("Testing examples: ", len(test_dataset))
# >> Testing examples: 72

기본 초매개변수로 결정 트리 학습

초매개변수를 지정하지 않고 CART (Classification and Regression Trees) 학습 알고리즘 (학습자라고도 함)을 사용하여 첫 번째 결정 트리를 학습시킬 수 있습니다. ydf.CartLearner 학습자가 적절한 기본 초매개변수 값을 제공하기 때문입니다. 이 유형의 모델의 작동 방식에 대해서는 이 과정의 후반부에서 자세히 알아보겠습니다

model = ydf.CartLearner(label=label).train(train_dataset)

이전 호출은 입력 특성으로 사용할 열을 지정하지 않았습니다. 따라서 학습 세트의 모든 열이 사용됩니다. 또한 호출은 입력 특성의 시맨틱스 (예: 숫자, 범주형, 텍스트)를 지정하지 않았습니다. 따라서 특성 의미 체계가 자동으로 추론됩니다.

model.plot_tree()를 호출하여 결과 결정 트리를 표시합니다.

model.plot_tree()

Colab에서는 마우스를 사용하여 각 노드의 클래스 분포와 같은 특정 요소에 관한 세부정보를 표시할 수 있습니다.

기본 초매개변수로 학습된 결정 트리

그림 17. 기본 초매개변수로 학습된 결정 트리

Colab에서 루트 조건에 243개의 예가 있음을 보여줍니다. 그러나 학습 데이터 세트에 272개의 예시가 있었다는 것을 기억할 수 있습니다. 나머지 29개 예는 유효성 검사 및 트리 가지치기를 위해 자동으로 예약되었습니다.

첫 번째 조건은 bill_depth_mm의 값을 테스트합니다. 표 4와 5는 첫 번째 조건의 결과에 따른 다양한 종의 가능성을 보여줍니다.

표 4. bill_depth_mm ≥ 42.3인 경우 다양한 종의 가능성

가능성
Adelie (빨간색) 8%
Gentoo (파란색) 58%
턱끈 (녹색) 36%

 

표 5. bill_depth_mm < 42.3 인 경우 다양한 종의 가능성

가능성
Adelie (빨간색) 97%
Gentoo (파란색) 2%
턱끈 (녹색) 0%

bill_depth_mm는 숫자 특성입니다. 따라서 값 42.3은 숫자 특성이 있는 이진 분류를 위한 정확한 분할 알고리즘을 사용하여 찾았습니다.

bill_depth_mm ≥ 42.3가 True이면 flipper_length_mm ≥ 207.5가 Gentoos와 Gentoos+Adelie를 거의 완벽하게 구분할 수 있는지 여부를 추가로 테스트합니다.

다음 코드는 모델의 학습 및 테스트 정확성을 제공합니다.

train_evaluation = model.evaluate(train_dataset)
print("train accuracy:", train_evaluation.accuracy)
# >> train accuracy:  0.9338

test_evaluation = model.evaluate(test_dataset)
print("test accuracy:", test_evaluation.accuracy)
# >> test accuracy:  0.9167

드물지만 테스트 정확성이 학습 정확성보다 높을 수 있습니다. 이 경우 테스트 세트가 학습 세트와 다를 수 있습니다. 그러나 여기서는 학습 및 테스트가 무작위로 분할되었기 때문에 그렇지 않습니다. 테스트 데이터 세트가 매우 작아서 (예시 72개) 정확도 추정에 노이즈가 많다는 것을 더 잘 설명할 수 있습니다.

실제로는 이러한 작은 데이터 세트의 경우 더 정확한 평가 측정항목 값을 계산할 수 있는 교차 검증을 사용하는 것이 더 좋습니다. 하지만 이 예에서는 단순성을 위해 학습과 테스트를 계속 진행합니다.

모델 초매개변수 개선

이 모델은 기본 초매개변수 값으로 학습된 단일 결정 트리입니다. 더 정확한 예측을 얻으려면 다음과 같이 하면 됩니다.

  1. 랜덤 포레스트그라데이션 부스티드 트리 모델과 같이 더 강력한 학습자를 사용합니다. 이러한 학습 알고리즘은 다음 페이지에서 설명합니다.

  2. 관찰과 직관을 바탕으로 초매개변수를 옵티마이저합니다. 모델 개선 가이드가 유용할 수 있습니다.

  3. 초매개변수 조정을 사용하여 가능한 많은 수의 초매개변수를 자동으로 테스트합니다.

랜덤 포레스트 및 그래디언트 부스티드 트리 알고리즘은 아직 본 적이 없고, 자동 초매개변수 조정을 수행하기에는 예의 수가 너무 적으므로 모델을 수동으로 개선합니다.

위에 표시된 결정 트리는 작으며 예가 61개인 리프에는 아델리와 친스트랩 라벨이 혼합되어 있습니다. 왜 알고리즘이 이 리프를 더 나누지 않았을까요? 다음과 같이 두 가지 원인이 있습니다.

  • 리프당 최소 샘플 수 (기본값 min_examples=5)에 도달했을 수 있습니다.
  • 트리를 분할한 다음 과적합을 방지하기 위해 가지치기했을 수 있습니다.

최소 예 수를 1개로 줄이고 결과를 확인합니다.

model = ydf.CartLearner(label=label, min_examples=1).train(train_dataset)
model.plot_tree()

min_examples=1로 학습된 결정 트리

그림 18. min_examples=1로 학습된 결정 트리

 

61개의 예가 포함된 리프 노드를 여러 번 더 나눴습니다.

노드를 추가로 분할하는 것이 중요한지 확인하기 위해 테스트 데이터 세트에서 이 새 모델의 품질을 평가합니다.

print(model.evaluate(test_dataset).accuracy)
# >> 0.97222

테스트 정확성이 0.9167에서 0.97222로 높아져 모델의 품질이 향상되었습니다. 이러한 초매개변수 변경은 좋은 생각이었습니다.

결정 포레스트의 이전

초매개변수를 지속적으로 개선하면 완벽한 정확성에 도달할 수 있습니다. 하지만 이 수동 프로세스 대신 랜덤 포레스트와 같은 더 강력한 모델을 학습시키고 더 잘 작동하는지 확인할 수 있습니다.

model = ydf.RandomForestLearner(label=label).train(pandas_train_dataset)
print("Test accuracy: ", model.evaluate(pandas_test_dataset).accuracy)
# >> Test accuracy: 0.986111

랜덤 포레스트의 정확성은 단순한 트리보다 높습니다. 다음 페이지에서 그 이유를 알아보겠습니다.

사용 및 제한사항

앞서 언급했듯이 단일 결정 트리는 랜덤 포레스트, 그라데이션 부스티드 트리, 신경망과 같은 최신 머신러닝 방법보다 품질이 낮은 경우가 많습니다. 그러나 결정 트리는 다음과 같은 경우에도 여전히 유용합니다.

  • 보다 복잡한 접근 방식을 평가하기 위한 간단하고 저렴한 기준
  • 모델 품질과 해석 가능성 간에 균형이 있는 경우
  • 결정 포레스트 모델 해석의 프록시로 사용되며 이에 대해서는 과정 후반부에서 살펴보겠습니다