본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.
본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.
이미지 로딩 중...
AI Generated
2025. 12. 6. · 11 Views
Stacking 및 Voting Ensemble 완벽 가이드
여러 모델의 예측을 결합하여 더 강력한 예측 성능을 얻는 앙상블 기법인 Stacking과 Voting에 대해 알아봅니다. 초급 개발자도 쉽게 이해할 수 있도록 실무 예제와 함께 설명합니다.
목차
- 앙상블_학습의_기초
- Hard_Voting_다수결의_원칙
- Soft_Voting_확률의_평균
- Stacking의_개념
- Stacking_심화_다양한_구성
- 가중치_Voting
- 실전_프로젝트_적용
- Voting과_Stacking_비교_선택
1. 앙상블 학습의 기초
김개발 씨는 머신러닝 프로젝트를 진행하던 중 고민에 빠졌습니다. 랜덤 포레스트, SVM, 로지스틱 회귀 등 여러 모델을 만들어봤는데, 어떤 모델은 이 데이터에서 잘 맞고, 어떤 모델은 저 데이터에서 잘 맞습니다.
"하나만 선택해야 하나요?" 선배 박시니어 씨가 웃으며 답합니다. "굳이 하나만 쓸 필요 없어요.
다 합쳐보세요."
앙상블 학습은 여러 개의 모델을 결합하여 하나의 강력한 예측기를 만드는 기법입니다. 마치 중요한 결정을 내릴 때 여러 전문가의 의견을 종합하는 것과 같습니다.
한 명의 전문가보다 여러 전문가의 집단 지성이 더 정확한 판단을 내리는 원리를 활용합니다.
다음 코드를 살펴봅시다.
# 앙상블의 기본 원리: 여러 모델의 예측을 결합
from sklearn.ensemble import RandomForestClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.svm import SVC
import numpy as np
# 세 가지 다른 모델 생성
model1 = RandomForestClassifier(n_estimators=100)
model2 = LogisticRegression()
model3 = SVC(probability=True)
# 각 모델이 서로 다른 강점을 가짐
# RandomForest: 비선형 패턴에 강함
# LogisticRegression: 선형 관계 파악에 탁월
# SVC: 복잡한 경계 학습 가능
김개발 씨는 입사 6개월 차 데이터 사이언티스트입니다. 최근 고객 이탈 예측 모델을 만들라는 과제를 받았습니다.
열심히 여러 모델을 학습시켜봤지만, 어떤 모델도 만족스러운 성능을 보여주지 못했습니다. "랜덤 포레스트는 정확도가 85%인데, SVM은 82%네요.
로지스틱 회귀는 80%고요." 김개발 씨가 한숨을 쉬며 말했습니다. 옆자리의 박시니어 씨가 모니터를 힐끗 쳐다보더니 물었습니다.
"혹시 앙상블은 시도해봤어요?" 앙상블 학습이란 정확히 무엇일까요? 쉽게 비유하자면, 앙상블은 마치 퀴즈 대회에서 팀을 이루는 것과 같습니다.
역사에 강한 사람, 과학에 강한 사람, 예술에 강한 사람이 한 팀이 되면 어떤 문제가 나와도 누군가는 답을 알고 있습니다. 한 명의 천재보다 다양한 전문가들의 팀이 더 많은 문제를 맞출 수 있는 것처럼, 머신러닝에서도 여러 모델을 결합하면 개별 모델보다 더 좋은 성능을 얻을 수 있습니다.
왜 이런 현상이 일어날까요? 각 모델은 저마다 다른 방식으로 데이터를 바라봅니다.
랜덤 포레스트는 여러 결정 트리를 만들어 복잡한 비선형 패턴을 잡아냅니다. 로지스틱 회귀는 변수들 간의 선형 관계를 명확하게 파악합니다.
SVM은 데이터를 가장 잘 분리하는 경계면을 찾습니다. 문제는 현실 세계의 데이터가 이 모든 특성을 동시에 가지고 있다는 점입니다.
어떤 부분은 선형적이고, 어떤 부분은 비선형적입니다. 한 가지 모델만으로는 이 모든 패턴을 잡아내기 어렵습니다.
앙상블의 핵심 아이디어는 간단합니다. 각 모델이 잘하는 부분을 살리고, 못하는 부분은 다른 모델이 보완해주는 것입니다.
모델 A가 틀린 예측을 해도, 모델 B와 C가 맞추면 전체적으로는 정답을 얻을 수 있습니다. 실제로 머신러닝 경진대회인 Kaggle에서 상위권을 차지하는 솔루션들은 대부분 앙상블 기법을 사용합니다.
단일 모델로는 달성하기 어려운 성능을 앙상블로 끌어올리는 것이 일종의 정석이 되었습니다. 박시니어 씨의 설명을 들은 김개발 씨는 눈이 반짝였습니다.
"그러면 제가 만든 세 모델을 다 합치면 되는 건가요?" "맞아요. 그런데 어떻게 합치느냐에 따라 여러 가지 방법이 있어요.
가장 기본적인 건 Voting이고, 좀 더 정교한 건 Stacking이에요." 앙상블 학습의 세계로 들어가기 전에, 먼저 이 기본 개념을 확실히 이해해두면 앞으로의 내용이 훨씬 쉬워집니다.
실전 팁
💡 - 앙상블에 사용하는 모델들은 서로 다른 특성을 가진 것이 좋습니다
- 비슷한 모델을 여러 개 합치는 것보다 다양한 모델을 합치는 것이 효과적입니다
2. Hard Voting 다수결의 원칙
김개발 씨가 앙상블의 기본 개념을 이해하자, 박시니어 씨가 본격적인 설명을 시작했습니다. "가장 직관적인 방법부터 알아볼까요?
바로 투표예요." 김개발 씨가 고개를 갸웃거렸습니다. "투표요?
모델들이 투표를 한다고요?"
Hard Voting은 각 모델이 예측한 클래스 중 가장 많은 표를 받은 클래스를 최종 예측으로 선택하는 방식입니다. 마치 민주주의 선거에서 다수결로 결정하는 것과 같습니다.
세 모델 중 두 모델이 "고양이"라고 예측하면, 최종 답은 "고양이"가 됩니다.
다음 코드를 살펴봅시다.
from sklearn.ensemble import VotingClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.svm import SVC
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
# 샘플 데이터 생성
X, y = make_classification(n_samples=1000, n_features=20, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42)
# Hard Voting 앙상블 구성
voting_clf = VotingClassifier(
estimators=[
('rf', RandomForestClassifier(n_estimators=100)),
('lr', LogisticRegression()),
('svc', SVC())
],
voting='hard' # 다수결 투표
)
voting_clf.fit(X_train, y_train)
print(f"Hard Voting 정확도: {voting_clf.score(X_test, y_test):.4f}")
박시니어 씨가 화이트보드에 간단한 그림을 그리기 시작했습니다. "자, 여기 세 명의 의사가 있다고 생각해봐요.
환자가 왔는데, 의사 A는 감기라고 하고, 의사 B도 감기라고 하고, 의사 C는 독감이라고 해요. 어떤 진단을 믿을 거예요?" 김개발 씨가 답했습니다.
"두 명이 감기라고 했으니까 감기요?" "바로 그거예요. 그게 Hard Voting이에요." Hard Voting은 앙상블 기법 중 가장 직관적이고 이해하기 쉬운 방법입니다.
각 모델은 자신의 예측을 내놓고, 최종 결과는 단순히 표가 가장 많은 클래스가 됩니다. 이 방식의 장점은 명확합니다.
구현이 매우 간단하고, 결과를 해석하기도 쉽습니다. "세 모델 중 두 모델이 이 고객이 이탈할 것이라고 예측했습니다"라고 설명하면 누구나 이해할 수 있습니다.
위의 코드를 살펴보겠습니다. VotingClassifier를 사용하면 단 몇 줄의 코드로 Hard Voting을 구현할 수 있습니다.
estimators 파라미터에 사용할 모델들을 튜플 형태로 전달합니다. 각 튜플은 모델의 이름과 모델 객체로 구성됩니다.
voting='hard' 옵션이 핵심입니다. 이 옵션을 주면 각 모델의 예측 클래스만 보고 다수결로 결정합니다.
그런데 Hard Voting에는 한 가지 한계가 있습니다. 김개발 씨가 질문했습니다.
"그런데 만약 어떤 모델이 다른 모델보다 훨씬 성능이 좋으면요? 그래도 똑같이 한 표씩인가요?" 박시니어 씨가 고개를 끄덕였습니다.
"좋은 질문이에요. Hard Voting은 모든 모델을 동등하게 취급해요.
정확도가 90%인 모델이나 70%인 모델이나 똑같이 한 표예요." 이것이 Hard Voting의 한계입니다. 모델의 신뢰도나 확신의 정도를 전혀 고려하지 않습니다.
모델 A가 "99% 확신을 가지고 클래스 1"이라고 예측해도, 모델 B와 C가 "51% 확신으로 클래스 0"이라고 하면 클래스 0이 선택됩니다. 그럼에도 Hard Voting은 여전히 유용합니다.
특히 모델들의 성능이 비슷할 때, 또는 확률 예측을 지원하지 않는 모델을 사용할 때 좋은 선택입니다. 실무에서는 빠르게 베이스라인을 구축할 때 Hard Voting을 먼저 시도해보는 경우가 많습니다.
간단하면서도 꽤 좋은 성능 향상을 얻을 수 있기 때문입니다.
실전 팁
💡 - Hard Voting은 모든 모델의 성능이 비슷할 때 가장 효과적입니다
- 확률 출력을 지원하지 않는 모델도 Hard Voting에는 사용할 수 있습니다
3. Soft Voting 확률의 평균
"그럼 모델의 확신 정도를 반영하는 방법은 없나요?" 김개발 씨의 질문에 박시니어 씨가 미소를 지었습니다. "있죠.
Soft Voting이라는 게 있어요. 이건 각 모델이 얼마나 확신하는지까지 고려해요."
Soft Voting은 각 모델이 출력하는 확률값의 평균을 구해 가장 높은 평균 확률을 가진 클래스를 선택하는 방식입니다. 단순히 표 수만 세는 Hard Voting과 달리, 각 모델이 얼마나 확신하는지를 반영합니다.
확신이 높은 예측에 더 큰 가중치가 자연스럽게 부여됩니다.
다음 코드를 살펴봅시다.
from sklearn.ensemble import VotingClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.svm import SVC
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
X, y = make_classification(n_samples=1000, n_features=20, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42)
# Soft Voting 앙상블 구성
soft_voting_clf = VotingClassifier(
estimators=[
('rf', RandomForestClassifier(n_estimators=100)),
('lr', LogisticRegression()),
('svc', SVC(probability=True)) # 확률 출력 활성화 필수
],
voting='soft' # 확률 평균 방식
)
soft_voting_clf.fit(X_train, y_train)
print(f"Soft Voting 정확도: {soft_voting_clf.score(X_test, y_test):.4f}")
박시니어 씨가 예시를 들어 설명했습니다. "다시 의사 세 명 상황으로 돌아가볼게요.
이번엔 각 의사가 확신의 정도도 말해준다고 해봐요." 화이트보드에 다음과 같이 적었습니다. 의사 A: 감기 (확신도 90%) 의사 B: 독감 (확신도 60%) 의사 C: 독감 (확신도 55%) "Hard Voting이라면 독감이 2표니까 독감이 되겠죠?
근데 뭔가 이상하지 않아요?" 김개발 씨가 고개를 끄덕였습니다. "의사 A가 90%나 확신하는데, 다른 두 의사는 반반에 가까운 확신이네요." "바로 그거예요.
Soft Voting은 이 확률을 평균내요." 감기 평균 확률: (0.90 + 0.40 + 0.45) / 3 = 0.583 독감 평균 확률: (0.10 + 0.60 + 0.55) / 3 = 0.417 "감기의 평균 확률이 더 높으니까 최종 진단은 감기가 되는 거예요." Soft Voting의 핵심은 확률값입니다. 각 모델은 단순히 "클래스 A입니다"가 아니라 "클래스 A일 확률이 85%입니다"라고 예측해야 합니다.
코드에서 주목할 점은 SVC(probability=True) 부분입니다. SVM은 기본적으로 확률을 출력하지 않습니다.
probability=True 옵션을 주어야 확률 예측이 가능해집니다. 이 옵션 없이 Soft Voting을 시도하면 에러가 발생합니다.
Soft Voting은 일반적으로 Hard Voting보다 더 좋은 성능을 보입니다. 모델의 확신도라는 추가 정보를 활용하기 때문입니다.
어떤 모델이 특정 샘플에 대해 매우 높은 확신을 가지고 있다면, 그 예측은 더 믿을 만한 것입니다. 하지만 Soft Voting에도 주의할 점이 있습니다.
모델이 출력하는 확률이 잘 **보정(calibrated)**되어 있어야 합니다. 어떤 모델은 항상 극단적인 확률(0.99나 0.01)을 출력하고, 어떤 모델은 보수적인 확률(0.6이나 0.4)을 출력합니다.
이런 경우 확률의 스케일이 달라서 공정한 평균이 되지 않을 수 있습니다. 실무에서는 확률 보정 기법을 적용하거나, 모델별로 가중치를 다르게 주는 방법을 사용하기도 합니다.
VotingClassifier의 weights 파라미터를 사용하면 특정 모델에 더 큰 가중치를 줄 수 있습니다. 김개발 씨가 물었습니다.
"그럼 항상 Soft Voting이 더 좋은 건가요?" "대부분의 경우 그렇지만, 꼭 그런 건 아니에요. 확률 예측이 부정확한 모델이 섞여 있으면 오히려 Hard Voting이 나을 수도 있어요.
항상 둘 다 테스트해보는 게 좋아요."
실전 팁
💡 - Soft Voting을 사용하려면 모든 모델이 확률 예측을 지원해야 합니다
- SVC 사용 시 반드시 probability=True 옵션을 설정하세요
4. Stacking의 개념
Voting의 개념을 이해한 김개발 씨에게 박시니어 씨가 말했습니다. "Voting은 단순히 평균을 내는 거였잖아요?
근데 생각해보면, 어떤 모델의 예측을 더 믿어야 할지 학습할 수도 있지 않을까요?" 김개발 씨의 눈이 커졌습니다. "모델이 모델을 학습한다고요?"
Stacking은 여러 기본 모델의 예측값을 새로운 특성으로 사용하여 메타 모델이 최종 예측을 학습하는 앙상블 기법입니다. 마치 여러 전문가의 의견을 종합하는 최종 의사결정자가 있는 것과 같습니다.
메타 모델은 어떤 상황에서 어떤 기본 모델의 예측을 더 신뢰해야 하는지를 데이터로부터 학습합니다.
다음 코드를 살펴봅시다.
from sklearn.ensemble import StackingClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.svm import SVC
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
X, y = make_classification(n_samples=1000, n_features=20, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42)
# Stacking 앙상블 구성
stacking_clf = StackingClassifier(
estimators=[
('rf', RandomForestClassifier(n_estimators=100)),
('svc', SVC(probability=True))
],
final_estimator=LogisticRegression(), # 메타 모델
cv=5 # 교차 검증 폴드 수
)
stacking_clf.fit(X_train, y_train)
print(f"Stacking 정확도: {stacking_clf.score(X_test, y_test):.4f}")
박시니어 씨가 새로운 비유를 들었습니다. "회사에서 중요한 프로젝트 결정을 내린다고 생각해봐요.
마케팅팀, 개발팀, 재무팀이 각자 의견을 내요. 근데 CEO가 그냥 다수결로 결정할까요?" 김개발 씨가 생각해봤습니다.
"아뇨, CEO는 각 팀의 의견을 듣고 종합적으로 판단하겠죠. 상황에 따라 어떤 팀의 의견을 더 중요하게 볼 수도 있고요." "바로 그거예요.
Stacking에서 기본 모델들이 각 팀이고, 메타 모델이 CEO예요." Stacking의 핵심 아이디어는 학습된 결합입니다. Voting은 미리 정해진 규칙(다수결, 평균)으로 예측을 결합하지만, Stacking은 어떻게 결합해야 최적인지를 데이터로부터 학습합니다.
작동 방식을 단계별로 살펴보겠습니다. 첫 번째 단계에서 기본 모델들(base learners)이 학습됩니다.
위 코드에서는 RandomForest와 SVC가 기본 모델입니다. 각 모델은 원본 데이터로 학습을 진행합니다.
두 번째 단계에서 기본 모델들이 예측을 생성합니다. 이 예측값들이 새로운 특성이 됩니다.
원본 데이터가 20개의 특성을 가졌다면, 이제 기본 모델 2개의 예측값 2개가 새로운 특성이 됩니다. 세 번째 단계에서 메타 모델(final_estimator)이 이 새로운 특성으로 학습합니다.
위 코드에서는 LogisticRegression이 메타 모델입니다. 메타 모델은 "RandomForest가 이렇게 예측하고 SVC가 저렇게 예측했을 때, 실제 정답은 무엇이었는가"를 학습합니다.
여기서 중요한 것이 cv=5 파라미터입니다. 이것은 교차 검증을 의미합니다.
왜 교차 검증이 필요할까요? 만약 기본 모델을 전체 학습 데이터로 학습시킨 후, 같은 데이터에 대해 예측을 생성하면 어떻게 될까요?
기본 모델이 학습 데이터를 이미 "본" 상태이므로 예측이 지나치게 좋아집니다. 이런 예측으로 메타 모델을 학습시키면 과적합이 발생합니다.
교차 검증을 사용하면 기본 모델이 "보지 않은" 데이터에 대한 예측을 생성할 수 있습니다. 데이터를 5개 폴드로 나누고, 각 폴드에 대해 나머지 4개 폴드로 학습한 모델이 예측합니다.
이렇게 하면 공정한 예측값을 얻을 수 있습니다. Stacking은 Voting보다 강력하지만, 그만큼 복잡합니다.
학습 시간이 더 오래 걸리고, 하이퍼파라미터 튜닝도 더 어렵습니다. 하지만 제대로 구성하면 상당한 성능 향상을 얻을 수 있습니다.
실전 팁
💡 - 메타 모델은 보통 간단한 모델(로지스틱 회귀 등)을 사용합니다
- cv 값이 클수록 안정적이지만 학습 시간이 늘어납니다
5. Stacking 심화 다양한 구성
기본적인 Stacking을 이해한 김개발 씨가 물었습니다. "기본 모델과 메타 모델을 어떻게 선택해야 하나요?" 박시니어 씨가 답했습니다.
"좋은 질문이에요. 모델 선택에 따라 성능이 크게 달라질 수 있거든요."
Stacking의 성능은 기본 모델의 다양성과 메타 모델의 적절한 복잡도에 달려 있습니다. 기본 모델들은 서로 다른 관점에서 데이터를 바라보는 것이 좋습니다.
메타 모델은 기본 모델들의 예측을 효과적으로 결합할 수 있을 정도로만 복잡하면 됩니다.
다음 코드를 살펴봅시다.
from sklearn.ensemble import StackingClassifier
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
from sklearn.linear_model import LogisticRegression, RidgeClassifier
from sklearn.svm import SVC
from sklearn.neighbors import KNeighborsClassifier
from sklearn.neural_network import MLPClassifier
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
X, y = make_classification(n_samples=1000, n_features=20, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42)
# 다양한 유형의 기본 모델 조합
stacking_clf = StackingClassifier(
estimators=[
('rf', RandomForestClassifier(n_estimators=100)), # 트리 기반
('gb', GradientBoostingClassifier()), # 부스팅
('svc', SVC(probability=True)), # 커널 기반
('knn', KNeighborsClassifier()), # 거리 기반
],
final_estimator=LogisticRegression(),
passthrough=True # 원본 특성도 메타 모델에 전달
)
stacking_clf.fit(X_train, y_train)
print(f"다양한 Stacking 정확도: {stacking_clf.score(X_test, y_test):.4f}")
박시니어 씨가 화이트보드에 표를 그리기 시작했습니다. "기본 모델을 선택할 때 중요한 건 다양성이에요.
비슷한 모델을 여러 개 쓰는 것보다 서로 다른 방식으로 작동하는 모델을 쓰는 게 좋아요." 머신러닝 모델은 크게 몇 가지 유형으로 나눌 수 있습니다. 트리 기반 모델은 데이터를 조건에 따라 분할합니다.
RandomForest, GradientBoosting, XGBoost 등이 여기 속합니다. 비선형 관계를 잘 포착하고, 특성 간 상호작용을 자동으로 학습합니다.
선형 모델은 특성의 선형 조합으로 예측합니다. LogisticRegression, Ridge, Lasso 등이 있습니다.
선형 관계가 있는 데이터에서 효과적이고, 해석이 쉽습니다. 커널 기반 모델은 데이터를 고차원 공간으로 변환합니다.
SVM이 대표적입니다. 복잡한 결정 경계를 학습할 수 있습니다.
거리 기반 모델은 비슷한 샘플은 같은 클래스일 것이라고 가정합니다. KNN이 대표적입니다.
지역적인 패턴을 잘 포착합니다. 위 코드에서는 이 네 가지 유형의 모델을 모두 사용했습니다.
각 모델이 다른 관점에서 데이터를 바라보기 때문에, 결합했을 때 시너지가 발생합니다. passthrough=True 옵션도 주목할 만합니다.
이 옵션을 주면 메타 모델이 기본 모델의 예측뿐만 아니라 원본 특성도 함께 볼 수 있습니다. 때로는 이것이 성능 향상에 도움이 됩니다.
메타 모델 선택에 대해서도 알아보겠습니다. 일반적으로 메타 모델은 단순한 모델이 좋습니다.
로지스틱 회귀가 가장 흔히 사용됩니다. 왜 그럴까요?
메타 모델의 입력은 기본 모델들의 예측값입니다. 기본 모델이 4개이고 이진 분류라면, 메타 모델의 입력은 4개뿐입니다.
이렇게 적은 특성으로 복잡한 모델을 학습시키면 과적합이 발생하기 쉽습니다. 또한 기본 모델들이 이미 데이터의 복잡한 패턴을 학습했습니다.
메타 모델은 이 예측들을 "어떻게 조합할지"만 학습하면 됩니다. 이 작업에는 복잡한 모델이 필요 없습니다.
물론 예외도 있습니다. 기본 모델이 많거나, passthrough로 원본 특성을 함께 사용한다면 메타 모델도 조금 더 복잡해질 수 있습니다.
김개발 씨가 정리했습니다. "기본 모델은 다양하게, 메타 모델은 단순하게.
맞죠?" 박시니어 씨가 고개를 끄덕였습니다. "정확해요!"
실전 팁
💡 - 기본 모델은 알고리즘 유형을 다양하게 조합하세요
- passthrough=True를 사용하면 원본 특성도 메타 모델에 전달됩니다
6. 가중치 Voting
김개발 씨가 앙상블의 여러 기법을 공부하다가 의문이 생겼습니다. "Voting에서 모든 모델이 똑같은 영향력을 갖잖아요.
그런데 성능이 더 좋은 모델한테 더 큰 가중치를 줄 수는 없나요?" 박시니어 씨가 웃었습니다. "당연히 있죠."
가중치 Voting은 각 모델에 서로 다른 가중치를 부여하여 최종 예측에 대한 영향력을 조절하는 방식입니다. 성능이 더 좋은 모델에 높은 가중치를 주면, 그 모델의 예측이 최종 결과에 더 큰 영향을 미칩니다.
마치 회의에서 전문 분야에 대해서는 해당 전문가의 의견에 더 귀 기울이는 것과 같습니다.
다음 코드를 살펴봅시다.
from sklearn.ensemble import VotingClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.svm import SVC
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split, cross_val_score
X, y = make_classification(n_samples=1000, n_features=20, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42)
# 각 모델의 성능을 먼저 확인
rf = RandomForestClassifier(n_estimators=100)
lr = LogisticRegression()
svc = SVC(probability=True)
# 교차 검증으로 각 모델 성능 측정
for name, model in [('RF', rf), ('LR', lr), ('SVC', svc)]:
scores = cross_val_score(model, X_train, y_train, cv=5)
print(f"{name} CV 점수: {scores.mean():.4f}")
# 성능에 비례하여 가중치 부여 (예: RF가 가장 좋았다고 가정)
weighted_voting = VotingClassifier(
estimators=[('rf', rf), ('lr', lr), ('svc', svc)],
voting='soft',
weights=[3, 1, 2] # RF에 가장 높은 가중치
)
weighted_voting.fit(X_train, y_train)
print(f"가중치 Voting 정확도: {weighted_voting.score(X_test, y_test):.4f}")
박시니어 씨가 설명을 시작했습니다. "자, 다시 의사 세 명 비유로 돌아가볼게요.
근데 이번엔 한 명은 30년 경력의 베테랑이고, 한 명은 10년 차, 한 명은 신입이에요. 모든 의사의 의견을 똑같이 취급하는 게 맞을까요?" 김개발 씨가 대답했습니다.
"아뇨, 경험 많은 의사 의견에 더 비중을 두는 게 맞을 것 같아요." "바로 그게 가중치 Voting이에요." 가중치 Voting의 핵심은 weights 파라미터입니다. 위 코드에서 **weights=[3, 1, 2]**는 RF에 3, LR에 1, SVC에 2의 가중치를 부여한다는 의미입니다.
Soft Voting에서 가중치가 어떻게 적용되는지 살펴보겠습니다. 일반 Soft Voting은 각 모델의 확률을 단순 평균합니다.
하지만 가중치가 있으면 가중 평균을 계산합니다. 예를 들어 세 모델이 클래스 1에 대해 다음과 같은 확률을 예측했다고 해봅시다.
RF: 0.8, LR: 0.4, SVC: 0.6 단순 평균이라면: (0.8 + 0.4 + 0.6) / 3 = 0.6 가중 평균(weights=[3,1,2])이라면: (0.8×3 + 0.4×1 + 0.6×2) / (3+1+2) = 3.0 / 6 = 0.7 RF의 높은 확률 예측이 더 크게 반영되어 최종 확률이 높아졌습니다. 그럼 가중치는 어떻게 결정할까요?
가장 일반적인 방법은 교차 검증 점수를 기준으로 하는 것입니다. 위 코드처럼 각 모델의 교차 검증 점수를 먼저 측정하고, 그 점수에 비례하여 가중치를 부여합니다.
더 정교한 방법도 있습니다. 그리드 서치를 사용하여 최적의 가중치 조합을 찾을 수 있습니다.
가중치를 [1,1,1], [2,1,1], [1,2,1], ... 등으로 바꿔가며 검증 성능이 가장 좋은 조합을 선택합니다.
주의할 점도 있습니다. 가중치를 너무 극단적으로 설정하면 앙상블의 의미가 없어집니다.
예를 들어 weights=[100,1,1]이면 사실상 RF 단독 모델과 다를 바 없습니다. 앙상블의 장점인 다양성이 사라지는 것입니다.
김개발 씨가 물었습니다. "Hard Voting에서도 가중치를 쓸 수 있나요?" "물론이에요.
Hard Voting에서 가중치는 투표 수에 곱해집니다. weights=[3,1,2]이면 RF의 한 표가 3표의 가치를 갖는 거죠." 실무에서는 Soft Voting과 가중치를 함께 사용하는 경우가 많습니다.
확률 정보와 모델 성능 정보를 모두 활용할 수 있기 때문입니다.
실전 팁
💡 - 가중치는 교차 검증 점수를 기준으로 설정하는 것이 좋습니다
- 너무 극단적인 가중치는 앙상블의 다양성을 해칠 수 있습니다
7. 실전 프로젝트 적용
이론을 충분히 공부한 김개발 씨가 드디어 실제 프로젝트에 앙상블을 적용해보기로 했습니다. "이번 고객 이탈 예측 프로젝트에 앙상블을 적용해볼게요." 박시니어 씨가 조언했습니다.
"좋아요, 근데 실전에서는 몇 가지 더 고려할 게 있어요."
실제 프로젝트에서 앙상블을 적용할 때는 데이터 전처리, 모델 선택, 하이퍼파라미터 튜닝, 검증 등을 체계적으로 진행해야 합니다. 단순히 모델을 합치는 것이 아니라, 각 단계에서 최적의 선택을 해야 좋은 성능을 얻을 수 있습니다.
다음 코드를 살펴봅시다.
from sklearn.ensemble import StackingClassifier, VotingClassifier
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.svm import SVC
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
from sklearn.model_selection import cross_val_score, GridSearchCV
from sklearn.datasets import make_classification
import numpy as np
X, y = make_classification(n_samples=1000, n_features=20, random_state=42)
# SVC는 스케일링이 필요하므로 파이프라인으로 구성
svc_pipeline = Pipeline([
('scaler', StandardScaler()),
('svc', SVC(probability=True))
])
# 앙상블 구성
ensemble = VotingClassifier(
estimators=[
('rf', RandomForestClassifier(n_estimators=100)),
('gb', GradientBoostingClassifier()),
('svc', svc_pipeline)
],
voting='soft'
)
# 교차 검증으로 성능 평가
scores = cross_val_score(ensemble, X, y, cv=5, scoring='accuracy')
print(f"앙상블 CV 점수: {scores.mean():.4f} (+/- {scores.std()*2:.4f})")
박시니어 씨가 실전 팁을 공유하기 시작했습니다. "이론만으로는 부족해요.
실전에서 앙상블을 적용할 때 주의할 점들을 알려줄게요." 첫 번째는 데이터 전처리입니다. 모든 모델이 같은 전처리를 필요로 하는 것은 아닙니다.
RandomForest나 GradientBoosting 같은 트리 기반 모델은 특성 스케일링이 필요 없습니다. 하지만 SVM이나 로지스틱 회귀는 스케일링이 중요합니다.
위 코드에서 Pipeline을 사용한 부분을 주목하세요. SVC만 따로 StandardScaler를 적용했습니다.
이렇게 하면 각 모델에 맞는 전처리를 적용하면서도 앙상블로 묶을 수 있습니다. 두 번째는 교차 검증입니다.
앙상블의 성능을 평가할 때 단순히 train/test split만으로는 부족합니다. 데이터를 어떻게 나누느냐에 따라 결과가 달라질 수 있기 때문입니다.
cross_val_score를 사용하면 여러 번 나눠서 평가하므로 더 신뢰할 수 있는 성능 추정치를 얻습니다. 세 번째는 분산 확인입니다.
위 코드의 출력에서 (+/- 숫자) 부분은 표준편차의 2배입니다. 이 값이 크면 모델이 불안정하다는 뜻입니다.
앙상블을 사용하면 일반적으로 단일 모델보다 분산이 줄어듭니다. 네 번째는 계산 비용입니다.
앙상블은 여러 모델을 학습해야 하므로 시간이 오래 걸립니다. 특히 Stacking은 교차 검증까지 사용하므로 더 오래 걸립니다.
대용량 데이터에서는 모델 개수나 하이퍼파라미터를 조절해야 할 수 있습니다. 김개발 씨가 물었습니다.
"하이퍼파라미터 튜닝은 어떻게 해요? 모델이 여러 개니까 복잡할 것 같아요." "맞아요.
VotingClassifier나 StackingClassifier 안의 모델 하이퍼파라미터를 튜닝하려면 특별한 문법을 사용해요. 모델이름__파라미터 형식으로 접근합니다." 예를 들어 RandomForest의 n_estimators를 튜닝하려면 rf__n_estimators로 접근합니다.
GridSearchCV와 함께 사용하면 앙상블 전체를 최적화할 수 있습니다. 다섯 번째는 모델 다양성 확인입니다.
앙상블에 포함된 모델들이 비슷한 예측을 하면 앙상블의 효과가 줄어듭니다. 각 모델의 예측을 비교해서 상관관계가 너무 높으면 모델 조합을 바꿔보는 것이 좋습니다.
김개발 씨가 고개를 끄덕였습니다. "생각보다 고려할 게 많네요." "그렇죠.
하지만 이런 세부 사항을 잘 챙기면 성능이 크게 향상될 수 있어요."
실전 팁
💡 - 각 모델에 맞는 전처리를 Pipeline으로 구성하세요
- 반드시 교차 검증으로 성능을 평가하고, 분산도 함께 확인하세요
8. Voting과 Stacking 비교 선택
김개발 씨가 마지막으로 궁금한 점을 물었습니다. "그래서 Voting과 Stacking 중에 뭘 써야 해요?" 박시니어 씨가 답했습니다.
"상황에 따라 달라요. 각각의 장단점을 알면 선택하기 쉬워요."
Voting은 구현이 간단하고 해석이 쉬우며 과적합 위험이 낮습니다. Stacking은 더 유연하고 강력하지만 복잡하고 과적합에 주의해야 합니다.
데이터의 양, 계산 자원, 요구되는 성능 수준에 따라 적절한 방법을 선택해야 합니다.
다음 코드를 살펴봅시다.
from sklearn.ensemble import VotingClassifier, StackingClassifier
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.svm import SVC
from sklearn.model_selection import cross_val_score
from sklearn.datasets import make_classification
import time
X, y = make_classification(n_samples=1000, n_features=20, random_state=42)
# 기본 모델 정의
estimators = [
('rf', RandomForestClassifier(n_estimators=50)),
('gb', GradientBoostingClassifier(n_estimators=50)),
('svc', SVC(probability=True))
]
# Voting
start = time.time()
voting = VotingClassifier(estimators=estimators, voting='soft')
voting_scores = cross_val_score(voting, X, y, cv=5)
voting_time = time.time() - start
# Stacking
start = time.time()
stacking = StackingClassifier(estimators=estimators,
final_estimator=LogisticRegression(), cv=5)
stacking_scores = cross_val_score(stacking, X, y, cv=5)
stacking_time = time.time() - start
print(f"Voting - 정확도: {voting_scores.mean():.4f}, 시간: {voting_time:.2f}초")
print(f"Stacking - 정확도: {stacking_scores.mean():.4f}, 시간: {stacking_time:.2f}초")
박시니어 씨가 두 기법의 차이를 정리해주었습니다. "먼저 Voting의 장점부터 볼게요." Voting은 구현이 매우 간단합니다.
몇 줄의 코드로 여러 모델을 결합할 수 있습니다. 학습 시간도 짧습니다.
각 기본 모델을 한 번씩만 학습하면 되기 때문입니다. 해석도 쉽습니다.
"세 모델 중 두 모델이 이탈 고객이라고 예측했습니다"라고 설명하면 비전문가도 이해할 수 있습니다. 과적합 위험도 상대적으로 낮습니다.
단순 평균이나 다수결은 추가 파라미터를 학습하지 않기 때문입니다. "그럼 Stacking은요?" Stacking은 더 강력합니다.
단순 평균이 아니라 어떻게 결합해야 최적인지를 데이터로부터 학습하기 때문입니다. 기본 모델들 사이의 복잡한 관계도 메타 모델이 포착할 수 있습니다.
하지만 학습 시간이 훨씬 깁니다. 교차 검증을 사용하기 때문에 기본 모델을 여러 번 학습해야 합니다.
위 코드의 실행 결과를 보면 Stacking이 Voting보다 몇 배나 더 오래 걸리는 것을 확인할 수 있습니다. 과적합 위험도 있습니다.
메타 모델이 학습 데이터에 과하게 맞춰질 수 있습니다. 특히 데이터가 적을 때 주의해야 합니다.
"그래서 언제 뭘 써야 해요?" 박시니어 씨가 가이드라인을 제시했습니다. Voting을 선택하는 경우: - 빠른 프로토타이핑이 필요할 때 - 데이터가 적어서 과적합이 걱정될 때 - 모델 해석이 중요할 때 - 계산 자원이 제한적일 때 Stacking을 선택하는 경우: - 최고 성능이 필요할 때 (예: 경진대회) - 데이터가 충분히 많을 때 - 계산 자원이 충분할 때 - 기본 모델들의 예측이 서로 상보적일 때 "실무에서는 보통 Voting으로 시작해서, 더 성능이 필요하면 Stacking을 시도해요.
둘 다 해보고 비교하는 게 가장 좋아요." 김개발 씨가 고개를 끄덕였습니다. "Voting으로 먼저 베이스라인을 만들고, 필요하면 Stacking으로 올려보는 거네요." "정확해요.
그리고 둘을 섞어 쓸 수도 있어요. Voting 앙상블을 Stacking의 기본 모델로 사용하는 것처럼요."
실전 팁
💡 - 먼저 Voting으로 베이스라인을 구축하고, 필요시 Stacking으로 성능을 높이세요
- 두 방법 모두 시도해보고 교차 검증 결과를 비교하는 것이 좋습니다
이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!
댓글 (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의 핵심 개념과 실무 활용법을 배워봅니다. 초급 개발자도 쉽게 따라할 수 있도록 실전 예제와 함께 설명합니다.