Menangani class imbalance dan memilih metric yang tepat untuk business context
Optimalkan model menggunakan GridSearchCV dan hyperparameter tuning secara sistematis
4.1 Pengantar: Kekuatan Kolaborasi
“Kebijaksanaan kerumunan” - ide bahwa banyak predictor sederhana yang dikombinasikan menghasilkan predictor yang lebih baik daripada predictor individual.
Ensemble learning adalah teknik yang menggabungkan banyak model untuk mencapai performa superior. Ide sederhananya:
Keragaman (Diversity): Model harus berbeda satu sama lain
Ketepatan (Accuracy): Setiap model harus lebih baik dari random guessing
Kemerdekaan (Independence): Kesalahan model tidak boleh berkorelasi sempurna
XGBoost adalah implementasi yang dioptimalkan dan lebih cepat dari Gradient Boosting.
Code
# Catatan: Uncomment jika xgboost sudah terinstall# from xgboost import XGBClassifier## xgb = XGBClassifier(n_estimators=100, learning_rate=0.1, max_depth=3, random_state=42)# xgb.fit(X_train, y_train)## xgb_acc = xgb.score(X_test, y_test)# print(f"XGBoost Test Accuracy: {xgb_acc:.4f}")print("XGBoost memerlukan instalasi: pip install xgboost")print("Namun GradientBoosting dari sklearn sudah cukup untuk praktikum")
Kapan menggunakan Boosting:
Akurasi maksimal penting
Dataset besar
Interpretabilitas kurang penting
Waktu training bukan masalah
Warning: Boosting dan Overfitting
Boosting bisa overfit jika:
Terlalu banyak iterasi (n_estimators)
Learning rate terlalu tinggi
Max depth terlalu besar
Gunakan early stopping dan validasi set!
4.5 Stacking & Blending
4.5.1 Stacking (Stacked Generalization)
Stacking menggunakan meta-learner untuk mengkombinasikan prediksi dari base learners.
Proses:
Split data menjadi 3 bagian (train, validation, test)
Latih base learners pada bagian train
Prediksi pada bagian validation (features baru)
Latih meta-learner pada prediksi validation
Prediksi final dengan base learners dan meta-learner
Code
from sklearn.model_selection import cross_val_predictfrom sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifierfrom sklearn.linear_model import LogisticRegressionfrom sklearn.datasets import make_classification# DataX, y = make_classification(n_samples=400, n_features=20, n_informative=10, n_classes=2, random_state=42)X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)# Base learnersbase_learners = [ ('rf', RandomForestClassifier(n_estimators=50, random_state=42)), ('gb', GradientBoostingClassifier(n_estimators=50, random_state=42))]# Prediksi dari base learners menggunakan cross-validationmeta_features_train = []for name, model in base_learners: pred = cross_val_predict(model, X_train, y_train, cv=5, method='predict_proba') meta_features_train.append(pred[:, 1]) # Ambil probabilitas kelas 1X_meta_train = np.column_stack(meta_features_train)# Train meta-learnermeta_learner = LogisticRegression(random_state=42)meta_learner.fit(X_meta_train, y_train)# Prediksi pada test setmeta_features_test = []for name, model in base_learners: model.fit(X_train, y_train) pred = model.predict_proba(X_test) meta_features_test.append(pred[:, 1])X_meta_test = np.column_stack(meta_features_test)y_pred_stacking = meta_learner.predict(X_meta_test)acc_stacking = np.mean(y_pred_stacking == y_test)print(f"Stacking Accuracy: {acc_stacking:.4f}")# Bandingkan dengan base learners individualfor name, model in base_learners: model.fit(X_train, y_train) acc = model.score(X_test, y_test)print(f"{name.upper()} Accuracy: {acc:.4f}")
4.6 Comprehensive Model Evaluation
4.6.1 Metrics untuk Klasifikasi
Classification Metrics Taxonomy
Dari Confusion Matrix:
Accuracy: Akurasi overall
Precision: Dari prediksi positif, berapa yang benar?
Recall: Dari kasus positif, berapa yang terdeteksi?
Specificity: Dari kasus negatif, berapa yang terdeteksi?
from sklearn.model_selection import GridSearchCV# DataX, y = make_classification(n_samples=300, n_features=10, n_informative=5, n_classes=2, random_state=42)X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)# Hyperparameter grid untuk Random Forestparam_grid = {'n_estimators': [50, 100, 200],'max_depth': [3, 5, 7, None],'min_samples_split': [2, 5, 10]}# GridSearchCV dengan stratified k-foldrf = RandomForestClassifier(random_state=42)grid_search = GridSearchCV( rf, param_grid, cv=5, scoring='f1', # atau 'roc_auc' untuk imbalanced data n_jobs=-1)grid_search.fit(X_train, y_train)print(f"Best parameters: {grid_search.best_params_}")print(f"Best CV F1 Score: {grid_search.best_score_:.4f}")print(f"Test F1 Score: {grid_search.score(X_test, y_test):.4f}")
4.9 Model Evaluation Checklist
10-Point Evaluation Checklist
Data Leakage: Pastikan tidak ada informasi dari test set ke training
Cross-Validation: Gunakan k-fold bukan hanya single train-test split
Stratification: Untuk klasifikasi imbalanced, gunakan stratified k-fold
Baseline Model: Bandingkan dengan simple baseline
Multiple Metrics: Jangan hanya akurasi; gunakan precision, recall, F1, AUC
Threshold Tuning: Cari threshold optimal untuk use case
Feature Importance: Pahami fitur mana yang penting
Error Analysis: Analisis kesalahan model untuk perbaikan
Hyperparameter Tuning: Gunakan GridSearchCV atau RandomizedSearchCV
Final Validation: Validasi dengan truly held-out test set
4.10 Review Questions
Pertanyaan Konseptual:
Jelaskan mengapa ensemble methods biasanya lebih baik dari single models?
Perbedaan antara Bagging dan Boosting dalam hal training strategy?
Kapan precision dan kapan recall lebih penting?
Apa masalah utama dengan imbalanced datasets dan bagaimana mengatasi?
Mengapa class weights lebih baik dari oversampling pada dataset besar?
Pertanyaan Praktis:
Anda membangun model klasifikasi untuk deteksi fraud (hanya 0.1% data adalah fraud). Model Anda mencapai 99.9% accuracy. Apakah ini model yang baik? Metric apa yang lebih informatif?
Jelaskan perbedaan antara precision = 0.9 dan recall = 0.9. Manakah yang lebih penting untuk: (a) email spam detection, (b) cancer diagnosis, (c) bank loan approval?
Anda menjalankan GridSearchCV dengan 100 parameter combinations, 5-fold CV, dan data dengan 10,000 samples. Berapa total model yang akan dilatih? Apakah ini efisien?
ROC-AUC = 0.95 terdengar sempurna, tapi Precision-Recall AUC = 0.3. Bagaimana ini mungkin? Kapan ini bisa terjadi?
Anda telah mengoptimalkan hyperparameters dengan GridSearchCV pada training set, dan mendapatkan akurasi test 95%. Namun di production, akurasi turun menjadi 70%. Apa yang mungkin penyebabnya dan bagaimana mendiagnosis?
4.11 Hands-On Exercise
End-to-End Classification Project:
Dataset: Gunakan dataset imbalanced (misal fraud detection atau loan default)
Exploratory Analysis: Pahami imbalance ratio dan fitur
Preprocessing: Handle missing values, scale features
Baseline Model: Train logistic regression dengan default threshold
Ensemble Models: Train Random Forest, Gradient Boosting, Stacking
Evaluation:
5-fold stratified CV
Plot ROC curves untuk semua models
Hitung precision, recall, F1, AUC
Optimization:
GridSearchCV untuk best hyperparameters
Threshold tuning untuk business requirements
Handle class imbalance dengan SMOTE atau class_weight
Final Comparison: Pilih model terbaik dengan justifikasi jelas
Tips:
Jangan forget data leakage!
Dokumentasikan setiap keputusan
Visualisasi hasil (confusion matrix, ROC curve, feature importance)
🎯 Key Takeaways
✅ Ensemble methods meningkatkan performa dengan menggabungkan banyak models, mengurangi variance tanpa menambah bias
✅ Bagging (Random Forest) mengurangi variance melalui bootstrap sampling dan agregasi, dengan OOB estimation untuk validasi efisien
✅ Boosting (AdaBoost, Gradient Boosting, XGBoost) melatih models secara sequential untuk fokus pada sampel yang sulit
✅ Stacking menggunakan meta-learner untuk mengoptimalkan kombinasi prediksi dari diverse base learners
✅ Bias-Variance Tradeoff adalah konsep fundamental: underfitting (high bias), overfitting (high variance), ensemble helps balance keduanya
✅ Metrics selection harus sesuai context: accuracy untuk balanced, F1/ROC-AUC untuk imbalanced, precision untuk minimizing false positives, recall untuk minimizing false negatives
✅ Class imbalance memerlukan strategi khusus: resampling, SMOTE, class weights, atau threshold adjustment
✅ Cross-validation dengan stratified k-fold memberikan estimasi performa yang lebih reliable dan mencegah overfitting
✅ Hyperparameter tuning dengan GridSearchCV atau RandomizedSearchCV mengoptimalkan model secara sistematis
✅ Feature importance dari ensemble models memberikan insights untuk feature selection dan interpretability
# Bab 4: Ensemble Methods dan Evaluasi Model {#ch-ensemble-eval}::: {.callout-note}## 🎯 Hasil Pembelajaran (Learning Outcomes)Setelah mempelajari bab ini, Anda akan mampu:1. **Memahami** prinsip ensemble learning dan mengapa banyak model lebih baik dari satu model2. **Menjelaskan** bias-variance tradeoff dan cara ensemble methods mengurangi variance3. **Mengimplementasi** berbagai ensemble techniques: Bagging, Boosting, Stacking4. **Menghitung** metrik evaluasi komprehensif: akurasi, precision, recall, F1-score, ROC-AUC5. **Menangani** class imbalance dan memilih metric yang tepat untuk business context6. **Optimalkan** model menggunakan GridSearchCV dan hyperparameter tuning secara sistematis:::## 4.1 Pengantar: Kekuatan Kolaborasi"Kebijaksanaan kerumunan" - ide bahwa banyak predictor sederhana yang dikombinasikan menghasilkan predictor yang lebih baik daripada predictor individual.Ensemble learning adalah teknik yang menggabungkan banyak model untuk mencapai performa superior. Ide sederhananya:- **Keragaman** (Diversity): Model harus berbeda satu sama lain- **Ketepatan** (Accuracy): Setiap model harus lebih baik dari random guessing- **Kemerdekaan** (Independence): Kesalahan model tidak boleh berkorelasi sempurna$$\text{Ensemble Error} = \text{Bias} + \text{Variance} + \text{Error}$$Ensemble methods mengurangi variance sambil mempertahankan bias rendah.## 4.2 Prinsip Ensemble Learning### 4.2.1 Bias-Variance DecompositionSetiap prediksi memiliki dua sumber error:- **Bias**: Error dari model yang terlalu sederhana (underfitting)- **Variance**: Error dari model yang terlalu kompleks (overfitting)```{python}import numpy as npimport matplotlib.pyplot as pltfrom sklearn.pipeline import Pipelinefrom sklearn.preprocessing import PolynomialFeaturesfrom sklearn.linear_model import LinearRegressionfrom sklearn.model_selection import cross_val_score# Buat data dengan true function: y = sin(x)np.random.seed(42)X_train = np.random.uniform(0, 2*np.pi, 20).reshape(-1, 1)y_train = np.sin(X_train.ravel()) + np.random.normal(0, 0.1, 20)X_test = np.linspace(0, 2*np.pi, 200).reshape(-1, 1)y_test = np.sin(X_test.ravel())# Models dengan berbagai complexitydegrees = [1, 3, 5, 10, 15]train_errors = []test_errors = []for d in degrees: model = Pipeline([ ('poly_features', PolynomialFeatures(degree=d)), ('linear_regression', LinearRegression()) ]) model.fit(X_train, y_train) train_error = np.mean((model.predict(X_train) - y_train) **2) test_error = np.mean((model.predict(X_test) - y_test) **2) train_errors.append(train_error) test_errors.append(test_error)print(f"Degree {d:2d}: Train Error = {train_error:.4f}, Test Error = {test_error:.4f}")# Visualisasi Bias-Variance Trade-offplt.figure(figsize=(10, 5))plt.plot(degrees, train_errors, 'o-', label='Training Error', linewidth=2, markersize=8)plt.plot(degrees, test_errors, 's-', label='Test Error (Generalization)', linewidth=2, markersize=8)plt.xlabel('Model Complexity (Polynomial Degree)', fontsize=12)plt.ylabel('Mean Squared Error', fontsize=12)plt.title('Bias-Variance Trade-off', fontsize=14, fontweight='bold')plt.legend(fontsize=11)plt.grid(True, alpha=0.3)plt.tight_layout()plt.show()print(f"\nUnderfitting: Low complexity models (degree 1-3)")print(f"Optimal: Medium complexity models (degree 3-5)")print(f"Overfitting: High complexity models (degree 10+)")```## 4.3 Bagging (Bootstrap Aggregating)Bagging mengurangi variance dengan melatih banyak model pada bootstrap samples dari data.**Algoritma:**1. Buat B bootstrap samples dari training data2. Latih base learner pada setiap sample3. Agregasi prediksi semua modelsUntuk **klasifikasi**: voting mayoritasUntuk **regresi**: rata-rata prediksi### 4.3.1 Out-of-Bag (OOB) Error EstimationBootstrap sample rata-rata mengandung ~63.2% unique samples. Sisanya (Out-of-Bag) bisa digunakan untuk validasi tanpa perlu test set terpisah.```{python}from sklearn.ensemble import BaggingClassifierfrom sklearn.tree import DecisionTreeClassifierfrom sklearn.datasets import make_classification# DataX, y = make_classification(n_samples=300, n_features=10, n_informative=5, n_classes=2, random_state=42)# Bagging dengan OOB estimationbagging = BaggingClassifier( estimator=DecisionTreeClassifier(), n_estimators=50, oob_score=True, random_state=42)bagging.fit(X, y)print(f"OOB Score (unbiased estimate): {bagging.oob_score_:.4f}")print(f"Training Score: {bagging.score(X, y):.4f}")print(f"OOB diestimasi dari ~{int(300*0.632)} samples yang tidak digunakan")```### 4.3.2 Feature Importance dari Random ForestRandom Forest mengukur importance fitur berdasarkan pengurangan impurity rata-rata.```{python}from sklearn.ensemble import RandomForestClassifierfrom sklearn.datasets import load_breast_cancerimport pandas as pd# Datacancer = load_breast_cancer()X = cancer.datay = cancer.target# Train Random Forestrf = RandomForestClassifier(n_estimators=100, random_state=42)rf.fit(X, y)# Feature Importancefeature_importance = pd.DataFrame({'Feature': cancer.feature_names,'Importance': rf.feature_importances_}).sort_values('Importance', ascending=False)print("Top 10 Most Important Features:")print(feature_importance.head(10).to_string(index=False))# Visualisasi top 10import matplotlib.pyplot as plttop_10 = feature_importance.head(10)plt.figure(figsize=(10, 6))plt.barh(range(len(top_10)), top_10['Importance'].values)plt.yticks(range(len(top_10)), top_10['Feature'].values)plt.xlabel('Importance', fontsize=12)plt.title('Top 10 Feature Importance (Random Forest)', fontsize=14, fontweight='bold')plt.tight_layout()plt.show()```## 4.4 Boosting MethodsBoosting melatih models secara sequential, setiap model fokus pada sampel yang sulit dari model sebelumnya.### 4.4.1 AdaBoost (Adaptive Boosting)Adaptive Boosting meningkatkan bobot sampel yang salah klasifikasi.**Algoritma:**1. Mulai dengan bobot uniform untuk semua samples2. Latih weak learner3. Tingkatkan bobot sampel yang salah4. Ulangi untuk M iterasi5. Kombinasi dengan weighted majority voting```{python}from sklearn.ensemble import AdaBoostClassifierfrom sklearn.datasets import load_irisfrom sklearn.model_selection import train_test_split# Datairis = load_iris()X_train, X_test, y_train, y_test = train_test_split( iris.data, iris.target, test_size=0.2, random_state=42)# AdaBoost dengan Decision Tree sebagai base learneradaboost = AdaBoostClassifier( estimator=DecisionTreeClassifier(max_depth=1), # Weak learner n_estimators=50, learning_rate=1.0, random_state=42)adaboost.fit(X_train, y_train)train_acc = adaboost.score(X_train, y_train)test_acc = adaboost.score(X_test, y_test)print(f"AdaBoost Train Accuracy: {train_acc:.4f}")print(f"AdaBoost Test Accuracy: {test_acc:.4f}")print(f"Number of estimators: {len(adaboost.estimators_)}")```### 4.4.2 Gradient BoostingGradient Boosting melatih models secara sequential untuk memprediksi residual dari model sebelumnya.**Intuisi:**- Model 1: Prediksi awal (error besar)- Model 2: Prediksi residual dari Model 1- Model 3: Prediksi residual dari Model 1+2- ...dan seterusnya```{python}from sklearn.ensemble import GradientBoostingClassifier, GradientBoostingRegressorfrom sklearn.datasets import make_regression# Regression exampleX, y = make_regression(n_samples=200, n_features=10, n_informative=5, noise=10, random_state=42)X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)# Gradient Boosting Regressorgbr = GradientBoostingRegressor( n_estimators=100, learning_rate=0.1, max_depth=3, random_state=42)gbr.fit(X_train, y_train)train_r2 = gbr.score(X_train, y_train)test_r2 = gbr.score(X_test, y_test)print(f"Gradient Boosting Train R²: {train_r2:.4f}")print(f"Gradient Boosting Test R²: {test_r2:.4f}")# Feature importancefeature_importance = pd.DataFrame({'Feature': [f'Feature {i}'for i inrange(10)],'Importance': gbr.feature_importances_}).sort_values('Importance', ascending=False)print("\nTop 5 Feature Importance:")print(feature_importance.head(5).to_string(index=False))```### 4.4.3 XGBoost: Extreme Gradient BoostingXGBoost adalah implementasi yang dioptimalkan dan lebih cepat dari Gradient Boosting.```{python}# Catatan: Uncomment jika xgboost sudah terinstall# from xgboost import XGBClassifier## xgb = XGBClassifier(n_estimators=100, learning_rate=0.1, max_depth=3, random_state=42)# xgb.fit(X_train, y_train)## xgb_acc = xgb.score(X_test, y_test)# print(f"XGBoost Test Accuracy: {xgb_acc:.4f}")print("XGBoost memerlukan instalasi: pip install xgboost")print("Namun GradientBoosting dari sklearn sudah cukup untuk praktikum")```**Kapan menggunakan Boosting:**- Akurasi maksimal penting- Dataset besar- Interpretabilitas kurang penting- Waktu training bukan masalah::: {.callout-warning}## Warning: Boosting dan OverfittingBoosting bisa overfit jika:- Terlalu banyak iterasi (n_estimators)- Learning rate terlalu tinggi- Max depth terlalu besarGunakan early stopping dan validasi set!:::## 4.5 Stacking & Blending### 4.5.1 Stacking (Stacked Generalization)Stacking menggunakan meta-learner untuk mengkombinasikan prediksi dari base learners.**Proses:**1. Split data menjadi 3 bagian (train, validation, test)2. Latih base learners pada bagian train3. Prediksi pada bagian validation (features baru)4. Latih meta-learner pada prediksi validation5. Prediksi final dengan base learners dan meta-learner```{python}from sklearn.model_selection import cross_val_predictfrom sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifierfrom sklearn.linear_model import LogisticRegressionfrom sklearn.datasets import make_classification# DataX, y = make_classification(n_samples=400, n_features=20, n_informative=10, n_classes=2, random_state=42)X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)# Base learnersbase_learners = [ ('rf', RandomForestClassifier(n_estimators=50, random_state=42)), ('gb', GradientBoostingClassifier(n_estimators=50, random_state=42))]# Prediksi dari base learners menggunakan cross-validationmeta_features_train = []for name, model in base_learners: pred = cross_val_predict(model, X_train, y_train, cv=5, method='predict_proba') meta_features_train.append(pred[:, 1]) # Ambil probabilitas kelas 1X_meta_train = np.column_stack(meta_features_train)# Train meta-learnermeta_learner = LogisticRegression(random_state=42)meta_learner.fit(X_meta_train, y_train)# Prediksi pada test setmeta_features_test = []for name, model in base_learners: model.fit(X_train, y_train) pred = model.predict_proba(X_test) meta_features_test.append(pred[:, 1])X_meta_test = np.column_stack(meta_features_test)y_pred_stacking = meta_learner.predict(X_meta_test)acc_stacking = np.mean(y_pred_stacking == y_test)print(f"Stacking Accuracy: {acc_stacking:.4f}")# Bandingkan dengan base learners individualfor name, model in base_learners: model.fit(X_train, y_train) acc = model.score(X_test, y_test)print(f"{name.upper()} Accuracy: {acc:.4f}")```## 4.6 Comprehensive Model Evaluation### 4.6.1 Metrics untuk Klasifikasi::: {.callout-note}## Classification Metrics Taxonomy**Dari Confusion Matrix:**- Accuracy: Akurasi overall- Precision: Dari prediksi positif, berapa yang benar?- Recall: Dari kasus positif, berapa yang terdeteksi?- Specificity: Dari kasus negatif, berapa yang terdeteksi?- F1-Score: Harmonic mean precision dan recall**Threshold-Independent:**- ROC-AUC: Area under ROC curve- PR-AUC: Area under Precision-Recall curve- Log Loss: Cross-entropy loss**Multi-class:**- Macro F1: F1 rata-rata per kelas- Weighted F1: F1 weighted by support- One-vs-Rest: Evaluate per kelas:::```{python}from sklearn.metrics import (classification_report, roc_curve, auc, precision_recall_curve, confusion_matrix)# Binary classificationy_true = [0, 1, 1, 0, 1, 1, 0, 1, 0, 1]y_pred_prob = [0.1, 0.8, 0.7, 0.2, 0.9, 0.6, 0.3, 0.85, 0.15, 0.95]y_pred = [int(p >0.5) for p in y_pred_prob]# Comprehensive reportprint("Classification Report:")print(classification_report(y_true, y_pred, target_names=['Negative', 'Positive']))# ROC Curvefpr, tpr, thresholds = roc_curve(y_true, y_pred_prob)roc_auc = auc(fpr, tpr)print(f"\nROC-AUC Score: {roc_auc:.4f}")# Precision-Recall Curveprecision, recall, thresholds = precision_recall_curve(y_true, y_pred_prob)pr_auc = auc(recall, precision)print(f"PR-AUC Score: {pr_auc:.4f}")```### 4.6.2 Metrics untuk Regresi```{python}from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score# Regression predictionsy_true = [3.0, -0.5, 2.0, 7.0, 4.3, -2.0]y_pred = [2.5, 0.0, 2.0, 8.0, 4.0, -2.5]mae = mean_absolute_error(y_true, y_pred)mse = mean_squared_error(y_true, y_pred)rmse = np.sqrt(mse)r2 = r2_score(y_true, y_pred)print("Regression Metrics:")print(f" MAE (Mean Absolute Error): {mae:.4f}")print(f" MSE (Mean Squared Error): {mse:.4f}")print(f" RMSE (Root Mean Squared Error): {rmse:.4f}")print(f" R² Score: {r2:.4f}")# MAPE (Mean Absolute Percentage Error)mape = np.mean(np.abs((np.array(y_true) - np.array(y_pred)) / np.array(y_true))) *100print(f" MAPE (Mean Absolute % Error): {mape:.2f}%")```## 4.7 Menangani Class ImbalanceKetika kelas tidak seimbang (misal 95% negative, 5% positive), model cenderung memprioritaskan kelas mayoritas.### 4.7.1 Strategi Handling Imbalance**1. Resampling:**```{python}from sklearn.datasets import make_classificationfrom collections import Counter# Data dengan imbalanceX, y = make_classification(n_samples=1000, n_features=20, n_informative=10, weights=[0.9, 0.1], random_state=42)print(f"Original distribution: {Counter(y)}")# Oversampling (duplicate minority class)from sklearn.utils import resampleX_majority = X[y ==0]X_minority = X[y ==1]y_majority = y[y ==0]y_minority = y[y ==1]X_minority_upsampled, y_minority_upsampled = resample( X_minority, y_minority, n_samples=len(X_majority), random_state=42)X_balanced = np.vstack([X_majority, X_minority_upsampled])y_balanced = np.hstack([y_majority, y_minority_upsampled])print(f"After oversampling: {Counter(y_balanced)}")```**2. SMOTE (Synthetic Minority Over-sampling):**```{python}# from imblearn.over_sampling import SMOTE## smote = SMOTE(random_state=42)# X_smote, y_smote = smote.fit_resample(X, y)# print(f"After SMOTE: {Counter(y_smote)}")print("SMOTE tersedia di: pip install imbalanced-learn")```**3. Class Weight:**```{python}from sklearn.utils.class_weight import compute_class_weight# Hitung class weights otomatisclass_weights = compute_class_weight('balanced', classes=np.unique(y), y=y)print(f"Class weights: {class_weights}")# Gunakan dalam modelrf_balanced = RandomForestClassifier( n_estimators=100, class_weight='balanced', # atau dictionary: {0: weight0, 1: weight1} random_state=42)rf_balanced.fit(X, y)print(f"Balanced RF Accuracy: {rf_balanced.score(X, y):.4f}")```**4. Threshold Adjustment:**```{python}from sklearn.metrics import precision_recall_curve# Ubah decision thresholdy_pred_proba = rf_balanced.predict_proba(X)[:, 1]# Default threshold = 0.5y_pred_default = (y_pred_proba >0.5).astype(int)# Adjusted threshold = 0.3 (lebih sensitif mendeteksi minority)y_pred_adjusted = (y_pred_proba >0.3).astype(int)from sklearn.metrics import recall_scoreprint(f"Recall dengan threshold 0.5: {recall_score(y, y_pred_default):.4f}")print(f"Recall dengan threshold 0.3: {recall_score(y, y_pred_adjusted):.4f}")```## 4.8 Best Practices untuk Model Selection```{python}from sklearn.model_selection import GridSearchCV# DataX, y = make_classification(n_samples=300, n_features=10, n_informative=5, n_classes=2, random_state=42)X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)# Hyperparameter grid untuk Random Forestparam_grid = {'n_estimators': [50, 100, 200],'max_depth': [3, 5, 7, None],'min_samples_split': [2, 5, 10]}# GridSearchCV dengan stratified k-foldrf = RandomForestClassifier(random_state=42)grid_search = GridSearchCV( rf, param_grid, cv=5, scoring='f1', # atau 'roc_auc' untuk imbalanced data n_jobs=-1)grid_search.fit(X_train, y_train)print(f"Best parameters: {grid_search.best_params_}")print(f"Best CV F1 Score: {grid_search.best_score_:.4f}")print(f"Test F1 Score: {grid_search.score(X_test, y_test):.4f}")```## 4.9 Model Evaluation Checklist::: {.callout-tip}## 10-Point Evaluation Checklist1. **Data Leakage**: Pastikan tidak ada informasi dari test set ke training2. **Cross-Validation**: Gunakan k-fold bukan hanya single train-test split3. **Stratification**: Untuk klasifikasi imbalanced, gunakan stratified k-fold4. **Baseline Model**: Bandingkan dengan simple baseline5. **Multiple Metrics**: Jangan hanya akurasi; gunakan precision, recall, F1, AUC6. **Threshold Tuning**: Cari threshold optimal untuk use case7. **Feature Importance**: Pahami fitur mana yang penting8. **Error Analysis**: Analisis kesalahan model untuk perbaikan9. **Hyperparameter Tuning**: Gunakan GridSearchCV atau RandomizedSearchCV10. **Final Validation**: Validasi dengan truly held-out test set:::## 4.10 Review Questions**Pertanyaan Konseptual:**1. Jelaskan mengapa ensemble methods biasanya lebih baik dari single models?2. Perbedaan antara Bagging dan Boosting dalam hal training strategy?3. Kapan precision dan kapan recall lebih penting?4. Apa masalah utama dengan imbalanced datasets dan bagaimana mengatasi?5. Mengapa class weights lebih baik dari oversampling pada dataset besar?**Pertanyaan Praktis:**6. Anda membangun model klasifikasi untuk deteksi fraud (hanya 0.1% data adalah fraud). Model Anda mencapai 99.9% accuracy. Apakah ini model yang baik? Metric apa yang lebih informatif?7. Jelaskan perbedaan antara precision = 0.9 dan recall = 0.9. Manakah yang lebih penting untuk: (a) email spam detection, (b) cancer diagnosis, (c) bank loan approval?8. Anda menjalankan GridSearchCV dengan 100 parameter combinations, 5-fold CV, dan data dengan 10,000 samples. Berapa total model yang akan dilatih? Apakah ini efisien?9. ROC-AUC = 0.95 terdengar sempurna, tapi Precision-Recall AUC = 0.3. Bagaimana ini mungkin? Kapan ini bisa terjadi?10. Anda telah mengoptimalkan hyperparameters dengan GridSearchCV pada training set, dan mendapatkan akurasi test 95%. Namun di production, akurasi turun menjadi 70%. Apa yang mungkin penyebabnya dan bagaimana mendiagnosis?## 4.11 Hands-On Exercise**End-to-End Classification Project:**1. **Dataset**: Gunakan dataset imbalanced (misal fraud detection atau loan default)2. **Exploratory Analysis**: Pahami imbalance ratio dan fitur3. **Preprocessing**: Handle missing values, scale features4. **Baseline Model**: Train logistic regression dengan default threshold5. **Ensemble Models**: Train Random Forest, Gradient Boosting, Stacking6. **Evaluation**: - 5-fold stratified CV - Plot ROC curves untuk semua models - Hitung precision, recall, F1, AUC7. **Optimization**: - GridSearchCV untuk best hyperparameters - Threshold tuning untuk business requirements - Handle class imbalance dengan SMOTE atau class_weight8. **Final Comparison**: Pilih model terbaik dengan justifikasi jelas**Tips:**- Jangan forget data leakage!- Dokumentasikan setiap keputusan- Visualisasi hasil (confusion matrix, ROC curve, feature importance)---## 🎯 Key Takeaways✅ **Ensemble methods** meningkatkan performa dengan menggabungkan banyak models, mengurangi variance tanpa menambah bias✅ **Bagging** (Random Forest) mengurangi variance melalui bootstrap sampling dan agregasi, dengan OOB estimation untuk validasi efisien✅ **Boosting** (AdaBoost, Gradient Boosting, XGBoost) melatih models secara sequential untuk fokus pada sampel yang sulit✅ **Stacking** menggunakan meta-learner untuk mengoptimalkan kombinasi prediksi dari diverse base learners✅ **Bias-Variance Tradeoff** adalah konsep fundamental: underfitting (high bias), overfitting (high variance), ensemble helps balance keduanya✅ **Metrics selection** harus sesuai context: accuracy untuk balanced, F1/ROC-AUC untuk imbalanced, precision untuk minimizing false positives, recall untuk minimizing false negatives✅ **Class imbalance** memerlukan strategi khusus: resampling, SMOTE, class weights, atau threshold adjustment✅ **Cross-validation** dengan stratified k-fold memberikan estimasi performa yang lebih reliable dan mencegah overfitting✅ **Hyperparameter tuning** dengan GridSearchCV atau RandomizedSearchCV mengoptimalkan model secara sistematis✅ **Feature importance** dari ensemble models memberikan insights untuk feature selection dan interpretability---