의사결정나무: 앙상블의 기초
rpart로 의사결정나무를 만들고 시각화하며 편향-분산 상충 관계를 이해합니다.
의사결정나무: 앙상블의 기초은(는) CoddyKit의 무료 R Academy 강의입니다. 이것은 4개 중 1번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 R Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. R Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
의사결정 트리의 분할 방식
의사결정 트리는 특징 공간을 직사각형 영역으로 재귀적으로 나눕니다. 각 노드에서 알고리즘은 모든 특징과 가능한 모든 분할 지점을 검색해 목표 변수를 가장 잘 분리하는 분할을 찾습니다. 그 결과는 if-else 규칙으로 이루어진 트리가 됩니다.
library(rpart)
# Fit a classification tree
tree <- rpart(
Species ~ .,
data = iris,
method = 'class' # use 'anova' for regression
)
print(tree)GINI와 엔트로피 분할 기준
분할 기준은 노드의 불순도를 측정합니다. Gini 불순도는 무작위로 선택한 요소를 잘못 분류할 확률을 측정합니다. 엔트로피(정보 이득)는 정보의 무질서가 감소한 정도를 측정합니다. 두 기준은 대체로 비슷한 트리를 만들며, Gini가 계산이 더 빠르고 rpart의 기본값입니다.
# Default: Gini impurity (parms = list(split = 'gini'))
tree_gini <- rpart(Species ~ ., data = iris, method = 'class')
# Using information gain (entropy)
tree_entropy <- rpart(
Species ~ ., data = iris, method = 'class',
parms = list(split = 'information')
)
cat('Gini root split:', tree_gini$frame$var[1])
cat('Entropy root split:', tree_entropy$frame$var[1])printcp() — 복잡도 표
printcp(tree)는 복잡도 매개변수(CP) 표를 출력합니다. 각 행에는 트리 크기(분할 수), 학습 데이터에서의 상대 오차, 교차 검증 오차(xerror)가 표시됩니다. CP 표는 최적의 가지치기 수준을 찾는 데 사용됩니다.
tree <- rpart(medv ~ ., data = MASS::Boston, method = 'anova',
control = rpart.control(minsplit = 5, cp = 0.001))
printcp(tree)
# Identify the CP with minimum cross-validated error
best_cp <- tree$cptable[
which.min(tree$cptable[, 'xerror']),
'CP'
]
cat('Best CP:', best_cp)prune() — 트리 가지치기
prune(tree, cp)는 cp로 지정한 복잡도 수준에 맞게 트리를 가지치기합니다. 가지치기는 예측에 거의 기여하지 않는 가지를 축소하여 과적합을 방지합니다. 표준적인 방법은 CV 오차를 최소화하는 CP를 찾은 다음 가지치기하는 것입니다.
best_cp <- tree$cptable[
which.min(tree$cptable[, 'xerror']), 'CP'
]
pruned_tree <- prune(tree, cp = best_cp)
cat('Original tree nodes:', nrow(tree$frame))
cat('Pruned tree nodes:', nrow(pruned_tree$frame))rpart.plot() — 트리 시각화
rpart.plot 패키지의 rpart.plot(tree)는 결정 트리를 깔끔하고 색상이 적용된 형태로 시각화합니다. 각 내부 노드에는 분할 규칙이 표시되고, 각 리프에는 예측 클래스와 학습 표본의 비율이 표시됩니다.
library(rpart.plot)
tree <- rpart(Species ~ ., data = iris, method = 'class')
pruned <- prune(tree, cp = 0.02)
rpart.plot(
pruned,
type = 4, # split labels on branches
extra = 104, # show class + probability
fallen.leaves = TRUE
)편향-분산 상충
깊고 가지치기하지 않은 트리는 낮은 편향(학습 데이터에 거의 완벽하게 적합됨)을 가지지만, 높은 분산(데이터가 조금만 바뀌어도 매우 다른 트리가 생성됨)을 가집니다. 얕은 트리나 가지치기한 트리는 편향이 더 높지만 분산은 더 낮습니다. 최적의 트리는 이 두 가지 오차 원인 사이에서 균형을 이룹니다.
랜덤 포레스트나 부스팅과 같은 앙상블 방법은 이러한 상충 관계를 직접 해결합니다.
# Deep tree = low bias, high variance (overfits)
deep_tree <- rpart(medv ~ ., data = MASS::Boston,
control = rpart.control(minsplit = 2, cp = 0))
# Shallow tree = high bias, low variance (underfits)
shallow_tree <- rpart(medv ~ ., data = MASS::Boston,
control = rpart.control(maxdepth = 2))
cat('Deep nodes:', nrow(deep_tree$frame))
cat('Shallow nodes:', nrow(shallow_tree$frame))결정 트리의 과적합
가지치기하지 않은 트리는 모든 학습 예제를 암기하여 학습 오차를 0으로 만들 수 있습니다. 동일한 트리를 보지 못한 데이터에 평가하면 성능이 급격히 떨어집니다. 이는 지도 학습에서 과적합을 보여 주는 대표적인 예입니다.
set.seed(42)
train_idx <- sample(nrow(MASS::Boston), 400)
train_bos <- MASS::Boston[train_idx, ]
test_bos <- MASS::Boston[-train_idx, ]
# Fully grown tree
full <- rpart(medv ~ ., data = train_bos,
control = rpart.control(cp = 0, minsplit = 2))
train_pred <- predict(full, train_bos)
test_pred <- predict(full, test_bos)
cat('Train RMSE:', sqrt(mean((train_pred - train_bos$medv)^2)))
cat('Test RMSE:', sqrt(mean((test_pred - test_bos$medv)^2)))rpart의 변수 중요도
rpart는 각 예측 변수에 대해 variable.importance를 기록합니다. 이는 모든 분할에서 해당 변수가 기여한 분할 기준의 총 개선량입니다. 이를 통해 어떤 특성이 모델의 의사 결정을 주도하는지 빠르게 파악할 수 있습니다.
tree <- rpart(medv ~ ., data = MASS::Boston, method = 'anova')
# Variable importance (sorted)
imp <- sort(tree$variable.importance, decreasing = TRUE)
print(imp)
# Quick barplot
barplot(imp, las = 2, main = 'Variable Importance',
col = 'steelblue', cex.names = 0.8)트리에서 앙상블로
단일 결정 트리는 불안정합니다. 데이터를 다시 표본 추출하면 매우 다른 트리가 생성됩니다. 앙상블 방법은 이러한 불안정성을 활용합니다.
- 배깅 / 랜덤 포레스트: 부트스트랩 표본에서 많은 트리를 학습한 후 평균을 냅니다.
- 부스팅: 트리를 순차적으로 학습하며, 각 트리가 이전 트리의 오차를 보정하도록 합니다.
- 두 방법 모두 트리의 표현력을 유지하면서 분산을 줄입니다.
# Demonstrating instability of a single tree
set.seed(1); t1 <- rpart(medv ~ ., data = MASS::Boston[sample(506, 400), ])
set.seed(2); t2 <- rpart(medv ~ ., data = MASS::Boston[sample(506, 400), ])
# Root split may differ between trees
cat('Tree 1 root split:', t1$frame$var[1])
cat('Tree 2 root split:', t2$frame$var[1])rpart 제어 매개변수
rpart.control()은 트리가 성장하는 방식을 제어합니다. 주요 매개변수는 cp(복잡도 패널티), minsplit(분할을 시도하는 데 필요한 최소 관측값 수), minbucket(리프의 최소 크기), maxdepth입니다. 트리 기반 모델을 조정하려면 이러한 매개변수를 이해하는 것이 필수적입니다.
ctrl <- rpart.control(
cp = 0.005, # complexity penalty
minsplit = 20, # min obs to try a split
minbucket = 7, # min obs in any leaf
maxdepth = 10 # max tree depth
)
tree <- rpart(medv ~ ., data = MASS::Boston,
method = 'anova', control = ctrl)
printcp(tree)트리 성능 평가
가지치기한 후 분리해 둔 테스트 세트에서 트리를 평가합니다. 회귀에서는 RMSE와 R-squared를 계산하고, 분류에서는 정확도와 혼동 행렬을 계산합니다. 이러한 지표를 기준 모델과 비교하여 단일 트리가 제공하는 가치를 파악합니다.
pruned_tree <- prune(tree, cp = best_cp)
test_pred <- predict(pruned_tree, newdata = test_bos)
rmse <- sqrt(mean((test_pred - test_bos$medv)^2))
ss_res <- sum((test_pred - test_bos$medv)^2)
ss_tot <- sum((test_bos$medv - mean(test_bos$medv))^2)
r2 <- 1 - ss_res / ss_tot
cat('RMSE:', round(rmse, 3))
cat('R2:', round(r2, 3))빠른 확인
prune(tree, cp = best_cp)를 호출하는 목적을 가장 잘 설명하는 문장은 무엇입니까?
결정 트리 복습
앙상블의 기반인 결정 트리에서 기억할 핵심 내용:
- 트리는 특성 공간을 재귀적으로 분할하며, 분할에는 Gini 또는 엔트로피 기준을 사용합니다.
rpart(y ~ ., data, method)는 트리를 학습하고,printcp()는 복잡도 표를 표시합니다.- 교차 검증 오차가 최소인 CP를 찾은 다음
prune(tree, cp)를 사용합니다. rpart.plot()은 트리 구조를 시각화합니다.- 깊은 트리는 과적합됩니다(낮은 편향, 높은 분산). 얕은 트리는 과소적합됩니다.
tree$variable.importance는 총 분할 개선량을 기준으로 예측 변수의 순위를 매깁니다.- 앙상블 방법(랜덤 포레스트, 부스팅)은 단일 트리의 불안정성을 극복합니다.
# Standard rpart workflow
tree <- rpart(y ~ ., data = train, method = 'anova',
control = rpart.control(cp = 0.001))
best_cp <- tree$cptable[which.min(tree$cptable[, 'xerror']), 'CP']
pruned <- prune(tree, cp = best_cp)
test_pred <- predict(pruned, newdata = test)
rmse <- sqrt(mean((test_pred - test$y)^2))
cat('Pruned Tree RMSE:', rmse)자주 묻는 질문
“의사결정나무: 앙상블의 기초” 강의는 무료인가요?
네 — “의사결정나무: 앙상블의 기초” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 R Academy 강의 전체를 잠금 해제할 수 있습니다. R Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
“의사결정나무: 앙상블의 기초”에서 뭘 배우나요?
rpart로 의사결정나무를 만들고 시각화하며 편향-분산 상충 관계를 이해합니다. 브라우저에서 직접 실행하는 실습 코드로 R Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.
R Academy을(를) 시작하는 데 경험이 필요한가요?
사전 경험은 필요하지 않습니다. CoddyKit의 R Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 1번째 강의입니다.
“의사결정나무: 앙상블의 기초” 강의는 얼마나 걸리나요?
대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.
이 R Academy 강의에서 코드를 작성하고 실행할 수 있나요?
네. 모든 R Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.
이 강의의 모든 강의
- 의사결정나무: 앙상블의 기초
- ranger로 랜덤 포레스트 만들기
- xgboost를 활용한 그래디언트 부스팅
- 특성 중요도와 모델 해석