본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.
본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.
이미지 로딩 중...
AI Generated
2025. 12. 4. · 11 Views
결정 트리와 앙상블 완벽 가이드
머신러닝의 핵심 알고리즘인 결정 트리부터 랜덤 포레스트, XGBoost까지 앙상블 기법을 체계적으로 학습합니다. 초급 개발자도 쉽게 이해할 수 있도록 실무 예제와 함께 설명합니다.
목차
1. 결정 트리 알고리즘 원리
어느 날 김개발 씨는 회사에서 고객 이탈 예측 모델을 만들라는 업무를 받았습니다. 데이터는 있는데, 어떤 알고리즘을 써야 할지 막막했습니다.
선배 박시니어 씨가 다가와 말했습니다. "일단 결정 트리부터 시작해봐.
가장 직관적이거든."
결정 트리는 한마디로 스무고개 게임과 같습니다. "예" 또는 "아니오"로 대답할 수 있는 질문을 연속으로 던져서 최종 결론에 도달하는 방식입니다.
마치 의사가 환자를 진단할 때 증상을 하나씩 물어보는 것처럼, 데이터의 특성을 기준으로 분류해 나갑니다.
다음 코드를 살펴봅시다.
from sklearn.tree import DecisionTreeClassifier
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
# 붓꽃 데이터 로드
iris = load_iris()
X_train, X_test, y_train, y_test = train_test_split(
iris.data, iris.target, test_size=0.2, random_state=42
)
# 결정 트리 모델 생성 및 학습
tree_model = DecisionTreeClassifier(max_depth=3, random_state=42)
tree_model.fit(X_train, y_train)
# 예측 및 정확도 확인
accuracy = tree_model.score(X_test, y_test)
print(f"정확도: {accuracy:.2f}")
김개발 씨는 입사 6개월 차 주니어 데이터 분석가입니다. 오늘 팀장님으로부터 중요한 업무를 받았습니다.
최근 고객 이탈률이 높아지고 있으니, 어떤 고객이 이탈할 가능성이 높은지 예측하는 모델을 만들어 달라는 것이었습니다. 김개발 씨는 머신러닝 책을 펼쳐 들었지만, 수많은 알고리즘 중에서 무엇을 선택해야 할지 막막했습니다.
그때 옆자리의 박시니어 씨가 슬쩍 화면을 들여다보았습니다. "처음이라면 결정 트리부터 시작하는 게 좋아.
결과를 해석하기 쉽거든." 그렇다면 결정 트리란 정확히 무엇일까요? 쉽게 비유하자면, 결정 트리는 마치 스무고개 게임과 같습니다.
"이 동물은 다리가 4개인가요?" "예." "털이 있나요?" "예." "멍멍 짖나요?" "예." "그럼 개군요!" 이처럼 예/아니오로 대답할 수 있는 질문을 연속으로 던져서 최종 답에 도달합니다. 결정 트리도 마찬가지입니다.
데이터의 **특성(feature)**을 기준으로 질문을 던지고, 그 답에 따라 가지를 뻗어나갑니다. 예를 들어 고객 이탈 예측에서는 "월 사용 금액이 5만원 미만인가?"라는 질문을 먼저 던질 수 있습니다.
그런데 어떤 질문을 먼저 던져야 할까요? 바로 여기서 **정보 이득(Information Gain)**이라는 개념이 등장합니다.
정보 이득은 특정 질문이 얼마나 데이터를 잘 나누는지를 수치로 표현한 것입니다. 좋은 질문은 한 번에 데이터를 명확하게 두 그룹으로 나눕니다.
마치 도서관에서 책을 찾을 때 "소설인가요?"라는 질문이 "빨간색 표지인가요?"보다 훨씬 유용한 것과 같습니다. 위의 코드를 살펴보겠습니다.
먼저 DecisionTreeClassifier를 생성할 때 max_depth=3이라는 파라미터가 보입니다. 이것은 트리의 최대 깊이를 3단계로 제한한다는 의미입니다.
왜 제한할까요? 제한 없이 트리를 키우면 학습 데이터에 너무 딱 맞춰버리는 과적합(overfitting) 문제가 생깁니다.
마치 시험 문제만 달달 외워서 똑같은 문제는 맞추지만, 조금만 변형되면 틀리는 것과 같습니다. 실제 현업에서 결정 트리는 어떻게 활용할까요?
은행에서 대출 심사를 할 때 결정 트리를 많이 사용합니다. "연소득이 얼마 이상인가?", "신용등급이 몇 등급인가?" 같은 질문으로 대출 승인 여부를 결정하는 것입니다.
결과를 설명하기 쉬워서 규제가 까다로운 금융권에서 특히 선호합니다. 박시니어 씨의 설명을 들은 김개발 씨는 고개를 끄덕였습니다.
"아, 그래서 결정 트리가 화이트박스 모델이라고 불리는 거군요!"
실전 팁
💡 - max_depth를 너무 크게 설정하면 과적합이 발생하니 교차검증으로 적절한 값을 찾으세요
- feature_importances_ 속성으로 어떤 특성이 중요한지 확인할 수 있습니다
2. 결정 트리의 장단점
김개발 씨가 결정 트리 모델을 완성하고 팀장님께 보고하러 갔습니다. 팀장님은 모델을 살펴보더니 물었습니다.
"이 모델의 한계는 뭐야? 왜 더 복잡한 모델을 안 썼어?" 김개발 씨는 잠시 말문이 막혔습니다.
결정 트리는 해석이 쉽고 데이터 전처리가 거의 필요 없다는 큰 장점이 있습니다. 하지만 데이터가 조금만 바뀌어도 트리 구조가 크게 달라지는 불안정성이 있고, 단일 트리로는 복잡한 패턴을 잡기 어렵습니다.
이런 단점을 극복하기 위해 앙상블 기법이 등장했습니다.
다음 코드를 살펴봅시다.
from sklearn.tree import DecisionTreeClassifier, plot_tree
import matplotlib.pyplot as plt
# 결정 트리 시각화
tree_model = DecisionTreeClassifier(max_depth=3, random_state=42)
tree_model.fit(X_train, y_train)
# 트리 구조 시각화
plt.figure(figsize=(15, 10))
plot_tree(tree_model, feature_names=iris.feature_names,
class_names=iris.target_names, filled=True, rounded=True)
plt.title("결정 트리 시각화")
plt.show()
# 특성 중요도 확인
for name, importance in zip(iris.feature_names, tree_model.feature_importances_):
print(f"{name}: {importance:.3f}")
팀장님의 질문에 김개발 씨는 당황했습니다. 분명 모델이 잘 작동하는 것 같은데, 왜 더 복잡한 모델을 쓰지 않았냐고 물으시는 걸까요?
박시니어 씨가 나서서 설명했습니다. "팀장님, 결정 트리는 장단점이 분명한 알고리즘입니다.
상황에 따라 적합한 선택이 될 수도 있고, 아닐 수도 있습니다." 먼저 결정 트리의 장점부터 살펴봅시다. 첫째, 해석이 매우 쉽습니다.
트리 구조를 그림으로 그릴 수 있고, "왜 이런 예측을 했는지"를 명확하게 설명할 수 있습니다. 마치 의사가 환자에게 진단 과정을 설명하듯이 말입니다.
이것이 바로 결정 트리가 금융, 의료 분야에서 사랑받는 이유입니다. 둘째, 데이터 전처리가 거의 필요 없습니다.
스케일링을 하지 않아도 되고, 범주형 변수도 자연스럽게 처리합니다. 다른 알고리즘들은 데이터를 정규화하고, 원핫인코딩하고, 결측치를 처리하느라 시간이 많이 드는데, 결정 트리는 그런 수고가 덜합니다.
셋째, 비선형 관계도 잡아냅니다. 선형 회귀는 직선으로만 데이터를 나누지만, 결정 트리는 계단식으로 복잡한 경계를 만들 수 있습니다.
하지만 단점도 분명히 존재합니다. 가장 큰 문제는 불안정성입니다.
데이터가 조금만 바뀌어도 트리 구조가 완전히 달라질 수 있습니다. 마치 돌탑을 쌓을 때 아래쪽 돌 하나를 빼면 전체가 무너지는 것과 같습니다.
루트 노드의 분기 조건이 바뀌면 그 아래 모든 구조가 영향을 받습니다. 둘째, 과적합에 취약합니다.
제한 없이 트리를 키우면 학습 데이터의 노이즈까지 완벽하게 학습해버립니다. 시험 문제를 달달 외우는 학생처럼, 새로운 데이터에는 약한 모델이 됩니다.
셋째, 예측 성능의 한계가 있습니다. 단일 결정 트리는 아무리 튜닝해도 복잡한 패턴을 잡는 데 한계가 있습니다.
현실 세계의 데이터는 너무나 복잡하기 때문입니다. 팀장님이 고개를 끄덕였습니다.
"그래서 앙상블을 쓰는 거지?" 박시니어 씨가 미소 지었습니다. "네, 맞습니다.
결정 트리 하나의 한계를 극복하기 위해 여러 개의 트리를 조합하는 앙상블 기법이 등장했습니다." 김개발 씨는 노트에 열심히 받아 적었습니다. 결정 트리의 장단점을 정확히 이해해야 언제 쓰고 언제 쓰지 말아야 할지 판단할 수 있기 때문입니다.
실전 팁
💡 - 모델 해석이 중요한 상황에서는 결정 트리를 우선 고려하세요
- 성능이 중요하다면 결정 트리는 베이스라인으로 삼고 앙상블로 발전시키세요
3. 앙상블 기법 개요
김개발 씨는 결정 트리의 한계를 깨닫고 더 좋은 방법을 찾기 시작했습니다. 박시니어 씨가 조언했습니다.
"혼자서 모든 걸 잘하는 사람은 없어. 하지만 여러 사람이 모이면 놀라운 일이 일어나지.
모델도 마찬가지야."
**앙상블(Ensemble)**은 여러 개의 모델을 조합하여 더 강력한 예측 모델을 만드는 기법입니다. 마치 여러 전문가의 의견을 종합하여 더 나은 결정을 내리는 것과 같습니다.
단일 모델의 약점을 서로 보완하여 분산을 줄이고 예측 성능을 높입니다.
다음 코드를 살펴봅시다.
from sklearn.ensemble import VotingClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.svm import SVC
# 세 가지 다른 모델 생성
tree = DecisionTreeClassifier(max_depth=4, random_state=42)
logistic = LogisticRegression(max_iter=1000, random_state=42)
svm = SVC(probability=True, random_state=42)
# 투표 기반 앙상블 (Voting Ensemble)
voting_clf = VotingClassifier(
estimators=[('tree', tree), ('logistic', logistic), ('svm', svm)],
voting='soft' # 확률 기반 투표
)
voting_clf.fit(X_train, y_train)
print(f"앙상블 정확도: {voting_clf.score(X_test, y_test):.2f}")
박시니어 씨는 커피를 한 모금 마시고 설명을 이어갔습니다. "김개발 씨, 퀴즈 프로그램을 본 적 있어?
'청중 찬스'라는 게 있잖아. 어려운 문제가 나오면 관객들에게 투표를 받아서 가장 많은 표를 얻은 답을 선택하는 거야." 김개발 씨가 고개를 끄덕였습니다.
"아, 집단지성 같은 건가요?" "바로 그거야! **앙상블(Ensemble)**이 정확히 그런 원리야.
한 명의 천재보다 평범한 사람 100명의 평균이 더 정확할 때가 많거든." 앙상블의 핵심 아이디어는 간단합니다. 여러 개의 모델이 각자 예측을 하고, 그 결과를 종합하는 것입니다.
개별 모델이 완벽하지 않더라도, 서로 다른 방식으로 틀리기 때문에 종합하면 오류가 상쇄됩니다. 이것을 수학적으로는 분산 감소라고 표현합니다.
단일 모델은 데이터에 따라 예측이 크게 흔들릴 수 있지만, 여러 모델의 평균은 훨씬 안정적입니다. 앙상블에는 크게 세 가지 전략이 있습니다.
첫째, **배깅(Bagging)**입니다. 같은 알고리즘으로 여러 모델을 만들되, 각 모델이 서로 다른 데이터 샘플로 학습합니다.
마치 같은 시험을 여러 번 보는데, 매번 다른 문제 세트로 보는 것과 같습니다. 둘째, **부스팅(Boosting)**입니다.
모델을 순차적으로 학습시키는데, 이전 모델이 틀린 부분에 집중해서 다음 모델을 학습시킵니다. 마치 오답노트를 만들어서 틀린 문제만 집중적으로 공부하는 것과 같습니다.
셋째, **스태킹(Stacking)**입니다. 여러 다른 종류의 모델을 사용하고, 그 예측 결과를 새로운 모델의 입력으로 사용합니다.
마치 여러 전문가의 의견을 종합해서 최종 결정을 내리는 위원회와 같습니다. 위의 코드에서 VotingClassifier는 가장 간단한 형태의 앙상블입니다.
결정 트리, 로지스틱 회귀, SVM이라는 세 가지 서로 다른 모델이 각자 예측을 하고, 그 결과를 투표로 종합합니다. voting='soft'는 단순히 다수결을 하는 것이 아니라, 각 모델이 예측한 확률을 평균내어 최종 결정을 한다는 의미입니다.
확신이 높은 모델의 의견이 더 반영되는 셈입니다. 김개발 씨가 질문했습니다.
"그럼 어떤 앙상블 기법을 써야 하나요?" 박시니어 씨가 대답했습니다. "상황에 따라 다르지.
배깅과 부스팅에 대해 더 자세히 알아보면 판단할 수 있을 거야."
실전 팁
💡 - 서로 다른 종류의 모델을 조합하면 앙상블 효과가 더 좋습니다
- voting='soft'가 voting='hard'보다 대체로 성능이 좋습니다
4. 배깅과 부스팅
김개발 씨는 앙상블의 두 가지 주요 전략인 배깅과 부스팅에 대해 궁금해졌습니다. 박시니어 씨가 화이트보드에 그림을 그리며 설명하기 시작했습니다.
"이 둘은 접근 방식이 완전히 다르거든. 한번 비교해볼까?"
**배깅(Bagging)**은 데이터를 랜덤하게 샘플링하여 여러 모델을 병렬로 학습시키고 평균을 냅니다. **부스팅(Boosting)**은 이전 모델의 오류에 집중하여 순차적으로 모델을 개선해 나갑니다.
배깅은 분산을 줄이고, 부스팅은 편향을 줄이는 데 효과적입니다.
다음 코드를 살펴봅시다.
from sklearn.ensemble import BaggingClassifier, AdaBoostClassifier
from sklearn.tree import DecisionTreeClassifier
# 배깅: 여러 트리를 병렬로 학습 (분산 감소)
bagging = BaggingClassifier(
estimator=DecisionTreeClassifier(max_depth=4),
n_estimators=50, # 50개의 트리
max_samples=0.8, # 각 트리는 80% 샘플 사용
bootstrap=True, # 복원 추출
random_state=42
)
# 부스팅: 틀린 샘플에 가중치 부여 (편향 감소)
boosting = AdaBoostClassifier(
estimator=DecisionTreeClassifier(max_depth=2),
n_estimators=50,
learning_rate=0.5, # 각 트리의 기여도
random_state=42
)
bagging.fit(X_train, y_train)
boosting.fit(X_train, y_train)
print(f"배깅 정확도: {bagging.score(X_test, y_test):.2f}")
print(f"부스팅 정확도: {boosting.score(X_test, y_test):.2f}")
박시니어 씨가 화이트보드 앞에 섰습니다. "배깅과 부스팅, 이름은 비슷한데 철학이 완전히 달라." 먼저 **배깅(Bagging, Bootstrap Aggregating)**부터 설명하겠습니다.
배깅은 마치 여론조사와 같습니다. 전국민에게 물어볼 수 없으니, 무작위로 1000명을 뽑아서 조사합니다.
그리고 이 과정을 여러 번 반복해서 결과를 평균 냅니다. 배깅도 마찬가지입니다.
전체 데이터에서 **복원 추출(bootstrap)**로 여러 개의 샘플을 만들고, 각 샘플로 모델을 학습시킵니다. 복원 추출이란 한 번 뽑은 데이터를 다시 넣어서 또 뽑을 수 있다는 의미입니다.
그래서 각 샘플은 원본 데이터와 비슷하지만 조금씩 다릅니다. 핵심은 병렬 처리입니다.
50개의 모델이 서로 독립적으로, 동시에 학습할 수 있습니다. 그래서 학습 속도가 빠릅니다.
배깅의 장점은 분산을 줄이는 것입니다. 하나의 모델은 데이터에 따라 예측이 크게 흔들릴 수 있지만, 50개 모델의 평균은 훨씬 안정적입니다.
이제 **부스팅(Boosting)**을 살펴봅시다. 부스팅은 마치 오답노트 공부법과 같습니다.
첫 번째 시험을 보고, 틀린 문제를 오답노트에 적습니다. 두 번째 시험 준비할 때는 오답노트에 있는 문제에 집중합니다.
세 번째, 네 번째도 마찬가지입니다. 점점 약점이 보완됩니다.
부스팅도 이와 같습니다. 첫 번째 모델이 예측을 하고, 틀린 샘플에 더 높은 가중치를 부여합니다.
두 번째 모델은 이 가중치를 반영해서 학습하므로, 첫 번째 모델이 틀린 부분에 더 집중합니다. 핵심은 순차 처리입니다.
이전 모델의 결과를 알아야 다음 모델을 학습할 수 있으므로, 병렬 처리가 불가능합니다. 그래서 배깅보다 학습 속도가 느립니다.
부스팅의 장점은 편향을 줄이는 것입니다. 단순한 모델(얕은 트리)을 사용하더라도, 순차적으로 보완하면서 복잡한 패턴을 학습할 수 있습니다.
코드에서 AdaBoostClassifier는 가장 기본적인 부스팅 알고리즘입니다. learning_rate는 각 트리가 최종 예측에 기여하는 정도를 조절합니다.
너무 크면 과적합, 너무 작으면 학습이 느려집니다. 김개발 씨가 정리했습니다.
"그러니까 배깅은 분산을 줄이고, 부스팅은 편향을 줄인다는 거죠?" 박시니어 씨가 미소 지었습니다. "정확해!
그래서 상황에 따라 선택해야 해. 모델이 불안정하면 배깅, 모델이 너무 단순하면 부스팅이 좋아."
실전 팁
💡 - 과적합이 걱정되면 배깅을, 과소적합이 걱정되면 부스팅을 선택하세요
- 부스팅의 learning_rate는 n_estimators와 함께 조절해야 합니다
5. 랜덤 포레스트 알고리즘
김개발 씨는 배깅의 대표적인 알고리즘인 랜덤 포레스트에 대해 알고 싶어졌습니다. 박시니어 씨가 말했습니다.
"랜덤 포레스트는 내가 실무에서 가장 많이 쓰는 알고리즘이야. 성능도 좋고, 튜닝도 쉽거든."
**랜덤 포레스트(Random Forest)**는 배깅에 특성 무작위 선택을 추가한 알고리즘입니다. 여러 개의 결정 트리를 만들되, 각 트리가 서로 다른 데이터와 서로 다른 특성을 사용하도록 강제합니다.
이렇게 하면 트리들 사이의 상관관계가 낮아져서 앙상블 효과가 극대화됩니다.
다음 코드를 살펴봅시다.
from sklearn.ensemble import RandomForestClassifier
import numpy as np
# 랜덤 포레스트 모델 생성
rf_model = RandomForestClassifier(
n_estimators=100, # 100개의 트리
max_depth=5, # 각 트리의 최대 깊이
max_features='sqrt', # 각 분기에서 고려할 특성 수
min_samples_split=5, # 분기에 필요한 최소 샘플 수
random_state=42,
n_jobs=-1 # 모든 CPU 코어 사용
)
rf_model.fit(X_train, y_train)
print(f"랜덤 포레스트 정확도: {rf_model.score(X_test, y_test):.2f}")
# 특성 중요도 확인
for name, importance in zip(iris.feature_names, rf_model.feature_importances_):
print(f"{name}: {importance:.3f}")
박시니어 씨가 자신의 노트북을 열었습니다. "내가 실무에서 새로운 문제를 만나면 거의 항상 랜덤 포레스트부터 시작해.
왜 그런지 설명해줄게." 랜덤 포레스트는 이름 그대로 **무작위(Random)로 만든 여러 개의 결정 트리(Forest)**입니다. 그런데 단순히 배깅을 결정 트리에 적용한 것 이상의 아이디어가 있습니다.
일반 배깅은 데이터를 무작위로 샘플링합니다. 랜덤 포레스트는 여기에 더해 특성(feature)도 무작위로 선택합니다.
예를 들어 10개의 특성이 있다면, 각 트리의 각 분기점에서 10개를 다 보는 것이 아니라, 무작위로 3개만 보고 그중에서 최선의 분기를 선택합니다. max_features='sqrt'는 특성 개수의 제곱근만큼만 고려하겠다는 의미입니다.
왜 이렇게 할까요? 트리들 사이의 다양성을 높이기 위해서입니다.
만약 특성 하나가 압도적으로 중요하다면, 모든 트리가 비슷한 구조를 가지게 됩니다. 그러면 100개의 트리가 있어도 사실상 하나의 트리와 다름없습니다.
하지만 특성을 무작위로 제한하면, 각 트리가 서로 다른 관점에서 데이터를 바라보게 됩니다. 이것은 마치 여러 전문가가 각자의 전문 분야에서 의견을 내는 것과 같습니다.
금융 전문가, 기술 전문가, 마케팅 전문가가 각자의 시각으로 분석하고, 그 의견을 종합하면 더 풍부한 결론을 얻을 수 있습니다. 코드에서 주목할 파라미터들을 살펴보겠습니다.
n_estimators=100은 트리의 개수입니다. 일반적으로 많을수록 좋지만, 어느 시점 이후로는 성능 향상이 미미해집니다.
100에서 500 사이가 보통 적당합니다. max_depth=5는 각 트리의 깊이를 제한합니다.
랜덤 포레스트는 과적합에 강하지만, 그래도 적절한 깊이 제한은 도움이 됩니다. n_jobs=-1은 모든 CPU 코어를 사용하겠다는 의미입니다.
배깅 기반이므로 병렬 처리가 가능합니다. 이것이 랜덤 포레스트의 큰 장점입니다.
feature_importances_는 매우 유용한 속성입니다. 어떤 특성이 예측에 얼마나 중요한지 알 수 있습니다.
이 정보를 바탕으로 불필요한 특성을 제거하거나, 중요한 특성을 더 정교하게 다듬을 수 있습니다. 김개발 씨가 물었습니다.
"그럼 랜덤 포레스트만 쓰면 되는 거 아닌가요?" 박시니어 씨가 고개를 저었습니다. "아니, 더 강력한 녀석이 있어.
바로 XGBoost야. 캐글 대회에서 가장 많이 우승한 알고리즘이지."
실전 팁
💡 - n_estimators는 100부터 시작해서 성능 변화를 관찰하며 늘려가세요
- feature_importances_로 특성 중요도를 파악하고 특성 엔지니어링에 활용하세요
6. XGBoost 그라디언트 부스팅
캐글 대회 이야기가 나오자 김개발 씨의 눈이 반짝였습니다. "XGBoost요?
그거 대회에서 엄청 많이 쓰인다고 들었어요!" 박시니어 씨가 고개를 끄덕였습니다. "맞아.
정형 데이터에서는 거의 무적이야."
**XGBoost(eXtreme Gradient Boosting)**는 그라디언트 부스팅을 극도로 최적화한 알고리즘입니다. 정규화를 통해 과적합을 방지하고, 병렬 처리로 속도를 높였습니다.
결측치 처리, 가지치기, 캐싱 등 다양한 최적화 기법이 적용되어 정형 데이터에서 최고 수준의 성능을 보여줍니다.
다음 코드를 살펴봅시다.
from xgboost import XGBClassifier
from sklearn.metrics import classification_report
# XGBoost 모델 생성
xgb_model = XGBClassifier(
n_estimators=100, # 부스팅 라운드 수
max_depth=4, # 트리 깊이
learning_rate=0.1, # 학습률 (작을수록 정교)
subsample=0.8, # 각 트리에 사용할 샘플 비율
colsample_bytree=0.8, # 각 트리에 사용할 특성 비율
reg_alpha=0.1, # L1 정규화
reg_lambda=1.0, # L2 정규화
random_state=42,
use_label_encoder=False,
eval_metric='mlogloss'
)
xgb_model.fit(X_train, y_train)
y_pred = xgb_model.predict(X_test)
print(f"XGBoost 정확도: {xgb_model.score(X_test, y_test):.2f}")
박시니어 씨가 진지한 표정으로 말했습니다. "XGBoost는 2014년에 등장해서 머신러닝 대회 판도를 완전히 바꿔놓았어.
캐글에서 수많은 대회를 휩쓸었지." **그라디언트 부스팅(Gradient Boosting)**은 부스팅의 발전된 형태입니다. AdaBoost가 틀린 샘플에 가중치를 주는 방식이라면, 그라디언트 부스팅은 **잔차(residual)**를 직접 학습합니다.
잔차란 실제 값과 예측 값의 차이입니다. 첫 번째 모델이 예측을 하면, 두 번째 모델은 그 오차를 예측합니다.
세 번째 모델은 남은 오차를 예측합니다. 이렇게 점점 오차를 줄여나갑니다.
XGBoost는 이 그라디언트 부스팅을 극한까지 최적화한 것입니다. 첫째, **정규화(Regularization)**가 내장되어 있습니다.
reg_alpha는 L1 정규화, reg_lambda는 L2 정규화입니다. 이것이 과적합을 방지합니다.
AdaBoost나 기본 그라디언트 부스팅은 정규화가 없어서 과적합에 취약했습니다. 둘째, 병렬 처리가 가능합니다.
부스팅은 순차적이라 병렬화가 어렵다고 했는데, XGBoost는 트리 내부의 분기점 탐색을 병렬화했습니다. 그래서 속도가 매우 빠릅니다.
셋째, 결측치를 자동으로 처리합니다. 데이터에 빈 값이 있어도 별도의 전처리 없이 학습할 수 있습니다.
XGBoost는 결측치를 왼쪽 또는 오른쪽 분기 중 더 좋은 쪽으로 자동 배치합니다. 코드의 주요 파라미터를 살펴보겠습니다.
learning_rate=0.1은 각 트리가 최종 예측에 기여하는 정도입니다. 작을수록 더 많은 트리가 필요하지만, 더 정교한 학습이 가능합니다.
보통 0.01에서 0.3 사이를 사용합니다. subsample=0.8과 colsample_bytree=0.8은 각각 행과 열을 무작위로 샘플링하는 비율입니다.
랜덤 포레스트처럼 다양성을 높여 과적합을 방지합니다. max_depth=4는 트리 깊이입니다.
XGBoost는 기본값이 6인데, 보통 3에서 10 사이가 적당합니다. 너무 깊으면 과적합, 너무 얕으면 과소적합입니다.
김개발 씨가 감탄했습니다. "와, 정말 많은 최적화가 들어가 있네요!" 박시니어 씨가 덧붙였습니다.
"LightGBM이나 CatBoost도 비슷한 원리야. 요즘은 이 셋을 GBDT 삼대장이라고 부르지.
정형 데이터에서는 딥러닝보다 이 녀석들이 더 강력할 때가 많아."
실전 팁
💡 - learning_rate를 낮추면 n_estimators를 높여야 합니다 (보통 반비례 관계)
- early_stopping_rounds를 사용하면 최적의 n_estimators를 자동으로 찾을 수 있습니다
7. 앙상블 모델 활용
김개발 씨는 이제 다양한 앙상블 기법을 배웠습니다. 하지만 실제 프로젝트에서 어떻게 적용해야 할지 막막했습니다.
박시니어 씨가 웃으며 말했습니다. "이론은 충분해.
이제 실전이야. 내가 실무에서 쓰는 워크플로우를 알려줄게."
실무에서 앙상블 모델을 활용할 때는 교차검증, 하이퍼파라미터 튜닝, 모델 비교가 핵심입니다. 여러 모델을 체계적으로 비교하고, 최적의 파라미터를 찾아 최종 모델을 선정합니다.
경우에 따라 여러 모델을 조합한 스태킹도 효과적입니다.
다음 코드를 살펴봅시다.
from sklearn.model_selection import cross_val_score, GridSearchCV
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
# 여러 모델 비교
models = {
'Random Forest': RandomForestClassifier(n_estimators=100, random_state=42),
'Gradient Boosting': GradientBoostingClassifier(n_estimators=100, random_state=42)
}
# 교차검증으로 모델 비교
for name, model in models.items():
scores = cross_val_score(model, X_train, y_train, cv=5, scoring='accuracy')
print(f"{name}: {scores.mean():.3f} (+/- {scores.std()*2:.3f})")
# GridSearchCV로 최적 파라미터 탐색
param_grid = {
'n_estimators': [50, 100, 200],
'max_depth': [3, 5, 7],
'learning_rate': [0.01, 0.1, 0.3]
}
grid_search = GridSearchCV(
GradientBoostingClassifier(random_state=42),
param_grid, cv=5, scoring='accuracy', n_jobs=-1
)
grid_search.fit(X_train, y_train)
print(f"최적 파라미터: {grid_search.best_params_}")
박시니어 씨가 화이트보드에 워크플로우를 그렸습니다. "실무에서 앙상블 모델을 쓸 때는 이 순서를 따라가면 돼." 첫째, 베이스라인부터 만들어라. 아무리 복잡한 문제도 단순한 모델부터 시작합니다.
로지스틱 회귀나 단일 결정 트리로 베이스라인을 잡습니다. 이 베이스라인보다 나아지지 않으면, 복잡한 모델을 쓸 이유가 없습니다.
둘째, 교차검증을 반드시 사용해라. cross_val_score는 데이터를 5등분해서, 4개로 학습하고 1개로 검증하는 과정을 5번 반복합니다. 이렇게 하면 운이 좋아서 성능이 좋게 나온 건지, 진짜 좋은 건지 알 수 있습니다.
코드에서 scores.mean() 뿐만 아니라 scores.std()도 출력하는 이유가 여기 있습니다. 평균이 높아도 표준편차가 크면 불안정한 모델입니다.
셋째, 하이퍼파라미터 튜닝을 해라. GridSearchCV는 지정한 파라미터 조합을 모두 시도해서 최적의 조합을 찾습니다. 위 코드에서는 3 x 3 x 3 = 27가지 조합을 시도합니다.
단, 조합이 너무 많으면 시간이 오래 걸립니다. 그럴 때는 RandomizedSearchCV를 사용해서 무작위로 일부 조합만 탐색할 수 있습니다.
넷째, 여러 모델을 비교해라. 랜덤 포레스트가 항상 최고인 것은 아닙니다. 데이터 특성에 따라 XGBoost가 더 좋을 수도 있고, 단순한 로지스틱 회귀가 충분할 수도 있습니다.
항상 여러 모델을 비교해보세요. 다섯째, 필요하면 스태킹을 고려해라. 여러 모델의 예측을 새로운 특성으로 사용해서 메타 모델을 학습시키는 것이 **스태킹(Stacking)**입니다.
잘 하면 성능이 올라가지만, 복잡도가 높아지므로 꼭 필요할 때만 사용합니다. 김개발 씨가 열심히 받아 적었습니다.
"결국 체계적인 실험이 중요하다는 거죠?" 박시니어 씨가 고개를 끄덕였습니다. "맞아.
감으로 하면 안 돼. 숫자로 비교하고, 근거를 가지고 결정해야 해.
그게 데이터 사이언티스트와 코더의 차이야." 김개발 씨는 오늘 배운 내용을 정리하며 뿌듯한 미소를 지었습니다. 결정 트리부터 XGBoost까지, 앙상블의 세계는 넓고 깊었지만, 이제 그 첫걸음을 뗐습니다.
실전 팁
💡 - 항상 베이스라인 모델부터 시작하고, 점진적으로 복잡도를 높이세요
- GridSearchCV 대신 Optuna 같은 라이브러리를 사용하면 더 효율적인 탐색이 가능합니다
이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!
댓글 (0)
함께 보면 좋은 카드 뉴스
Helm 마이크로서비스 패키징 완벽 가이드
Kubernetes 환경에서 마이크로서비스를 효율적으로 패키징하고 배포하는 Helm의 핵심 기능을 실무 중심으로 학습합니다. Chart 생성부터 릴리스 관리까지 체계적으로 다룹니다.
보안 아키텍처 구성 완벽 가이드
프로젝트의 보안을 처음부터 설계하는 방법을 배웁니다. AWS 환경에서 VPC부터 WAF, 암호화, 접근 제어까지 실무에서 바로 적용할 수 있는 보안 아키텍처를 단계별로 구성해봅니다.
AWS Organizations 완벽 가이드
여러 AWS 계정을 체계적으로 관리하고 통합 결제와 보안 정책을 적용하는 방법을 실무 스토리로 쉽게 배워봅니다. 초보 개발자도 바로 이해할 수 있는 친절한 설명과 실전 예제를 제공합니다.
AWS KMS 암호화 완벽 가이드
AWS KMS(Key Management Service)를 활용한 클라우드 데이터 암호화 방법을 초급 개발자를 위해 쉽게 설명합니다. CMK 생성부터 S3, EBS 암호화, 봉투 암호화까지 실무에 필요한 모든 내용을 담았습니다.
AWS Secrets Manager 완벽 가이드
AWS에서 데이터베이스 비밀번호, API 키 등 민감한 정보를 안전하게 관리하는 Secrets Manager의 핵심 개념과 실무 활용법을 배워봅니다. 초급 개발자도 쉽게 따라할 수 있도록 실전 예제와 함께 설명합니다.