의사결정트리로 분류 규칙을 설계하는 방법
의사결정트리의 분할 기준, 가지치기, 결측값 처리와 규칙 추출 방식을 정리하고 분류·회귀 모델 운영 시 고려할 사항을 다룬다.
2026-08-14 · 최초 발행 2025-10-14
규칙을 따라 데이터를 나누는 모델
의사결정트리는 일련의 의사결정 규칙으로 레코드 집합을 작은 그룹으로 나누고, 각 그룹의 분류나 예측값을 결정하는 지도학습 기법이다. 분기가 진행될수록 노드는 더 순수한 집단이 되도록 구성된다. 분류(classification)와 회귀(regression) 모두에 쓸 수 있으며, 규칙을 설명하고 운영에 반영하기 쉽다는 점이 강점이다.
18세기 칼 린네의 생물 분류 체계처럼, 조건을 따라가며 결과에 도달하는 직관적인 구조를 제공한다. 의사결정 노드는 분기 규칙을 갖고, 통계적 검정에 따른 분기는 Chance/Test Node로 표현할 수 있다. 최종 클래스나 값을 내놓는 곳은 End(Leaf) Node다.
이 구조가 필요한 이유는 예측값만이 아니라 명확한 규칙셋도 함께 얻을 수 있기 때문이다. 해석과 설명이 쉬우며, 운영 규칙 자동화에도 연결하기 좋다.
순수도를 높이는 분기 설계
범주형 타깃은 엔트로피와 정보이득(Information Gain), 지니지수(Gini), 카이제곱(CHAID)으로 분기를 평가할 수 있다. 연속형 타깃에는 분산 축소(Variance Reduction)나 F-검정을 적용한다.
ID3나 CHAID처럼 여러 갈래로 나누는 방식과 CART처럼 이진으로 나누는 방식은 함께 고려할 수 있다. 데이터 분포와 운영 요구가 선택의 기준이 된다.
수치형 변수는 대체로 임계값을 찾아 이진 분할한다. 어느 경계값을 택할지는 데이터 마이너의 역량과 검증 절차에 달려 있다. 범주형 변수는 고유값이 지나치게 많다면 유사 카테고리를 병합하고, 카이제곱 검정 등으로 그 근거를 확인할 수 있다.
결측값도 단순히 제거할 대상은 아니다. 별도 범주로 나누거나 대리 분할(surrogate split)을 적용할 수 있다. 설문 거부처럼 결측 자체가 행동 특성을 나타내는 경우에는 강한 분류 신호가 될 수 있다.
분할로 순수도가 더 이상 높아지지 않거나 최소 샘플 수 및 최대 깊이에 도달하면 트리 생성을 멈춘다. 다만 이렇게 만든 Full Tree가 곧 최적 모델이라는 뜻은 아니다. 과적합을 막으려면 가지치기(pruning)가 필요하다.
모델 복잡도와 검증을 함께 다루기
가지치기에는 비용-복잡도 가지치기(Cost-Complexity)나 오류 기반 감소(Error-Based)를 적용할 수 있다. 교차타당성으로 ccp_alpha 등의 최적 복잡도 파라미터를 고르고, 훈련 데이터와 검증 데이터의 분포가 다른지도 점검해야 한다.
루트에서 리프까지 이어지는 경로는 사람이 읽을 수 있는 if-then 규칙으로 바꿀 수 있다. 각 노드에 표본 수, 클래스 비율, 정분류 비율을 표시하면 운영 담당자와 규칙을 검토하기도 수월하다.
알고리즘별 성격
ID3는 엔트로피와 정보이득을 사용하며 다지분리를 중심으로 한다. 과적합 경향은 있지만 역사적 의의가 있다. C5.0은 개선된 정보이득 기준을 사용하고 다지·이진 분리를 지원하며, 속도와 메모리 효율을 개선했다. 가중치와 부스팅 옵션도 제공한다.
CHAID는 카이제곱 또는 F-검정에 기반한 다지분리 방식으로, 범주형 변수와 통계적 유의성 해석에 강점이 있다. CART는 지니지수와 분산차이를 이용해 이진분리하며, 회귀와 분류 모두에 적용할 수 있다. 대리 분할 등을 포함해 실무 안정성이 높다.
| 알고리즘 | 성능(정확도) | 확장성(속도/메모리) | 일관성(규칙 안정성) | 안정성(과적합 저항) | 운영 편의(설명/규칙화) |
|---|---|---|---|---|---|
| ID3 | 중 | 중 | 중하 | 하 | 중 |
| C5.0 | 중상 | 상 | 중상 | 중상 | 상 |
| CHAID | 중 | 중 | 중 | 중 | 상(유의성 해석 용이) |
| CART | 상(회귀 포함) | 중상 | 상 | 상(가지치기·대리분기) | 상 |
이 비교는 데이터 특성과 전처리 품질에 따라 달라질 수 있다.
트리 생성부터 운영 반영까지
분석은 목적을 정하고 후보 변수를 고른 뒤 분기 평가 척도를 정하는 흐름으로 시작한다. 좋은 분할은 자식 노드의 규모가 균형을 이루고, 부모 노드보다 순수도가 높아지는 경우다.
트리를 만든 다음에는 비용-복잡도 경로를 산출하고 검증 점수가 가장 높은 지점을 선택해 불필요하거나 부적절한 규칙을 덜어낸다. 교차타당성(K-fold), 홀드아웃 검증으로 과대적합과 과소적합을 확인하며, 훈련 데이터와 테스트 데이터 간 분포 변화 및 데이터 드리프트도 살핀다.
마지막으로 규칙셋과 임계값을 검토하고 리프별 행동 가이드를 정한다. 운영에 반영하기 전에는 샘플 파일로 예측 결과를 확인한다.
고카디널리티 범주는 병합 기준으로 카이제곱(χ²)을 적용할 수 있다. 클래스 불균형이 심하면 가중치나 샘플링을 사용한다. 결측이 많이 발생한다면 결측 전용 분기 또는 대리 분할을 사용하고, “is_null” 지표를 추가한다.
분기 품질을 점검하는 기준
사전 분류된 훈련 세트에서 입력 변수와 목표 변수를 분명히 구분한 뒤, 순수도 지표를 선택한다. 수치형 변수는 임계값을 스캔해 정보이득을 최대화하고, 범주형 변수는 유사 클래스를 병합한 뒤 χ²로 유의성을 검정한다. 결측값은 별도 분기나 대리 분할로 다루며 결측 여부 플래그도 활용한다.
순수도를 더 개선할 수 없거나 깊이 및 표본 한계에 이르면 Full Tree 생성을 멈춘다. Full Tree는 과적합 위험이 있으므로 이후 가지치기가 필요하다. 효과를 평가할 때는 노드에 유입된 레코드 수, 클래스 비율, 리프의 최종 분류 규칙, 노드별 정분류 비율을 보고 훈련·테스트 분포 차이와 분산·드리프트를 점검한다.
규칙 기반 판단이 필요한 영역
고객 세분화와 이탈 예측에서는 리프별 규칙을 캠페인 타깃팅과 오퍼 설계에 활용할 수 있다. 여신 심사와 사기 탐지에서는 설명 가능한 승인·거절 기준을 제공해 컴플라이언스 대응에 연결한다.
의료 트리아지와 품질 관리에는 임계값 기반 위험 등급화 및 공정 이상 탐지에 적용할 수 있다. 설문 비응답 관리에서는 결측값 분기로 “거부 집단”을 식별하고 별도 정책을 수립할 수 있다.
의사결정트리는 규칙셋을 기반으로 감사 추적을 남기고 비즈니스 룰을 옮기기 쉽다. 룰 엔진이나 SQL로 규칙을 전환하기 편해 릴리스 주기를 단축할 수 있다. 앙상블 대비 정확도는 3~10%p 낮을 수 있으나, 투명성과 운영 편의에서는 우위가 있다. 가지치기와 가중치 조정으로 안정성을 확보할 수 있다.
변수 수와 표본 수가 증가하면 선형~준선형으로 확장한다. 고카디널리티 범주와 결측이 많은 데이터에서는 전처리와 병합 전략이 필요하다.
Python으로 분류 모델 구성하기
전제조건: Python 3.10+, scikit-learn 1.3+, pandas 2.x
주의: scikit-learn DecisionTreeClassifier는 NaN 직접 분기를 지원하지 않음. 결측 지표 추가 및 단순 대치로 정보 손실 최소화.
# pip install scikit-learn==1.3.2 pandas==2.2.2
import pandas as pd
from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.tree import DecisionTreeClassifier
from sklearn.impute import SimpleImputer
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import OneHotEncoder
from sklearn.pipeline import Pipeline
# 예시 데이터
df = pd.DataFrame({
"age": [23, 45, 36, None, 52, 28, None, 41],
"gender": ["F", "M", "F", "F", "M", "M", None, "F"],
"income": [32.1, 58.4, 41.2, 39.0, 70.5, 35.0, 29.9, 55.3],
"label": [0, 1, 0, 0, 1, 0, 0, 1]
})
X = df[["age", "gender", "income"]]
y = df["label"]
# 결측 플래그 추가(결측 자체의 정보 보존)
for col in ["age", "gender", "income"]:
X[f"{col}_is_null"] = X[col].isna().astype(int)
num_cols = ["age", "income"]
cat_cols = ["gender"]
extra_cols = [c for c in X.columns if c.endswith("_is_null")]
preprocess = ColumnTransformer(
transformers=[
("num", SimpleImputer(strategy="median"), num_cols),
("cat", Pipeline(steps=[
("imp", SimpleImputer(strategy="most_frequent")),
("ohe", OneHotEncoder(handle_unknown="ignore"))
]), cat_cols)
],
remainder="passthrough" # 결측 플래그 유지
)
# 비용-복잡도 가지치기(ccp_alpha) 튜닝
clf = Pipeline(steps=[
("prep", preprocess),
("tree", DecisionTreeClassifier(random_state=42, class_weight="balanced", ccp_alpha=0.005, max_depth=5))
])
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42, stratify=y)
cv_score = cross_val_score(clf, X_train, y_train, cv=5, scoring="roc_auc").mean()
clf.fit(X_train, y_train)
print("CV AUC:", round(cv_score, 3))
print("Test Accuracy:", round(clf.score(X_test, y_test), 3))
클래스 불균형에는 class_weight 또는 샘플 가중치를 활용한다. ccp_alpha, max_depth, min_samples_leaf 같은 복잡도 파라미터는 교차타당성으로 탐색한다. 규칙을 배포할 때는 리프별 임계값을 룰 엔진이나 SQL로 변환하고 버전을 관리한다.
예측값보다 규칙이 중요한 경우
의사결정트리의 핵심은 순수도를 높이는 반복 분기와 간결한 규칙셋 도출에 있다. 정확도만 최대화하기보다 해석성, 운영 가능성, 거버넌스가 필요한 환경에 적합하다. 트리 생성, 가지치기, 타당성 평가, 해석과 배포의 흐름을 지키고 분할 기준 및 결측·범주형 변수 처리 전략을 함께 적용해야 안정성과 설명력을 확보할 수 있다.
초기 도입에서는 CART 또는 C5.0 기반 설정을 고려하고, ccp_alpha와 max_depth 튜닝 및 교차타당성 운영을 권장한다.