스태킹에 대해 설명하기 전에, 이를 이해하기 위한 두 가지 중요한 개념을 먼저 알아보겠습니다: 기본 학습자와 메타 학습자입니다.
기본 학습자(Base Learner)
기본 학습자는 앙상블 모델의 첫 번째 단계에서 사용되는 개별 모델들입니다. 각 기본 학습자는 독립적으로 학습하여 자체적인 예측을 수행합니다. 이들은 앙상블을 구성하는 기본적인 요소로, 서로 다른 알고리즘을 사용할 수도 있고, 동일한 알고리즘을 다른 데이터 샘플에 대해 학습시킬 수도 있습니다.
메타 학습자(Meta Learner)
메타 학습자는 앙상블 모델의 두 번째 단계에서 작동하는 모델입니다. 메타 학습자는 기본 학습자들이 생성한 예측값을 입력으로 받아, 이를 바탕으로 최종 예측을 수행합니다. 메타 학습자는 기본 학습자들이 가진 오류나 편향을 보정하여, 더 나은 최종 결과를 얻기 위해 사용됩니다.
스태킹(Stacking)이란 무엇인가?
스태킹은 여러 개의 기본 모델, 즉 기본 학습자(Base Learners)의 예측을 결합하여 최종 예측을 만드는 머신러닝 기법입니다. 이 과정에서는 동일한 학습 데이터셋을 여러 기본 모델에 학습시키고, 이 모델들의 예측값을 상위 모델(메타 모델, Meta Model)에 입력으로 사용하여 최종 예측을 수행합니다. 스태킹의 핵심 아이디어는 서로 다른 기본 모델의 예측을 결합함으로써 단일 모델을 사용하는 것보다 더 뛰어난 예측 성능을 얻는 것입니다.
스태킹(Stacking)의 작동 방식
스태킹은 여러 개의 서로 다른 모델(기본 학습자)을 학습시켜, 그들의 예측 결과를 결합하여 최종 예측을 만드는 앙상블 기법입니다. 이 결합을 통해 개별 모델보다 더 나은 성능을 기대할 수 있습니다. 스태킹은 두 단계로 나누어집니다.
- 기본 학습자(Base Learners): 서로 다른 알고리즘을 사용하는 여러 모델들이 학습됩니다.
- 메타 모델(Meta Model): 기본 학습자들이 만든 예측을 입력으로 받아, 최종 예측을 수행합니다.
스태킹이 작동하는 과정은 다음과 같습니다.
1. 데이터 준비
- 먼저, 데이터를 준비합니다. 이 과정에서는 `numpy`를 사용해 난수를 생성하여 500개의 샘플과 10개의 피처를 가진 데이터셋 `X`를 만듭니다. 타겟 값 `y`는 이진 분류 문제로, 0과 1 사이의 값을 가집니다.
- 데이터를 학습용과 검증용으로 분할합니다. 여기서는 `train_test_split`을 사용해 80%의 데이터를 학습 세트(`X_train`, `y_train`)로, 20%의 데이터를 검증 세트(`X_val`, `y_val`)로 분할합니다.
X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2, random_state=42)
2. 기본 모델 선택
- 두 가지 기본 모델을 선택합니다. 이 코드에서는 `GradientBoostingClassifier`와 `RandomForestClassifier`를 사용합니다. 이 모델들은 서로 다른 방식으로 데이터를 학습하며, 서로 다른 예측 오류를 보완할 수 있습니다.
base_models = [
GradientBoostingClassifier(random_state=42),
RandomForestClassifier(random_state=42),
]
3. 메타 모델 선택
- 메타 모델로는 `LogisticRegression`을 선택합니다. 이 모델은 기본 모델들이 생성한 예측값을 입력으로 받아 최종 예측을 수행하는 역할을 합니다.
meta_model = LogisticRegression()
4. 기본 모델 학습
- `KFold` 교차 검증을 사용해 기본 모델들을 학습합니다. `KFold`는 데이터를 여러 개의 폴드로 나누고, 각 폴드마다 모델을 학습시킨 후, 나머지 폴드에 대해 예측을 수행합니다.
- `X_train_meta` 배열에 기본 모델들이 학습 데이터에 대해 예측한 결과를 저장합니다. 이 배열은 이후 메타 모델을 학습하는 데 사용됩니다.
for i, model in enumerate(base_models):
fold_predictions = np.zeros(X_train.shape[0]) # 각 fold마다 예측 결과를 누적할 배열
for train_idx, val_idx in kf.split(X_train):
model.fit(X_train[train_idx], y_train[train_idx])
fold_predictions[val_idx] = model.predict(X_train[val_idx])
X_train_meta[:, i] = fold_predictions # 각 모델의 예측을 메타 입력으로 저장
5. 검증 세트에서 예측 수행
- 기본 모델들을 학습한 후, 이 모델들을 사용해 검증 데이터(`X_val`)에 대한 예측을 수행합니다. 이 예측값은 메타 모델의 입력으로 사용됩니다.
X_val_meta = np.zeros((X_val.shape[0], len(base_models)))
for i, model in enumerate(base_models):
X_val_meta[:, i] = model.predict(X_val)
6. 메타 모델 학습
- 메타 모델은 `X_train_meta`에 저장된 기본 모델들의 예측값을 특징(feature)으로 사용하여 학습됩니다. 이 과정에서 메타 모델은 기본 모델들의 예측 패턴을 학습하여 최종 예측을 수행할 수 있게 됩니다.
meta_model.fit(X_train_meta, y_train)
7. 검증 세트에서 최종 예측 수행
- 학습된 메타 모델을 사용해 검증 데이터(`X_val`)에 대한 최종 예측을 수행합니다. 이때 `X_val_meta`에 저장된 기본 모델들의 예측값을 입력으로 사용합니다.
y_pred = meta_model.predict(X_val_meta)
8. 모델 평가
- 마지막으로, F1 점수를 계산하여 스태킹 앙상블 모델의 성능을 평가합니다. F1 점수는 모델의 예측 결과와 실제 값을 비교하여 계산됩니다.
f1 = f1_score(y_val, y_pred, average='macro')
print(f"F1 Score: {f1:.2f}")
결국, 스태킹은 여러 모델의 예측값을 결합하여 최종 예측을 만듭니다. 기본 학습자들이 개별적으로 예측을 수행한 뒤, 이 예측값들을 메타 모델에 입력으로 사용하여 더 정확한 최종 예측을 생성합니다. 다양한 모델의 강점을 활용함으로써, 스태킹은 개별 모델보다 더 우수한 성능을 발휘할 수 있습니다.
스태킹(Stacking)의 작동 방식 - 그림으로 표현
전체 코드
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.ensemble import GradientBoostingClassifier, RandomForestClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import f1_score
import numpy as np
from sklearn.model_selection import StratifiedKFold
# 데이터 준비 (예시용으로 난수 데이터 생성)
np.random.seed(42)
X = np.random.rand(500, 10) # 500개의 샘플, 10개의 피처
y = np.random.randint(0, 2, 500) # 이진 분류를 위한 타겟 값
# 학습 데이터와 검증 데이터로 분할
X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2, random_state=42)
# 기본 모델들 정의
base_models = [
GradientBoostingClassifier(random_state=42),
RandomForestClassifier(random_state=42),
]
# 메타 모델 정의
meta_model = LogisticRegression()
# StratifiedKFold 교차 검증을 통해 메타 모델을 위한 예측값 생성
kf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
X_train_meta = np.zeros((X_train.shape[0], len(base_models)))
for i, model in enumerate(base_models):
for train_idx, val_idx in kf.split(X_train, y_train): # 타겟값 y_train을 추가로 사용하여 폴드 분할
model.fit(X_train[train_idx], y_train[train_idx])
X_train_meta[val_idx, i] = model.predict(X_train[val_idx])
# 검증 데이터에 대한 메타 모델 입력 생성 및 최종 예측
X_val_meta = np.zeros((X_val.shape[0], len(base_models)))
for i, model in enumerate(base_models):
X_val_meta[:, i] = model.predict(X_val)
# StratifiedKFold를 통해 얻은 X_train_meta로 메타 모델 학습
meta_model.fit(X_train_meta, y_train)
# 검증 데이터 예측 및 F1 Score 계산
y_pred = meta_model.predict(X_val_meta)
f1 = f1_score(y_val, y_pred, average='macro')
print(f"F1 Score: {f1:.2f}")
################################
####### Test 데이터셋 예측 ########
################################
X_test = np.random.rand(10, 10) # 10개의 샘플, 10개의 피처
X_test_meta = np.zeros((X_test.shape[0], len(base_models))) # 테스트 데이터에서 생성된 메타 모델 입력
# 테스트 데이터에 대한 예측값 생성
for i, model in enumerate(base_models):
X_test_meta[:, i] = model.predict(X_test) # 테스트 데이터에 대한 각 기본 모델의 예측값 저장
# 메타 모델을 사용한 최종 예측
test_pred = meta_model.predict(X_test_meta)
print("Test set predictions:", test_pred)
전체 코드를 단순하게 수정 (교차검증 추가)
import pandas as pd
from sklearn.model_selection import train_test_split, StratifiedKFold, cross_val_score
from sklearn.ensemble import GradientBoostingClassifier, RandomForestClassifier, StackingClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import f1_score
import numpy as np
# 데이터 준비 (예시용으로 난수 데이터 생성)
np.random.seed(42)
X = np.random.rand(500, 10) # 500개의 샘플, 10개의 피처
y = np.random.randint(0, 2, 500) # 이진 분류를 위한 타겟 값
# 학습 데이터와 검증 데이터로 분할
X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2, random_state=42)
# 기본 모델들 정의
base_models = [
('gbc', GradientBoostingClassifier(random_state=42)),
('rf', RandomForestClassifier(random_state=42)),
]
# 메타 모델 정의
meta_model = LogisticRegression()
# StratifiedKFold 정의
skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
# StackingClassifier 정의
stacking_model = StackingClassifier(
estimators=base_models,
final_estimator=meta_model,
cv=skf, # StratifiedKFold를 교차 검증 방법으로 사용
passthrough=False, # 기본 모델의 입력을 메타 모델에 전달하지 않음
n_jobs=-1 # 병렬 처리 사용
)
# cross_val_score를 사용하여 교차 검증 수행
cv_scores = cross_val_score(stacking_model, X_train, y_train, cv=skf, scoring='f1_macro', n_jobs=-1)
# 교차 검증 결과 출력
print(f"Cross-validated F1 scores: {cv_scores}")
print(f"Mean F1 score: {cv_scores.mean():.2f}")
# 스태킹 모델 학습
stacking_model.fit(X_train, y_train)
# 검증 데이터 예측 및 F1 Score 계산
y_pred = stacking_model.predict(X_val)
f1 = f1_score(y_val, y_pred, average='macro')
print(f"F1 Score on validation set: {f1:.2f}")
######## Test 데이터셋 예측 ########
X_test = np.random.rand(10, 10) # 10개의 샘플, 10개의 피처
# 테스트 데이터에 대한 최종 예측
test_pred = stacking_model.predict(X_test)
print("Test set predictions:", test_pred)
스태킹의 장점
스태킹은 머신러닝에서 다양한 장점을 제공합니다.
1. 향상된 예측 성능: 스태킹은 여러 기본 모델의 결과를 결합하여 편향과 분산을 줄이고, 더 나은 예측 성능을 제공합니다. 메타 모델은 각 기본 모델의 강점을 학습하여, 개별 모델이 단독으로는 포착할 수 없는 복잡한 패턴을 더 잘 포착할 수 있습니다.
2. 모델 다양성: 스태킹은 다양한 알고리즘, 구조, 하이퍼파라미터 설정을 사용하여 서로 다른 기본 모델을 활용합니다. 이러한 다양성은 과적합의 위험을 줄이고, 스태킹 앙상블을 다양한 데이터 유형에 대해 더 강력하게 만듭니다.
3. 유연성: 스태킹은 분류, 회귀, 시계열 예측 등 다양한 머신러닝 문제를 해결할 수 있는 유연한 전략입니다. 결정 트리, 서포트 벡터 머신, 신경망 등 다양한 기본 모델과 함께 사용할 수 있습니다
4. 해석 가능성: 스태킹은 최종 예측에서 각 기본 모델과 그 예측의 중요성을 드러낼 수 있습니다. 메타 모델에서 각 기본 모델의 기여도를 분석함으로써, 상대적인 중요성과 해석 가능성을 이해할 수 있습니다.
스태킹의 모범 사례
스태킹을 사용할 때 다음과 같은 모범 사례를 기억하는 것이 중요합니다:
1. 모델 다양성 유지: 스태킹의 강점은 기본 모델들의 다양성에 있습니다. 서로 다른 오류를 발생시킬 가능성이 있는 다양한 기본 모델을 사용하는 것이 중요합니다. 유사한 모델이나 비슷한 하이퍼파라미터 설정을 가진 모델만을 사용하면 성능 향상이 제한될 수 있습니다.
2. 성능 평가: 스태킹 앙상블의 성능을 평가할 때는 적절한 평가 지표를 사용합니다. 교차 검증이나 홀드아웃 검증 기법을 사용해 신뢰할 수 있는 성능 추정치를 얻고, 개별 기본 모델과 비교하여 스태킹 앙상블이 실제로 예측 성능을 향상시키는지 확인해야 합니다.
3. 메타 모델 선택: 문제에 적합한 메타 모델을 선택하기 위해 여러 메타 모델을 실험해 보세요. 메타 모델의 선택은 스태킹 앙상블의 성능에 큰 영향을 미칠 수 있습니다. 로지스틱 회귀, 결정 트리, 신경망 또는 그래디언트 부스팅 머신 등 다양한 메타 모델을 고려해 보세요. 선택 시에는 메타 모델의 해석 가능성, 복잡성, 일반화 성능을 고려해야 합니다.
4. 하이퍼파라미터 튜닝: 기본 모델과 메타 모델 모두의 하이퍼파라미터를 최적화하세요. 하이퍼파라미터 튜닝은 스태킹 앙상블의 성능에 큰 영향을 미칠 수 있습니다. 다양한 하이퍼파라미터 설정을 실험하여 최적의 성능을 발휘할 조합을 찾아보세요.
5. 앙상블 크기 조절: 너무 많은 기본 모델을 사용하면 과적합과 계산 복잡성이 증가할 수 있습니다. 성능 저하 없이 모델 해석 가능성과 계산 효율성을 유지할 수 있는 적절한 앙상블 크기를 찾아야 합니다.
6. 도메인 특성 고려: 스태킹을 적용할 때는 도메인별 특성을 고려해야 합니다. 도메인에 따라 스태킹 앙상블의 성능에 영향을 미치는 고유한 특징이 있을 수 있습니다. 예를 들어, 이미지 인식 작업에서는 색상, 질감, 형태 등 다양한 특성을 캡처할 수 있는 기본 모델을 사용하는 것이 성능 향상에 도움이 될 수 있습니다.
'pythonML' 카테고리의 다른 글
[pythonML] Autogluon 사용법 | Autogluon 매개변수, 속성, 메소드 | Autogluon 코드 적용 (0) | 2024.09.01 |
---|---|
[pythonML] H2O AutoML 사용법 | H2O 코드 적용 | H2O 파라미터 (0) | 2024.08.30 |
[pythonML] 배깅(Bagging)이란? | 배깅(Bagging)의 동작 원리 | 배깅을 사용한 모델 학습 코드 (1) | 2024.08.28 |
[pythonML] 앙상블(ensemble model)이란? | 앙상블의 종류 | 편향 (Bias)과 분산(Variance) (1) | 2024.08.27 |
[pythonML] XGBoost 하이퍼파라미터 (0) | 2023.06.13 |