1. Pengenalan Random Forest
Random Forest adalah salah satu algoritma Machine Learning paling populer dan powerful yang masuk dalam kategori Ensemble Learning. Algoritma ini menggabungkan ratusan bahkan ribuan pohon keputusan (Decision Tree) untuk menghasilkan prediksi yang lebih stabil, akurat, dan generalizable dibandingkan satu pohon tunggal.
Ide dasar di balik Random Forest sangat elegan: jika satu pohon keputusan rentan terhadap overfitting, maka gabungan banyak pohon β yang masing-masing sedikit berbeda β akan menghasilkan prediksi yang jauh lebih robust. Ibaratnya, keputusan kelompok (wisdom of the crowd) lebih baik daripada keputusan satu individu.
Mengapa Random Forest Penting?
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β Popularitas Algoritma ML β β β β Random Forest ββββββββββββββββββββββββββββββββββββββββ 92% β β XGBoost βββββββββββββββββββββββββββββββββββββββ 90% β β Logistic Reg. βββββββββββββββββββββββββββββββββββββ 88% β β SVM ββββββββββββββββββββββββββββββ 75% β β Neural Network ββββββββββββββββββββββββββββββββββββ 85% β β KNN ββββββββββββββββββββ 52% β β Naive Bayes ββββββββββββββββββ 48% β β β β Sumber: Kaggle ML & Data Science Survey 2025 β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Sejarah Singkat
Random Forest diperkenalkan oleh Leo Breiman pada tahun 2001 dalam makalahnya yang berjudul "Random Forests". Breiman menggabungkan dua ide sebelumnya β bootstrap aggregation (bagging) yang ia kembangkan sendiri pada tahun 1996 dan random subspace method dari Tin Kam Ho (1998). Kombinasi ini menghasilkan algoritma yang tidak hanya akurat, tetapi juga relatif mudah digunakan dan diinterpretasikan.
Cocok untuk Masalah Apa?
| Jenis Masalah | Cocok? | Contoh |
|---|---|---|
| Klasifikasi (Binary) | β Sangat cocok | Spam vs Bukan Spam, Kredit Disetujui/Tolak |
| Klasifikasi (Multi-class) | β Sangat cocok | Jenis Iris, Kategori Sentimen |
| Regresi | β Cocok | Prediksi Harga Rumah, Estimasi Penjualan |
| Feature Selection | β Bagus | Menentukan fitur paling berpengaruh |
| Data Imbalanced | β οΈ Perlu penanganan khusus | Detect fraud (1% dari transaksi) |
| Time Series | β οΈ Bisa, tapi ada algoritma lebih spesifik | Prediksi stock price |
| Data Unstructured (Image/Text) | β Kurang cocok | Pengenalan wajah, NLP |
2. Review Decision Tree
Sebelum memahami Random Forest, penting untuk memahami Decision Tree (Pohon Keputusan) karena Random Forest dibangun dari banyak decision tree. Decision tree bekerja dengan membagi data secara rekursif berdasarkan fitur dan threshold terbaik.
Bagaimana Decision Tree Bekerja
βββββββββββββββββββββββ
β Pendapatan > 5jt? β
ββββββββ¬βββββββ¬ββββββββ
Ya / \ Tidak
/ \
βββββββββββββΌβββ ββββββΌβββββββββββ
β Usia > 25? β β Riwayat Kreditβ
ββββ¬ββββββββ¬ββββ β Bagus? β
Ya / \ Tidak ββββ¬βββββββββ¬ββββ
/ \ Ya / \ Tidak
ββββββββββΌβββ βββββββββΌββ ββΌβββββββββ ββΌβββββββββββ
β β
Setuju β β β οΈ Tinjauβ ββ
Setuju β ββ Ditolak β
β (Leaf) β β (Leaf) β β (Leaf) β β (Leaf) β
βββββββββββββ βββββββββββ βββββββββββ βββββββββββββ
Cara Decision Tree Memilih Split
Decision tree memilih split terbaik menggunakan metrik impurity (ketidakmurnian). Dua metrik utama yang digunakan:
| Metrik | Formula | Digunakan di | Penjelasan |
|---|---|---|---|
| Gini Impurity | Gini = 1 - Ξ£(pα΅’Β²) | CART (sklearn default) | Mengukur probabilitas salah klasifikasi |
| Entropy (Information Gain) | H = -Ξ£(pα΅’ Β· logβ(pα΅’)) | ID3, C4.5 | Mengukur ketidakpastian dalam data |
Contoh Perhitungan Gini Impurity
import numpy as np
def gini_impurity(labels):
"""Hitung Gini Impurity dari sebuah node."""
_, counts = np.unique(labels, return_counts=True)
probabilities = counts / counts.sum()
return 1 - np.sum(probabilities ** 2)
# Contoh: 10 data β 7 positif, 3 negatif
labels_node_a = np.array([1,1,1,1,1,1,1,0,0,0])
print(f"Gini Node A (7+, 3-): {gini_impurity(labels_node_a):.4f}")
# Output: Gini Node A (7+, 3-): 0.4200
# Contoh: node murni (semua sama)
labels_pure = np.array([1,1,1,1,1])
print(f"Gini Node Pure (5+, 0-): {gini_impurity(labels_pure):.4f}")
# Output: Gini Node Pure (5+, 0-): 0.0000
# Contoh: node campuran (50-50 β paling impure)
labels_mixed = np.array([1,1,1,0,0,0])
print(f"Gini Node Mixed (3+, 3-): {gini_impurity(labels_mixed):.4f}")
# Output: Gini Node Mixed (3+, 3-): 0.5000
Masalah Decision Tree Tunggal
Meskipun Decision Tree mudah dipahami dan divisualisasikan, pohon tunggal memiliki beberapa masalah serius:
- Overfitting β Pohon yang dalam bisa menghafal data training dengan sempurna, termasuk noise-nya, sehingga buruk pada data baru
- Variance tinggi β Perubahan kecil pada data bisa menghasilkan pohon yang sangat berbeda
- Instabilitas β Sensitif terhadap sedikit perubahan dalam data training
Bayangkan kamu bertanya ke 1 orang saja soal investasi β jawabannya mungkin bias. Tapi kalau kamu bertanya ke 1000 orang ahli yang masing-masing punya perspektif berbeda, dan mengambil rata-rata jawaban mereka, hasilnya jauh lebih dapat diandalkan. Ini prinsip dasar Random Forest!
3. Bagging (Bootstrap Aggregation)
Bagging (singkatan dari Bootstrap Aggregation) adalah teknik ensemble yang dikembangkan oleh Leo Breiman pada tahun 1996. Bagging adalah fondasi utama dari Random Forest.
Bagaimana Bagging Bekerja
βββββββββββββββ
β Dataset β
β Asli (N β
β samples) β
ββββββββ¬βββββββ
β
β Bootstrap Sampling (sampling dengan replacement)
β
ββββββ΄βββββ¬βββββββββββββ¬βββββββββββββ
βΌ βΌ βΌ βΌ
ββββββββ ββββββββ ββββββββ ββββββββ
βBoot- β βBoot- β βBoot- β βBoot- β
βstrap β βstrap β βstrap β βstrap β
βSampleβ βSampleβ βSampleβ βSampleβ
β #1 β β #2 β β #3 β β #B β
ββββ¬ββββ ββββ¬ββββ ββββ¬ββββ ββββ¬ββββ
βΌ βΌ βΌ βΌ
ββββββββ ββββββββ ββββββββ ββββββββ
βTree β βTree β βTree β βTree β
β #1 β β #2 β β #3 β β #B β
ββββ¬ββββ ββββ¬ββββ ββββ¬ββββ ββββ¬ββββ
β β β β
βΌ βΌ βΌ βΌ
ββββββββββββββββββββββββββββββββββ
β VOTING (Klasifikasi): β
β Kelas mayoritas menang β
β β
β AVERAGING (Regresi): β
β Rata-rata semua prediksi β
βββββββββββββββββ¬βββββββββββββββββ
βΌ
βββββββββββββββ
β FINAL β
β PREDICTION β
βββββββββββββββ
Apa Itu Bootstrap Sampling?
Bootstrap sampling adalah teknik sampling di mana kita mengambil N sampel dari dataset asli (yang juga berisi N sampel) dengan replacement (dengan pengembalian). Artinya, satu data point bisa muncul lebih dari sekali dalam satu bootstrap sample.
Secara matematis, probabilitas suatu data point tidak terpilih dalam satu bootstrap sample adalah:
P(tidak terpilih) = (1 - 1/N)βΏ β 1/e β 0.368
Artinya, sekitar 63.2% data akan muncul dalam setiap bootstrap sample, dan sekitar 36.8% data tidak akan terpilih. Data yang tidak terpilih ini disebut Out-of-Bag (OOB) data dan bisa digunakan untuk validasi!
Contoh Bootstrap Sampling
import numpy as np
# Dataset asli: 8 data points
dataset = np.array([0, 1, 2, 3, 4, 5, 6, 7])
N = len(dataset)
print(f"Dataset asli: {dataset}")
print(f"Jumlah data: {N}")
np.random.seed(42)
# Bootstrap sample: sampling dengan replacement
bootstrap_indices = np.random.choice(N, size=N, replace=True)
bootstrap_sample = dataset[bootstrap_indices]
print(f"\nBootstrap sample: {bootstrap_sample}")
print(f"Indices yang dipilih: {bootstrap_indices}")
# Identifikasi OOB (Out-of-Bag) data
oob_mask = np.ones(N, dtype=bool)
oob_mask[bootstrap_indices] = False
oob_data = dataset[oob_mask]
print(f"\nOOB data (tidak terpilih): {oob_data}")
print(f"Jumlah OOB: {len(oob_data)} ({len(oob_data)/N*100:.1f}%)")
print(f"Data terpilih: {N - len(oob_data)} ({(N-len(oob_data))/N*100:.1f}%)")
# Demo: bandingkan beberapa bootstrap sample
print("\n--- 5 Bootstrap Sample Berbeda ---")
for i in range(5):
idx = np.random.choice(N, size=N, replace=True)
sample = dataset[idx]
unique = np.unique(sample)
print(f"Sample {i+1}: {sample} β {len(unique)} data unik dari {N}")
Out-of-Bag (OOB) Evaluation
Salah satu keunggulan bagging adalah adanya OOB evaluation. Karena setiap tree hanya dilatih pada bootstrap sample-nya sendiri (~63.2% data), sisa ~36.8% data (OOB) tidak digunakan saat training tree tersebut. Kita bisa menggunakan data OOB sebagai validation set tanpa perlu memisahkan data secara manual!
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import make_classification
from sklearn.metrics import accuracy_score, classification_report
from sklearn.model_selection import train_test_split
# Generate dataset
X, y = make_classification(
n_samples=1000,
n_features=20,
n_informative=15,
n_redundant=3,
random_state=42
)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
# Random Forest DENGAN OOB scoring
rf_with_oob = RandomForestClassifier(
n_estimators=100,
oob_score=True, # Aktifkan OOB scoring
random_state=42,
n_jobs=-1
)
rf_with_oob.fit(X_train, y_train)
print("=== OOB Evaluation ===")
print(f"OOB Score: {rf_with_oob.oob_score_:.4f}")
# Bandingkan dengan test set
y_pred = rf_with_oob.predict(X_test)
test_accuracy = accuracy_score(y_test, y_pred)
print(f"Test Score: {test_accuracy:.4f}")
print(f"\nSelisih: {abs(rf_with_oob.oob_score_ - test_accuracy):.4f}")
# Selisih biasanya kecil β OOB score β cross-validation score!
4. Cara Kerja Random Forest
Random Forest menggabungkan bagging dengan tambahan elemen kunci: random feature selection pada setiap split pohon. Inilah yang membedakannya dari bagging biasa.
Langkah-Langkah Random Forest
- Bootstrap Sampling β Buat B bootstrap sample dari dataset asli (B = jumlah tree, biasanya 100-1000)
- Grow Decision Tree β Untuk setiap bootstrap sample, tumbuhkan decision tree penuh (tanpa pruning)
- Random Feature Selection β Pada setiap node split, pilih subset fitur secara acak (biasanya βp untuk klasifikasi, p/3 untuk regresi, di mana p = jumlah total fitur)
- Vote/Average β Klasifikasi: mayoritas voting. Regresi: rata-rata prediksi
BAGGING BIASA: RANDOM FOREST:
Bootstrap Sample #1 βββΊ Tree #1 Bootstrap Sample #1 βββΊ Tree #1
(semua fitur tersedia) (random subset fitur per split)
Bootstrap Sample #2 βββΊ Tree #2 Bootstrap Sample #2 βββΊ Tree #2
(semua fitur tersedia) (random subset fitur per split)
Bootstrap Sample #3 βββΊ Tree #3 Bootstrap Sample #3 βββΊ Tree #3
(semua fitur tersedia) (random subset fitur per split)
... ...
KELEMAHAN: KEUNGGULAN:
Jika ada fitur dominan, Setiap tree "melihat" fitur
semua tree akan menggunakan berbeda β mengurangi korelasi
fitur tersebut β tree korelasi antar tree β generalisasi lebih baik
Mengapa Random Feature Selection Penting?
Tanpa random feature selection (hanya bagging), jika ada satu fitur yang sangat kuat, hampir semua tree akan memilih fitur tersebut di root node. Akibatnya, tree-tree tersebut akan sangat mirip (korelasi tinggi), dan manfaat ensemble berkurang drastis.
Dengan random feature selection, setiap tree dipaksa "melihat" subset fitur yang berbeda. Ini memaksa tree untuk menemukan pola menggunakan berbagai kombinasi fitur, sehingga tree menjadi lebih beragam (uncorrelated) dan ensemble menjadi lebih kuat.
| Parameter | Klasifikasi | Regresi | Penjelasan |
|---|---|---|---|
| max_features (default sklearn) | sqrt(n_features) | n_features (semua) | Jumlah fitur yang dipertimbangkan per split |
| max_features (recommended) | sqrt atau log2 | n_features/3 | Rule of thumb dari Breiman |
| Jumlah tree (n_estimators) | 100-1000 | 100-1000 | Lebih banyak tree = lebih stabil (tapi ada batas diminishing return) |
| Kedalaman pohon | Tanpa batas (penuh) | Tanpa batas (penuh) | Biarkan tree tumbuh penuh; kombinasi banyak tree akan mengurangi overfitting |
Visualisasi Proses
import numpy as np
import matplotlib.pyplot as plt
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import make_moons
from sklearn.model_selection import train_test_split
# Dataset: two moons (non-linear boundary)
X, y = make_moons(n_samples=500, noise=0.3, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
# Random Forest dengan 5 trees saja (untuk visualisasi)
rf_small = RandomForestClassifier(n_estimators=5, random_state=42)
rf_small.fit(X_train, y_train)
fig, axes = plt.subplots(2, 3, figsize=(15, 10))
# Plot 5 individual trees
for i, tree in enumerate(rf_small.estimators_):
ax = axes[i // 3, i % 3]
xx, yy = np.meshgrid(
np.linspace(X[:, 0].min()-0.5, X[:, 0].max()+0.5, 200),
np.linspace(X[:, 1].min()-0.5, X[:, 1].max()+0.5, 200)
)
Z = tree.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
ax.contourf(xx, yy, Z, alpha=0.3, cmap='RdYlBu')
ax.scatter(X_train[:, 0], X_train[:, 1], c=y_train, cmap='RdYlBu',
edgecolors='k', s=20)
ax.set_title(f'Tree #{i+1} (acc: {tree.score(X_test, y_test):.2f})')
# Plot final ensemble prediction
ax = axes[1, 2]
Z_rf = rf_small.predict(np.c_[xx.ravel(), yy.ravel()])
Z_rf = Z_rf.reshape(xx.shape)
ax.contourf(xx, yy, Z_rf, alpha=0.3, cmap='RdYlBu')
ax.scatter(X_train[:, 0], X_train[:, 1], c=y_train, cmap='RdYlBu',
edgecolors='k', s=20)
ax.set_title(f'Ensemble (acc: {rf_small.score(X_test, y_test):.2f})')
plt.suptitle('Random Forest: 5 Trees β 1 Ensemble', fontsize=14)
plt.tight_layout()
plt.show()
5. Feature Importance
Salah satu keunggulan terbesar Random Forest adalah kemampuannya memberikan feature importance β mengukur seberapa penting setiap fitur dalam membuat prediksi. Ini sangat berharga untuk interpretabilitas dan feature selection.
Jenis Feature Importance
| Metode | Penjelasan | Kelebihan | Kekurangan |
|---|---|---|---|
| Mean Decrease Impurity (MDI) | Total penurunan Gini/entropy yang dibawa oleh setiap fitur di seluruh tree | Cepat, dihitung saat training | Bias terhadap fitur kardinalitas tinggi |
| Mean Decrease Accuracy (MDA) | Penurunan akurasi saat fitur di-shuffle secara acak (permutation importance) | Lebih unbiased | Lebih lambat, butuh validasi set |
| SHAP Values | Nilai kontribusi setiap fitur berdasarkan game theory (Shapley value) | Interpretasi per-instance, shapely | Computational cost tinggi |
Contoh Feature Importance dengan Scikit-learn
import numpy as np
import matplotlib.pyplot as plt
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
# Load dataset breast cancer
data = load_breast_cancer()
X, y = data.data, data.target
feature_names = data.feature_names
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
# Train Random Forest
rf = RandomForestClassifier(
n_estimators=500,
random_state=42,
n_jobs=-1
)
rf.fit(X_train, y_train)
print(f"Test Accuracy: {rf.score(X_test, y_test):.4f}")
# === 1. MDI Feature Importance (Gini Importance) ===
importances_mdi = rf.feature_importances_
indices_mdi = np.argsort(importances_mdi)[::-1]
print("\n=== MDI Feature Importance (Top 10) ===")
for i in range(10):
print(f" {i+1}. {feature_names[indices_mdi[i]]}: {importances_mdi[indices_mdi[i]]:.4f}")
# Visualisasi
fig, axes = plt.subplots(1, 2, figsize=(16, 6))
# MDI Importance
axes[0].barh(range(10), importances_mdi[indices_mdi[:10]][::-1])
axes[0].set_yticks(range(10))
axes[0].set_yticklabels([feature_names[i] for i in indices_mdi[:10]][::-1])
axes[0].set_title('MDI Feature Importance (Gini)')
axes[0].set_xlabel('Importance')
# === 2. Permutation Importance ===
from sklearn.inspection import permutation_importance
perm_importance = permutation_importance(
rf, X_test, y_test, n_repeats=10, random_state=42, n_jobs=-1
)
indices_perm = np.argsort(perm_importance.importances_mean)[::-1]
print("\n=== Permutation Feature Importance (Top 10) ===")
for i in range(10):
print(f" {i+1}. {feature_names[indices_perm[i]]}: "
f"{perm_importance.importances_mean[indices_perm[i]]:.4f} "
f"Β± {perm_importance.importances_std[indices_perm[i]]:.4f}")
axes[1].barh(range(10), perm_importance.importances_mean[indices_perm[:10]][::-1])
axes[1].set_yticks(range(10))
axes[1].set_yticklabels([feature_names[i] for i in indices_perm[:10]][::-1])
axes[1].set_title('Permutation Feature Importance')
axes[1].set_xlabel('Mean Accuracy Decrease')
plt.tight_layout()
plt.show()
- MDI importance bisa menyesatkan jika ada fitur dengan banyak kategori (high cardinality), karena fitur tersebut memiliki lebih banyak kesempatan untuk di-split
- Permutation importance lebih reliable karena tidak bergantung pada struktur pohon
- Untuk analisis lebih mendalam, gunakan SHAP (SHapley Additive exPlanations) β tersedia di library
shap
6. Implementasi dengan Scikit-learn
Sekarang kita akan melihat implementasi lengkap Random Forest untuk masalah klasifikasi menggunakan scikit-learn. Kita akan mencakup preprocessing, training, evaluasi, dan visualisasi.
Contoh Lengkap: Klasifikasi Kanker Payudara
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import (
train_test_split, cross_val_score,
StratifiedKFold, learning_curve
)
from sklearn.metrics import (
accuracy_score, precision_score, recall_score,
f1_score, roc_auc_score, confusion_matrix,
classification_report, roc_curve
)
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
import warnings
warnings.filterwarnings('ignore')
# =============================================
# 1. LOAD & PERSIAPAN DATA
# =============================================
data = load_breast_cancer()
X = pd.DataFrame(data.data, columns=data.feature_names)
y = pd.Series(data.target, name='target')
print("=" * 60)
print("DATASET BREAST CANCER")
print("=" * 60)
print(f"Jumlah samples: {X.shape[0]}")
print(f"Jumlah fitur: {X.shape[1]}")
print(f"Kelas: {dict(zip(data.target_names, np.bincount(y)))}")
print(f"\n5 baris pertama:")
print(X.head())
# Train-test split
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42, stratify=y
)
print(f"\nTrain size: {X_train.shape[0]}")
print(f"Test size: {X_test.shape[0]}")
# =============================================
# 2. TRAINING RANDOM FOREST
# =============================================
rf_model = RandomForestClassifier(
n_estimators=300, # Jumlah tree
max_features='sqrt', # Fitur per split (sqrt untuk klasifikasi)
max_depth=None, # Tanpa batas kedalaman
min_samples_split=2, # Minimum sample untuk split
min_samples_leaf=1, # Minimum sample di leaf
bootstrap=True, # Gunakan bootstrap
oob_score=True, # Aktifkan OOB scoring
random_state=42,
n_jobs=-1, # Gunakan semua CPU core
class_weight='balanced' # Handle class imbalance
)
rf_model.fit(X_train, y_train)
# =============================================
# 3. EVALUASI MODEL
# =============================================
y_pred = rf_model.predict(X_test)
y_prob = rf_model.predict_proba(X_test)[:, 1]
print("\n" + "=" * 60)
print("EVALUASI MODEL")
print("=" * 60)
print(f"OOB Score: {rf_model.oob_score_:.4f}")
print(f"Test Accuracy: {accuracy_score(y_test, y_pred):.4f}")
print(f"Precision: {precision_score(y_test, y_pred):.4f}")
print(f"Recall: {recall_score(y_test, y_pred):.4f}")
print(f"F1-Score: {f1_score(y_test, y_pred):.4f}")
print(f"ROC AUC: {roc_auc_score(y_test, y_prob):.4f}")
print(f"\nClassification Report:")
print(classification_report(y_test, y_pred, target_names=data.target_names))
# =============================================
# 4. CROSS VALIDATION
# =============================================
cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
cv_scores = cross_val_score(rf_model, X, y, cv=cv, scoring='accuracy')
print("=" * 60)
print("CROSS VALIDATION (5-Fold)")
print("=" * 60)
print(f"Scores: {cv_scores}")
print(f"Mean: {cv_scores.mean():.4f} Β± {cv_scores.std():.4f}")
# =============================================
# 5. VISUALISASI
# =============================================
fig, axes = plt.subplots(2, 2, figsize=(14, 12))
# 5a. Confusion Matrix
cm = confusion_matrix(y_test, y_pred)
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues',
xticklabels=data.target_names,
yticklabels=data.target_names, ax=axes[0, 0])
axes[0, 0].set_title('Confusion Matrix')
axes[0, 0].set_xlabel('Prediksi')
axes[0, 0].set_ylabel('Aktual')
# 5b. ROC Curve
fpr, tpr, _ = roc_curve(y_test, y_prob)
axes[0, 1].plot(fpr, tpr, 'b-', linewidth=2,
label=f'RF (AUC = {roc_auc_score(y_test, y_prob):.3f})')
axes[0, 1].plot([0, 1], [0, 1], 'k--', alpha=0.5)
axes[0, 1].set_title('ROC Curve')
axes[0, 1].set_xlabel('False Positive Rate')
axes[0, 1].set_ylabel('True Positive Rate')
axes[0, 1].legend()
# 5c. Feature Importance (Top 15)
importances = rf_model.feature_importances_
indices = np.argsort(importances)[::-1][:15]
axes[1, 0].barh(range(15), importances[indices][::-1])
axes[1, 0].set_yticks(range(15))
axes[1, 0].set_yticklabels([data.feature_names[i] for i in indices][::-1])
axes[1, 0].set_title('Top 15 Feature Importance')
# 5d. Learning Curve
train_sizes, train_scores, val_scores = learning_curve(
rf_model, X_train, y_train, cv=5,
train_sizes=np.linspace(0.1, 1.0, 10),
scoring='accuracy', n_jobs=-1
)
axes[1, 1].plot(train_sizes, train_scores.mean(axis=1), 'o-', label='Training')
axes[1, 1].plot(train_sizes, val_scores.mean(axis=1), 'o-', label='Validation')
axes[1, 1].fill_between(train_sizes,
train_scores.mean(axis=1) - train_scores.std(axis=1),
train_scores.mean(axis=1) + train_scores.std(axis=1), alpha=0.2)
axes[1, 1].fill_between(train_sizes,
val_scores.mean(axis=1) - val_scores.std(axis=1),
val_scores.mean(axis=1) + val_scores.std(axis=1), alpha=0.2)
axes[1, 1].set_title('Learning Curve')
axes[1, 1].set_xlabel('Training Set Size')
axes[1, 1].set_ylabel('Accuracy')
axes[1, 1].legend()
plt.suptitle('Random Forest β Analisis Hasil', fontsize=14, y=1.02)
plt.tight_layout()
plt.show()
7. Hyperparameter Tuning
Random Forest memiliki banyak hyperparameter yang bisa dioptimasi. Pemahaman yang baik tentang hyperparameter ini akan membantu mendapatkan performa terbaik dari model.
Daftar Hyperparameter Penting
| Hyperparameter | Default | Rekomendasi | Pengaruh |
|---|---|---|---|
n_estimators | 100 | 100-1000 | Jumlah tree. Semakin banyak = lebih stabil, lebih lambat. Diminishing return setelah ~300 |
max_depth | None | 10-30 atau None | Kedalaman max tree. None = tree tumbuh penuh |
max_features | sqrt (klasifikasi) | sqrt, log2, 0.3 | Jumlah fitur per split. Lebih kecil = tree lebih beragam |
min_samples_split | 2 | 2-10 | Minimum sample untuk melakukan split |
min_samples_leaf | 1 | 1-5 | Minimum sample di leaf node |
bootstrap | True | True | Gunakan bootstrap sampling atau tidak |
class_weight | None | 'balanced' | Bobot kelas untuk data imbalanced |
RandomizedSearchCV vs GridSearchCV
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import RandomizedSearchCV, GridSearchCV
from scipy.stats import randint, uniform
import numpy as np
# Dataset
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
X, y = load_breast_cancer(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
# =============================================
# 1. RANDOMIZED SEARCH (Lebih cepat, recommended)
# =============================================
param_distributions = {
'n_estimators': randint(100, 500),
'max_depth': [None, 10, 15, 20, 30],
'max_features': ['sqrt', 'log2', 0.2, 0.3, 0.5],
'min_samples_split': randint(2, 15),
'min_samples_leaf': randint(1, 10),
'class_weight': [None, 'balanced', 'balanced_subsample']
}
rf_random = RandomizedSearchCV(
estimator=RandomForestClassifier(random_state=42),
param_distributions=param_distributions,
n_iter=100, # 100 kombinasi random
cv=5,
scoring='f1_weighted',
random_state=42,
n_jobs=-1,
verbose=1
)
rf_random.fit(X_train, y_train)
print("=" * 60)
print("RANDOMIZED SEARCH RESULTS")
print("=" * 60)
print(f"Best Score (CV): {rf_random.best_score_:.4f}")
print(f"Best Parameters:")
for param, value in rf_random.best_params_.items():
print(f" {param}: {value}")
best_rf = rf_random.best_estimator_
print(f"Test Accuracy: {best_rf.score(X_test, y_test):.4f}")
# =============================================
# 2. GRID SEARCH (Lebih teliti, lebih lambat)
# =============================================
# Hanya setelahRandomizedSearch menemukan range yang bagus
param_grid = {
'n_estimators': [200, 300, 400],
'max_depth': [None, 15, 20, 25],
'max_features': ['sqrt', 0.3],
'min_samples_split': [2, 3, 5],
'min_samples_leaf': [1, 2, 3]
}
rf_grid = GridSearchCV(
estimator=RandomForestClassifier(random_state=42),
param_grid=param_grid,
cv=5,
scoring='f1_weighted',
n_jobs=-1,
verbose=1
)
rf_grid.fit(X_train, y_train)
print("\n" + "=" * 60)
print("GRID SEARCH RESULTS")
print("=" * 60)
print(f"Best Score (CV): {rf_grid.best_score_:.4f}")
print(f"Best Parameters:")
for param, value in rf_grid.best_params_.items():
print(f" {param}: {value}")
best_rf_grid = rf_grid.best_estimator_
print(f"Test Accuracy: {best_rf_grid.score(X_test, y_test):.4f}")
- Mulai dengan RandomizedSearchCV untuk eksplorasi luas, lalu GridSearchCV untuk fine-tuning di range yang sudah ketahui
n_estimators= 300-500 sudah cukup untuk kebanyakan masalah; lebih banyak memberikan diminishing return- Jika data besar, kecilkan
max_featuresuntuk mempercepat training tanpa mengorbankan performa banyak - Gunakan
class_weight='balanced'jika dataset tidak seimbang
8. Random Forest untuk Regresi
Random Forest juga bisa digunakan untuk masalah regresi β memprediksi nilai kontinu (angka). Perbedaan utamanya: alih-alih melakukan voting (klasifikasi), Random Forest Regressor mengambil rata-rata prediksi dari semua tree.
import numpy as np
import matplotlib.pyplot as plt
from sklearn.ensemble import RandomForestRegressor
from sklearn.datasets import make_regression
from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score
# Generate dataset regresi
X, y = make_regression(
n_samples=1000,
n_features=10,
n_informative=7,
noise=15,
random_state=42
)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
# Random Forest Regressor
rf_reg = RandomForestRegressor(
n_estimators=300,
max_depth=20,
max_features='sqrt',
min_samples_split=5,
min_samples_leaf=2,
oob_score=True,
random_state=42,
n_jobs=-1
)
rf_reg.fit(X_train, y_train)
# Prediksi
y_pred = rf_reg.predict(X_test)
# Evaluasi
print("=" * 50)
print("RANDOM FOREST REGRESSOR β HASIL")
print("=" * 50)
print(f"OOB Score (RΒ²): {rf_reg.oob_score_:.4f}")
print(f"Test RΒ² Score: {r2_score(y_test, y_pred):.4f}")
print(f"RMSE: {np.sqrt(mean_squared_error(y_test, y_pred)):.4f}")
print(f"MAE: {mean_absolute_error(y_test, y_pred):.4f}")
# Visualisasi: Prediksi vs Aktual
fig, axes = plt.subplots(1, 3, figsize=(18, 5))
# Plot 1: Prediksi vs Aktual
axes[0].scatter(y_test, y_pred, alpha=0.5, s=20)
axes[0].plot([y_test.min(), y_test.max()],
[y_test.min(), y_test.max()], 'r--', linewidth=2)
axes[0].set_xlabel('Nilai Aktual')
axes[0].set_ylabel('Nilai Prediksi')
axes[0].set_title(f'Prediksi vs Aktual (RΒ²={r2_score(y_test, y_pred):.3f})')
# Plot 2: Residuals
residuals = y_test - y_pred
axes[1].scatter(y_pred, residuals, alpha=0.5, s=20)
axes[1].axhline(y=0, color='r', linestyle='--', linewidth=2)
axes[1].set_xlabel('Prediksi')
axes[1].set_ylabel('Residual (Aktual - Prediksi)')
axes[1].set_title('Residual Plot')
# Plot 3: Feature Importance
importances = rf_reg.feature_importances_
indices = np.argsort(importances)[::-1]
axes[2].bar(range(10), importances[indices])
axes[2].set_xticks(range(10))
axes[2].set_xticklabels([f'Feature {i}' for i in indices], rotation=45)
axes[2].set_title('Feature Importance')
plt.tight_layout()
plt.show()
# Perbandingan jumlah tree
print("\n--- Pengaruh Jumlah Tree ---")
n_trees_range = [10, 25, 50, 100, 200, 300, 500, 800]
scores = []
for n in n_trees_range:
rf_temp = RandomForestRegressor(n_estimators=n, random_state=42, n_jobs=-1)
cv_score = cross_val_score(rf_temp, X_train, y_train, cv=5,
scoring='r2', n_jobs=-1)
scores.append(cv_score.mean())
print(f" n_estimators={n:4d}: CV RΒ² = {cv_score.mean():.4f} "
f"(Β±{cv_score.std():.4f})")
plt.figure(figsize=(10, 5))
plt.plot(n_trees_range, scores, 'bo-', linewidth=2)
plt.xlabel('Jumlah Trees')
plt.ylabel('CV RΒ² Score')
plt.title('Pengaruh Jumlah Trees terhadap Performa')
plt.grid(True, alpha=0.3)
plt.show()
9. Kelebihan & Kekurangan
Kelebihan Random Forest
| Kelebihan | Penjelasan |
|---|---|
| β Tahan overfitting | Ensemble banyak tree mengurangi variance secara signifikan |
| β Sedikit preprocessing | Tidak perlu normalisasi/scaling, tahan terhadap outlier |
| β Handle missing values | Bisa menangani missing values secara internal |
| β Feature importance | Secara built-in memberikan ranking fitur paling penting |
| β OOB evaluation | Validasi internal tanpa perlu split data terpisah |
| β Parallelizable | Training tiap tree independen β bisa parallel (n_jobs=-1) |
| β Works out-of-the-box | Hyperparameter default sudah cukup bagus untuk banyak masalah |
| β Mixed data types | Bisa menangani fitur numerik dan kategorikal sekaligus |
Kekurangan Random Forest
| Kekurangan | Penjelasan |
|---|---|
| β Lambat untuk inference | Prediksi harus melewati semua tree (bisa lambat untuk real-time) |
| β Memory intensive | Menyimpan banyak tree membutuhkan memori besar |
| β Black box relatif | Meskipun ada feature importance, sulit menjelaskan prediksi individual |
| β Extrapolasi buruk | Tidak bisa memprediksi nilai di luar range data training |
| β Tidak ideal untuk data sekuensial | Tidak mempertahankan urutan data (time series, NLP) |
| β Imbalanced data | Bisa bias ke kelas mayoritas (perlu class_weight atau SMOTE) |
Random Forest vs Algoritma Lain
| Aspek | Random Forest | Gradient Boosting | SVM | Neural Network |
|---|---|---|---|---|
| Kecepatan Training | β‘ Cepat (parallel) | π’ Lambat (sequential) | π’ Lambat (large data) | π Sangat lambat (GPU needed) |
| Kecepatan Inference | π’ Lambat (banyak tree) | β‘ Cepat (fewer trees) | π’ Lambat (support vectors) | β‘ Cepat (once trained) |
| Akurasi | ββββ | βββββ | ββββ | βββββ |
| Mudah Digunakan | βββββ | βββ | ββ | ββ |
| Interpretability | βββ | ββ | ββ | β |
| Overfitting Risk | Rendah | Sedang (perlu tuning) | Sedang | Tinggi |
- Pertama coba RF β Random Forest sering menjadi baseline pertama yang bagus untuk tabular data
- Tidak ada waktu untuk preprocessing β RF relatif robust terhadap outlier dan tidak perlu scaling
- Perlu feature importance β RF memberikan ranking fitur secara built-in
- Data kecil-menengah β RF sangat cocok untuk dataset dengan ribuan sampai ratusan ribu baris
- Kecepatan training penting β RF bisa diparalelkan, training relatif cepat
10. Quiz: Uji Pemahamanmu!
Setelah membaca tutorial di atas, jawablah 5 pertanyaan berikut untuk menguji pemahamanmu tentang Random Forest: