본문 바로가기
의학 연구

[비전공자의 머신러닝 의학연구 #4] 결정트리 Decision Tree

by Dr CK 2026. 5. 2.

결정트리 (Decision Tree) 란 머신러닝 모형 중 하나로 스무고개처럼 Yes/No 의 답을 해가며 데이터를 분류하거나 수치를 예측하는 모형으로, 실제 사고방식과 유사하다.  if-then 의사결정 규칙이 트리 형태로 쌓인 것이고, 그래서 머신러닝 모델 중에서 임상적 직관과 가장 잘 맞는 모델이라고 볼 수 있다. 이렇게 질문에 따라 데이터들이 분기되는것이 트리를 닮았다고 하여 결정트리라고 한다.

1. 결정트리란?

데이터를 if-then 질문으로 반복해서 나누는 모델이다. 데이터 한 줄(예: 환자 한 명)이 들어오면, 트리의 꼭대기부터 질문에 답하면서 내려가다가, 마지막 잎(leaf)에 도달하면 그 잎의 예측값이 결과가 된다.

 

3가지 종류의 노드 :

  • 루트 노드(Root) — 트리의 꼭대기. 모든 데이터로 시작
  • 내부 노드(Internal) — 분할 조건을 가진 의사결정 노드 ("age ≥ 65?")
  • 잎 노드(Leaf) — 더 이상 분할되지 않는 종착점. 예측값을 출력

이 구조의 가장 큰 장점은 해석 가능성이다. 의사가 머릿속으로 진단 알고리즘을 따라가는 것과 똑같다. SHAP이나 LIME 같은 부가 해석 도구 없이도, 트리 자체가 임상 규칙으로 직접 변환되는 화이트박스 (white-box) 모형이다.

 

2. 결정트리의 학습 — 어떻게 분할을 결정하는가?

결정트리의 핵심은 어떤 변수를, 어떤 값에서 나눌 것인가 이다. 이걸 정하는 기준이 분할 기준(splitting criterion) 이다.

각 노드의 순도(purity) 를 측정해서, 분할 후 자식 노드들의 순도가 가장 높아지는 분할을 선택한다. 즉 불순도(impurity)가 가장 많이 줄어드는 분할을 찾는것이고, 가장 많이 쓰이는 불순도 측정이 두 가지 있다.

2-1. Gini 불순도 (CART 알고리즘 — sklearn 기본값)

Gini 불순도 는 "이 노드 안에서 무작위로 한 샘플을 뽑았을 때, 그것을 잘못 분류할 확률" 이다.

한 노드 안에 다양한 클래스가 섞일수록 Gini가 크고, 한 클래스로 통일될수록 0에 가까워진다

2-2. 엔트로피와 정보 이득

엔트로피(Entropy) 는 정보이론에서 온 불확실성 의 측정이다.

엔트로피는 0~1 사이 값을 가진다 (이진 분류 기준). 0에 가까울수록 순수, 1에 가까울수록 혼잡.

분할의 정보 이득(Information Gain) 은 — 분할 전 엔트로피 - 분할 후 엔트로피의 가중평균. 이 값이 클수록 좋은 분할이다.

2-3. 회귀 트리는 다른 기준을 쓴다

지금까지는 분류 트리이다. 회귀 트리 (연속값 예측) 는 분할 기준이 다르다 — MSE(평균제곱오차) 감소 또는 MAE 감소 를 사용한다.

"분할 후 자식 노드 안의 값들이 얼마나 비슷해졌는가" 를 보고, 비슷할수록 (분산이 작을수록) 좋은 분할이다.

작업이 다르면 불순도의 정의가 다를 뿐, 재귀적으로 가장 좋은 분할을 찾는다는 큰 흐름은 같다.

 

3. 분할 후보의 평가 — 매 노드에서 무엇을 비교하는가?

매 분할 시점에 알고리즘은 모든 변수 × 모든 분할점 조합을 평가한다.

  • 연속형 변수 (예: age) — 정렬 후 인접값 사이의 중간점을 후보로
  • 범주형 변수 (예: sex) — 가능한 부분집합 분할

각 후보에 대해 불순도 감소량을 계산한다 :

ΔI = I(부모) − [w_L × I(좌) + w_R × I(우)]

여기서 w_L, w_R은 각 자식 노드의 가중치(샘플 비율). 감소량이 가장 큰 (변수, 분할점) 조합이 선택된다.

위 그림은 같은 부모 노드에서 3가지 분할 후보를 평가한 예시이다. 각 분할의 자식 노드 Gini를 계산하고, 가중평균을 낸 후 부모 Gini와 비교한다. 감소량이 가장 큰 후보가 선택된다.

4. 학습 알고리즘의 흐름

위 분할 기준을 가지고 결정트리를 학습하는 알고리즘:

  1. 루트 노드 생성 — 모든 훈련 데이터로 시작
  2. 최적 분할 탐색 — 모든 (변수, 분할점) 조합을 평가 → 불순도 감소량이 최대인 것 선택
  3. 자식 노드 생성 — 선택된 분할로 데이터를 두 부분집합으로 나눔
  4. 재귀 적용 — 각 자식 노드에 대해 2-3을 독립적으로 반복. 좌측 자식과 우측 자식이 서로 다른 변수, 다른 분할점을 가질 수 있다 — 이게 결정트리가 변수 간 상호작용을 자연스럽게 학습하는 비결이다.
  5. 정지 조건 검사 — 다음 중 하나라도 만족되면 잎 노드로 만든다 :
    • 노드의 모든 샘플이 같은 클래스 (완전 순수)
    • 노드 샘플 수가 min_samples_split 미만
    • 트리 깊이가 max_depth 도달
    • 어떤 분할도 의미있는 불순도 감소를 못 만듦
  6. 잎 예측값 할당 — 분류는 다수결, 회귀는 평균
  7. 가지치기 (선택적) — 학습 후 비용-복잡도 가지치기 로 트리를 단순화 (과적합 방지)

이 알고리즘은 탐욕적(greedy) 이다. 탐욕적 알고리즘이란 매 순간 그 시점에서 가장 좋아 보이는 선택만 하는 알고리즘을 뜻한다. 매 분할에서 그 시점에 최적인 분할만 선택할 뿐, 전체 트리의 최적성을 보장하지는 않는다. 어떤 분할이 당장은 별로지만 이후에 큰 효과를 낼 수 있어도, 그 분할은 선택되지 않는다. 이게 결정트리의 알려진 한계이고, 부스팅이 부분적으로 보완하는 부분이다.

 

5. 결정트리의 데이터 요구사항

결정트리는 데이터 전처리 요구사항이 가장 적은 모델 중 하나이다.

  • 정규화·표준화 불필요 — 분할 기준은 단조 변환에 불변. age를 그대로 써도, log(age)를 써도, (age-50)/10을 써도 결과가 같다. 트리 모델은 표준화가 필요 없다.
  • 다중공선성 강건함 — 두 변수가 강하게 상관되어도 큰 문제 없음. 트리는 그 중 하나만 사용한다.
  • 이상치 강건함 — 분할 기준의 비교만으로 처리되므로 영향이 제한적이다.
  • 수치 인코딩 — sklearn 구현은 범주형 변수를 수치로 인코딩해야 한다 (Ordinal encoding 또는 One-hot)
  • 결측치 처리 — sklearn은 결측을 직접 처리 못함 → SimpleImputer 등으로 사전 처리. 참고로 XGBoost는 결측을 알아서 처리한다.
  • 충분한 표본 — 잎 노드당 최소 10-30개 샘플이 권장된다. 그래야 통계적으로 의미있는 분할이 된다.

 

6. 하이퍼파라미터

max_depth : 트리의 깊이 제한한다. 가장 중요한 파라미터로 과적합 통제의 가장 중요한 역할. 데이터마다 최적값이 다르므로 반드시 튜닝한다.

min_samples_split : 분할에 필요한 최소 샘플. "이 노드를 더 나누려면 최소 몇 명이 있어야 하는가?" 의 기준값. 너무 적은 샘플로 분할하면 통계적으로 의미없는 패턴을 학습할 수 있다.

min_samples_leaf : 잎 노드의 최소 샘플수. "분할 결과로 만들어진 각 자식이 최소 몇 명을 가져야 하는가?" 의 기준값. min_samples_split와의 차이점은 min_samples_split은 부모 노드가 분할을 시도할 수 있는지를 본다. min_samples_leaf는 그 분할의 결과가 받아들일 만한지를 본다.

criterion — 분할 기준. 보통 Gini와 Entropy. 큰 차이 없다.

 

7. 파이썬 코드 예시

 

1.10. Decision Trees

Decision Trees (DTs) are a non-parametric supervised learning method used for classification and regression. The goal is to create a model that predicts the value of a target variable by learning s...

scikit-learn.org

scikit-learn으로 결정트리 분류기를 학습하는 기본 코드이다.

설치가 필요한 패키지는 "scikit-learn" 으로 먼저 설치를 해야한다.

from sklearn.tree import DecisionTreeClassifier

# 모델 정의 및 학습
model = DecisionTreeClassifier(
    criterion='gini',
    max_depth=5,
    min_samples_split=20,
    min_samples_leaf=10,
    class_weight='balanced',
    random_state=42
)
model.fit(X_train, y_train)

# 평가
y_pred = model.predict(X_test)
y_proba = model.predict_proba(X_test)[:, 1]
print(f'Accuracy: {accuracy_score(y_test, y_pred):.3f}')
print(f'AUC:      {roc_auc_score(y_test, y_proba):.3f}')

 

X와 y의 입력 (데이터) 형식

X, y 모두 Numpy 배열을 입력형식으로 받고, X는 2D, y는 1D 배열의 형식을 취한다. 하지만 pandas 데이터 프레임 형식도 내부에서 Numpy로 변환하므로 pandas 형태도 괜찮다. Python의 List 형태도 입력받을 수 있다.

import numpy as np
import pandas as pd
from sklearn.tree import DecisionTreeClassifier

# 방법 1: NumPy 배열
X_np = np.array([[65, 3], [42, 1], [78, 4]])
y_np = np.array([1, 0, 1])

# 방법 2: Pandas DataFrame + Series
df = pd.read_csv('data.csv')
X_df = df[['age', 'stage']]   # DataFrame
y_df = df['outcome']            # Series

# 방법 3: 리스트
X_list = [[65, 3], [42, 1], [78, 4]]
y_list = [1, 0, 1]

# 셋 다 동일하게 작동
model = DecisionTreeClassifier()
model.fit(X_np, y_np)   # 또는 X_df, y_df / X_list, y_list

 

8. 결정트리의 한계

결정트리는 직관적이고 해석 가능하지만, 단독으로 쓰기엔 한계가 명확하다. 5가지를 본다.

불안정성 (High Variance) : 데이터의 작은 변화에도 트리 구조가 크게 바뀐다. 같은 데이터에서 한 샘플만 빼도 완전히 다른 트리가 만들어질 수 있다. 결정트리의 가장 큰 약점이다.

과적합 경향 : 깊이가 깊어지면 훈련 데이터에 과하게 맞춰진다. 잎이 너무 작아져 훈련 데이터의 노이즈까지 학습해버린다. max_depth나 ccp_alpha로 통제해야 한다.

편향된 분할 선택 : 카디널리티가 높은 변수 (가능한 값이 많은 변수) 를 선호한다. age 같은 연속형 변수가 sex 같은 이진 변수보다 더 자주 분할에 등장하는 경향이 있다.

외삽(extrapolation) 불가 : 훈련 데이터의 범위 밖은 예측할 수 없다. age 30~80으로 학습한 트리에 age=90을 넣으면, 트리는 그냥 가장 비슷한 잎(age 70-80 잎)의 예측을 그대로 출력한다.

탐욕적 알고리즘의 한계 : 매 단계에서 국소 최적만 선택. 전체 트리의 최적은 보장 못 한다.

 

반응형