CART 회귀 트리 가지치기로 일반화 성능과 해석력 확보하기

CART 회귀 트리의 이진 분할과 비용-복잡도 가지치기 원리를 정리하고, 교차검증 기반 α 선택으로 과적합을 제어하는 방법을 다룬다.

2026-08-14 · 최초 발행 2024-04-29

규칙으로 읽을 수 있는 비선형 회귀 모델

CART(Classification and Regression Trees) 회귀 트리는 입력 공간을 재귀적인 이진 분할로 나눈 뒤, 각 리프 노드에 속한 목표값의 평균을 예측값으로 둔다. 구간별 상수(piecewise) 근사 방식이므로 비선형성이나 특성 간 상호작용을 다루면서도 결과를 if-then 규칙 집합으로 확인할 수 있다.

분할은 후보 특성과 임계값 가운데 평균제곱오차(MSE)를 가장 많이 줄이는 지점을 탐욕적(greedy)으로 고르는 방식이다. 연속형 특성은 정렬 기반으로 스캔하고, 범주형 특성은 서브셋 분할 또는 원-핫 인코딩을 전제로 처리한다. 각 선택은 지역적으로 최적이지만, 누적 결과가 전역 최적을 보장하지는 않는다. 그럼에도 계산 효율과 해석 가능성이 필요한 상황에서는 유용하다.

트리를 멈추거나 다시 덜어내는 방법

트리를 깊게 성장시키면 학습 데이터의 세부 패턴까지 흡수하기 쉽다. 이는 과적합과 샘플 변화에 따른 성능 변동으로 이어질 수 있다. 가지치기는 이 문제를 사전 또는 사후에 제어한다.

사전 가지치기(pre-pruning)는 성장 단계에서 최대 깊이, 리프 최소 샘플 수, 최소 불순도 감소 같은 종료 규칙을 적용하는 방식이다. 데이터가 적거나 노이즈가 많은 환경에서는 분산을 완화할 수 있지만, 제약이 과도하면 편향이 커지고 과소적합 위험이 생긴다.

사후 가지치기(post-pruning)는 완전 성장 트리에서 불필요한 하위 가지를 제거한다. 비용-복잡도(cost-complexity) 기준은 다음과 같이 경험오차와 복잡도 패널티를 함께 본다.

R_alpha(T) = 경험오차 + α·노드수

비용-복잡도 가지치기에서는 ccp_alpha 경로를 구한 뒤 교차검증으로 적절한 α를 고르고, 그 α에서 최소 비용 트리를 선택한다. α가 높을수록 단순한 트리가 선택되며, 낮을수록 복잡한 트리가 남는다.

학습 과정에서 확인할 조건

입력은 학습 데이터셋(D, 특성 X, 타깃 y), 전처리 스키마, 검증 전략(K-fold)이다. 분할 탐색으로 트리를 성장시킨 뒤 사전 가지치기 후보를 학습하고, 비용-복잡도 경로를 계산한다. 이어서 각 α를 교차검증으로 평가해 최종 트리를 학습한다. 산출물은 최종 회귀 트리와 검증 지표(RMSE/MAE), 규칙셋, 특성 중요도다.

극단적인 α가 리프 1개짜리 빈약한 트리를 만들면 해당 후보는 제외한다. 고유값이 많은 범주형 특성은 과적합 위험이 있으므로 빈도 하한을 두고, 타깃 인코딩을 쓸 때는 폴드 내 피팅으로 누설을 막아야 한다. 데이터가 적으면 성능 분산이 커질 수 있어 반복 K-fold와 불확실성 리포트를 병행하는 편이 낫다.

입력 데이터 X,y전처리결측 처리·인코딩완전 트리 성장(사전 가지치기 최소화)비용-복잡도 경로 계산(ccp_alpha 시퀀스)교차검증 α에 대한 성능 추정최적 α 선택최종 트리 재학습(선택 α)평가/설명RMSE·규칙·중요도

전처리와 설명 가능성의 경계

회귀 트리는 스케일에 불변이므로 표준화가 필요하지 않다. 다만 결측치 분기 처리가 없는 구현에서는 전처리가 필수다. 이상치는 분할에 민감하게 작용할 수 있어 견고 추정 또는 클리핑 전처리를 고려한다.

모델은 불순도 감소 기반 특성 중요도를 제공하며, 규칙 경로를 보면 특성 간 상호작용도 드러난다. 이 특성은 규정 준수나 감사 대응에서 특히 유용하다. 대신 중요도와 경로를 해석할 때는 데이터 처리 과정과 분할 조건을 함께 확인해야 한다.

규칙 기반 의사결정이 필요한 장면

수요 예측과 재고 최적화에서는 프로모션, 요일, 시즌 요인을 분기 규칙으로 포착하고 단가·리드타임과의 상호작용을 반영할 수 있다. 가격 책정과 LTV 추정에서는 고객 등급 및 활동 지표의 임계값을 바탕으로 가격 티어를 만들고, 규칙 설명을 사업 의사결정에 연결한다.

신용·리스크 점수 보조 모델에서는 단순 규칙 기반 컷오프에 회귀 트리를 적용해 감사에 필요한 규칙 경로 근거를 제공할 수 있다. 용량 계획과 SLA 관리에서는 트래픽, 배치 창, 버전 릴리스와 지연시간의 관계를 규칙으로 모델링하고 이상 구간 식별 및 경고 임계 재설정에 활용한다.

무가지치기 대비 검증 RMSE는 520% 개선 가능하며, 이는 데이터 복잡도와 노이즈 수준에 의존한다. 모델 분산(리샘플 간 성능 표준편차)은 2040% 감소 추정된다. 규칙 기반 설명은 이해관계자 수용성을 높이고, 배포·모니터링을 간결하게 하며 운영 리스크를 완화한다.

가지치기 방식에 따른 운영 특성

구분 성능(일반화) 확장성(훈련/추론) 일관성(재현성) 안정성(노이즈 민감도) 운영 편의
무가지치기 초기 훈련 성능 우수, 검증 성능 불안정 깊이에 따라 급격히 저하 난수 시드·샘플 변화에 민감 과적합 및 이상치 민감 규칙 과다, 유지보수 부담
사전 가지치기 적절한 편향 증가로 평균적 개선 제어 용이, 훈련 속도 우수 하이퍼파라미터로 재현 용이 과소적합 위험 존재 설정 단순, 운영 친화
사후 가지치기(CCP) 교차검증 기반 최적화로 균형적 우수 경로 계산 오버헤드 소폭 존재 α로 결과 고정, 재현성 우수 분산 감소, 안정성 우수 규칙 수 제어 용이

비용-복잡도 경로를 적용하는 코드

전제조건: Python 3.10+, scikit-learn 1.3+, numpy/pandas 설치. 범주형 변수는 원-핫 인코딩 또는 타깃 누설 방지 인코딩 필요.

# python>=3.10, scikit-learn>=1.3
from sklearn.datasets import fetch_california_housing
from sklearn.model_selection import train_test_split, KFold, cross_val_score
from sklearn.tree import DecisionTreeRegressor
from sklearn.metrics import mean_squared_error
import numpy as np

# 1) 데이터 로드
X, y = fetch_california_housing(return_X_y=True, as_frame=True)
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42
)

# 2) 사전 가지치기 기본 트리(베이스라인)
prepruned = DecisionTreeRegressor(
    max_depth=8, min_samples_leaf=20, random_state=42
)
prepruned.fit(X_train, y_train)

# 3) 완전 트리로부터 비용-복잡도 경로 계산
full_tree = DecisionTreeRegressor(random_state=42)
path = full_tree.cost_complexity_pruning_path(X_train, y_train)
ccp_alphas = path.ccp_alphas

# 극단 α(리프 1개 유발) 제외
ccp_alphas = ccp_alphas[:-1]

# 4) 교차검증으로 최적 α 선택
cv = KFold(n_splits=5, shuffle=True, random_state=42)
mean_scores = []
for a in ccp_alphas:
    dt = DecisionTreeRegressor(random_state=42, ccp_alpha=a)
    # neg_mean_squared_error -> 값이 클수록 좋음
    scores = cross_val_score(dt, X_train, y_train, cv=cv,
                             scoring="neg_root_mean_squared_error")
    mean_scores.append(scores.mean())

best_alpha = ccp_alphas[int(np.argmax(mean_scores))]

# 5) 최종 트리 학습 및 평가
final_dt = DecisionTreeRegressor(random_state=42, ccp_alpha=best_alpha)
final_dt.fit(X_train, y_train)

def rmse(model, X, y):
    return mean_squared_error(y, model.predict(X), squared=False)

print("Pre-pruned RMSE (val-like):", -max(mean_scores))  # 참고치
print("Train RMSE:", rmse(final_dt, X_train, y_train))
print("Test  RMSE:", rmse(final_dt, X_test, y_test))

# 6) 간단한 설명 가능성 산출
importances = final_dt.feature_importances_
for name, imp in sorted(zip(X.columns, importances), key=lambda x: -x[1])[:5]:
    print(f"{name}: {imp:.3f}")

운영에서는 규칙 수(리프 수)를 모니터링하고 데이터 드리프트에 대비해 주기적 재학습을 스케줄링한다. 모델 카드에는 트리 깊이, 리프 수, ccp_alpha, 교차검증 분할 설정을 포함한다. 전처리 단계는 ColumnTransformer로 고정해 누설을 방지한다.

단순함과 표현력 사이의 선택

사전 가지치기와 사후 가지치기를 함께 쓸 수 있다. 적정 max_depthmin_samples_leaf로 노이즈를 먼저 제한하고, CCP로 최종 트리를 단순화하는 구성이다. α 선택의 분산은 반복 K-fold 또는 nested CV로 검증하며, 난수 시드 고정과 데이터 버전 관리를 병행한다. 이상치에는 클리핑 또는 윈저라이징을 적용하고, 고유값이 과도한 범주형 특성은 축소 처리한다.

얕은 트리는 설명하기 쉽지만 복잡한 패턴을 잃을 수 있다. 가지치기는 분산을 낮추는 대신 편향을 높일 수 있으며, 과도하게 적용하면 언더피팅으로 이어진다. CCP 경로 계산과 교차검증은 추가 계산 비용을 요구하지만 운영 안정성 향상과 맞바꿀 수 있다.

CART회귀 트리가지치기머신러닝교차검증