결정 트리 만들기

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

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

예비 과정

데이터 세트를 살펴보기 전에 다음을 수행하세요.

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

Palmer Penguins 데이터 세트

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

  • 턱끈
  • Gentoo
  • 아델리

이는 분류 문제입니다. 목표는 Palmer's Penguins 데이터 세트의 데이터를 기반으로 펭귄의 종을 예측하는 것입니다. 다음은 펭귄입니다.

세 가지 다른 펭귄 종

그림 16. 세 가지 다른 펭귄 종 이미지 제공: @allisonhorst

 

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

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. Palmer Penguins의 처음 3개 예시

bill_length_mm bill_depth_mm flipper_length_mm body_mass_g sex
0 아델리 Torgersen 39.1 18.7 181.0 3750.0 남성 2007
1 아델리 Torgersen 39.5 17.4 186.0 3800.0 여성 2007
2 아델리 Torgersen 40.3 18.0 195.0 3250.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 (분류 및 회귀 트리) 학습 알고리즘 (학습자라고도 함)으로 첫 번째 의사결정 트리를 학습시킬 수 있습니다. 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인 경우 다양한 종의 가능성

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

 

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

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

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

bill_depth_mm ≥ 42.3가 True인 경우 flipper_length_mm ≥ 207.5가 Gentoo와 Gentoo+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(train_dataset)
print("Test accuracy: ", model.evaluate(test_dataset).accuracy)
# >> Test accuracy: 0.986111

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

사용 및 제한사항

앞서 언급한 것처럼 단일 의사결정 트리는 랜덤 포레스트, 그레이디언트 부스티드 트리, 신경망과 같은 최신 머신러닝 방법보다 품질이 낮은 경우가 많습니다. 하지만 다음과 같은 경우에는 결정 트리가 여전히 유용합니다.

  • 더 복잡한 접근 방식을 평가하기 위한 간단하고 저렴한 기준선
  • 모델 품질과 해석 가능성 사이에 상충 관계가 있는 경우
  • 이 과정에서 나중에 살펴볼 결정 포레스트 모델의 해석을 대신합니다.