Referensi cepat supervised learning. Regresi, klasifikasi, tree-based models, evaluasi model, hyperparameter tuning, dan pipeline scikit-learn dengan Python.
Supervised learning melatih model pada data yang sudah punya label. Target bisa angka kontinu untuk regresi, atau kategori untuk klasifikasi. Cheat sheet ini membahas workflow yang benar, algoritma utama, evaluasi, dan jebakan yang bikin model kamu jeblok di data asli padahal di notebook kelihatan bagus.
Urutan langkah lebih penting daripada memilih model paling keren. Data yang diproses salah akan menghasilkan model yang diam-diam bocor dan skor test yang menyesatkan.
Pisahkan data sebelum scaling, imputation, atau encoding. Target encoder yang melihat seluruh data sebelum split akan menciptakan leakage.
from sklearn.model_selection import 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
)Gunakan stratify=y untuk klasifikasi supaya proporsi kelas di train dan test tetap sama. Ini penting saat kelas tidak seimbang. Untuk regresi, stratify bisa memakai bin dari target, tetapi sederhananya mulai dengan split acak ber-seed.
Satu split bisa kebetulan bagus. Validasi silang melipat data jadi K bagian dan melatih K kali, setiap kali satu lipatan jadi validasi.
from sklearn.model_selection import cross_val_score
from sklearn.ensemble import RandomForestClassifier
model = RandomForestClassifier(random_state=42)
scores = cross_val_score(model, X_train, y_train, cv=5, scoring="roc_auc")
print(scores)
print(f"mean AUC: {scores.mean():.3f}, std: {scores.std():.3f}")Pipeline memastikan preprocessing dan model selalu dijalankan bersama, jadi tidak ada bocor antar langkah. Semua model scikit-learn berbagi API fit, predict, dan score.
from sklearn.pipeline import Pipeline
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.impute import SimpleImputer
num_cols = ["umur", "pendapatan"]
cat_cols = ["kota", "pekerjaan"]
preprocessor = ColumnTransformer([
("num", Pipeline([
("imputer", SimpleImputer(strategy="median")),
("scaler", StandardScaler()),
]), num_cols),
("cat", Pipeline([
("imputer", SimpleImputer(strategy="most_frequent")),
("encoder", OneHotEncoder(handle_unknown="ignore")),
]), cat_cols),
])
pipeline = Pipeline([
("prep", preprocessor),
("model", RandomForestClassifier(random_state=42)),
])
pipeline.fit(X_train, y_train)
print(pipeline.score(X_test, y_test))Regresi memprediksi nilai kontinu. Mulai dari linear regression karena koefisiennya bisa dibaca. Kalau linear terlalu kaku, naik ke tree atau ensemble.
Linear regression mencari bobot yang meminimalkan jumlah kuadrat error. Koefisien punya interpretasi langsung: naik satu unit feature menggeser prediksi sebesar koefisien, dengan asumsi feature lain tetap.
from sklearn.linear_model import LinearRegression
model = LinearRegression()
model.fit(X_train, y_train)
print("koefisien:", model.coef_)
print("intercept:", model.intercept_)
# Formula di balik layar untuk satu fitur x:
# y_hat = intercept + coef * xAsumsi yang perlu dicek: hubungan kira-kira linear, residual tidak berpola, dan multikolinearitas tidak gila-gilaan. Sebaran residual yang membentuk corong menandakan heteroskedastisitas.
Ridge menambah penalti L2 yang mengecilkan koefisien. Lasso menambah penalti L1 yang bisa memaksa koefisien jadi nol. ElasticNet mencampur keduanya.
from sklearn.linear_model import Ridge, Lasso, ElasticNet
ridge = Ridge(alpha=1.0)
lasso = Lasso(alpha=0.1)
elastic = ElasticNet(alpha=0.1, l1_ratio=0.5)Alpha mengontrol kuatnya penalti. Semakin besar alpha, semakin kuat model menahan koefisien besar. Lasso berguna untuk feature selection otomatis karena koefisien yang tidak penting bisa persis nol.
MAE memakai satuan asli dan mudah dijelaskan ke non-teknis. RMSE menghukum error besar lebih keras. R-squared menjelaskan berapa proporsi varians target yang tertangkap model.
from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score
import numpy as np
pred = model.predict(X_test)
mae = mean_absolute_error(y_test, pred)
rmse = np.sqrt(mean_squared_error(y_test, pred))
r2 = r2_score(y_test, pred)
print(f"MAE={mae:.2f}, RMSE={rmse:.2f}, R2={r2:.3f}")Jika target condong seperti harga rumah, pertimbangkan log transform pada target dan melaporkan error di skala asli lewat inverse transform. Error persentase terkadang lebih berguna daripada error absolut.
Klasifikasi memprediksi kategori. Logistic regression memakai sigmoid untuk mengubah skor menjadi probabilitas. Model lain punya cara sendiri, tetapi API prediksinya sama.
Ini baseline kuat untuk klasifikasi biner. Beri bobot kelas saat data timpang supaya model tidak hanya menebak kelas mayoritas.
from sklearn.linear_model import LogisticRegression
model = LogisticRegression(max_iter=1000, class_weight="balanced")
model.fit(X_train, y_train)
proba = model.predict_proba(X_test)[:, 1]
print(proba[:5])predict mengembalikan kelas pakai threshold default 0.5. predict_proba mengembalikan probabilitas tiap kelas. Kalau kamu butuh keputusan, seringkali probabilitas lebih berguna daripada label keras.
Decision tree mudah dibaca tetapi gampang overfit. Random forest mengagregasi banyak pohon dari bootstrap sampel dan subset fitur. Gradient boosting membangun pohon yang memperbaiki error pohon sebelumnya.
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
dt = DecisionTreeClassifier(max_depth=5, random_state=42)
rf = RandomForestClassifier(n_estimators=200, max_depth=None, random_state=42)
gb = GradientBoostingClassifier(n_estimators=100, learning_rate=0.1, random_state=42)Untuk dataset tabular menengah, gradient boosting seperti XGBoost, LightGBM, atau CatBoost sering menang. Untuk data kecil atau ketika interpretasi penting, decision tree atau logistic regression lebih cocok.
SVM mencari batas keputusan yang memaksimalkan margin. Kernel radial menangani batas nonlinear. Skala fitur penting di sini karena SVM peka terhadap magnitudo fitur.
from sklearn.svm import SVC
model = SVC(kernel="rbf", C=1.0, gamma="scale", probability=True)
model.fit(X_train, y_train)C mengontrol toleransi kesalahan pelatihan. Semakin besar C, semakin keras model memaksakan batas rapi, yang bisa berujung overfit. gamma mengontrol jangkauan pengaruh satu titik latih.
KNN memprediksi berdasarkan label tetangga terdekat. Tidak ada fase training yang berat, tetapi prediksi lambat karena menghitung jarak ke semua titik.
from sklearn.neighbors import KNeighborsClassifier
model = KNeighborsClassifier(n_neighbors=5, metric="euclidean")
model.fit(X_train, y_train)KNN sangat butuh scaling. Jarak Euclidean didominasi feature dengan skala besar. Kalau satu kolom berisi puluhan ribu dan kolom lain berisi pecahan kecil, fitur besar menenggelamkan yang lain.
Accuracy menipu saat kelas tidak seimbang. Model yang menebak selalu mayoritas bisa tampak 95% akurat pada data dengan 95% kelas mayoritas. Gunakan beberapa metrik sekaligus.
Matriks ini menghitung empat kombinasi: true positive, false negative, false positive, dan true negative.
from sklearn.metrics import confusion_matrix, classification_report
pred = model.predict(X_test)
print(confusion_matrix(y_test, pred))
print(classification_report(y_test, pred))Precision menjawab: dari semua prediksi positif, berapa yang benar positif? Recall menjawab: dari semua kasus benar positif, berapa yang tertangkap? F1 mengharmonisasikan keduanya.
precision = TP / (TP + FP)
recall = TP / (TP + FN)
f1 = 2 * precision * recall / (precision + recall)Pilih prioritas berdasarkan biaya kesalahan. Deteksi fraud lebih peduli recall karena fraud yang lolos mahal. Rekomendasi artikel lebih peduli precision supaya pengguna tidak dibanjiri saran sampah.
ROC AUC mengukur kemampuan model mengurutkan contoh positif di atas negatif. Pada data sangat tidak seimbang, kurva precision-recall lebih informatif.
from sklearn.metrics import roc_auc_score, average_precision_score, precision_recall_curve
proba = model.predict_proba(X_test)[:, 1]
auc = roc_auc_score(y_test, proba)
pr_auc = average_precision_score(y_test, proba)
print(f"ROC AUC={auc:.3f}, PR AUC={pr_auc:.3f}")ROC AUC 0.5 berarti model tidak lebih baik dari tebakan acak. AUC 1.0 berarti pemisahan sempurna. AUC yang terlalu sempurna layak dicurigai, biasanya ada kebocoran label atau duplikasi data.
Threshold default 0.5 jarang optimal. Geser threshold dengan melihat kurva precision-recall dan biaya bisnis.
precision, recall, thresholds = precision_recall_curve(y_test, proba)
f1 = 2 * (precision * recall) / (precision + recall + 1e-9)
best = thresholds[f1.argmax()]
print(f"threshold terbaik (F1): {best:.3f}")Naikkan threshold untuk menekan false positive. Turunkan threshold untuk menekan false negative. Pilihan ini soal trade-off, bukan parameter teknis murni.
Hyperparameter dipilih sebelum pelatihan, bukan dipelajari dari data. Grid search mencoba semua kombinasi yang kamu sebut. Random search mencicipi kombinasi acak dalam rentang.
from sklearn.model_selection import GridSearchCV, RandomizedSearchCV
param_grid = {
"model__n_estimators": [100, 200, 400],
"model__max_depth": [None, 5, 10, 20],
}
gs = GridSearchCV(
pipeline, param_grid, cv=5, scoring="roc_auc", n_jobs=-1
)
gs.fit(X_train, y_train)
print(gs.best_params_, gs.best_score_)Perhatikan model__ di nama parameter, karena parameter berada di dalam pipeline. Cek pipeline.get_params().keys() kalau ragu. Model final dievaluasi di test hanya sekali, supaya test tidak ikut dipakai untuk memilih.
Ada beberapa pendekatan, dan masing-masing punya risiko. Undersampling membuang data mayoritas dan bisa kehilangan informasi. Oversampling menggandakan data minoritas dan bisa menambah overfit. Mengubah bobot kelas atau threshold sering lebih aman daripada menciptakan data sintetis.
# Bobot kelas di dalam estimator
from sklearn.ensemble import RandomForestClassifier
rf = RandomForestClassifier(class_weight="balanced", random_state=42)
# Bobot manual untuk kelas biner
manual_weights = {0: 1.0, 1: 5.0}
model = LogisticRegression(class_weight=manual_weights, max_iter=1000)Alat sintetis seperti SMOTE hanya boleh dijalankan di dalam pipeline dan setelah split, bukan sebelum. Kalau SMOTE dijalankan sebelum split, tetangga sintetis dari data test merembes ke train.
Tidak ada satu model terbaik untuk semua data. Pilihan tergantung ukuran data, kebutuhan interpretasi, dan apakah fitur kamu tabular atau terstruktur lain.
| Kondisi | Mulai dari | Catatan |
|---|---|---|
| Butuh interpretasi koefisien | Logistic regression, linear regression | Koefisien bisa dijelaskan ke stakeholder |
| Data tabular menengah sampai besar | Gradient boosting (XGBoost, LightGBM) | Sering juara di kompetisi tabular |
| Data kecil, baseline cepat | Decision tree atau KNN | Cepat, mudah dibaca |
| Fitur sangat banyak | Linear dengan regularisasi | Lasso sekaligus memangkas fitur |
| Batas keputusan nonlinear | SVM kernel RBF atau random forest | Perlu scaling untuk SVM |
| Target punya struktur temporal | Model dengan split berbasis waktu | Jangan campur masa lalu dan masa depan |
Coba dua atau tiga model dan bandingkan lewat validasi silang, bukan lewat feeling. Baseline yang paling sederhana sering memberi batas bawah yang jujur: jika logistic regression sudah memuaskan, model 500 parameter mungkin tidak menambah apa-apa selain biaya operasional.
Feature importance membantu kamu memahami sinyal dominan dan mendeteksi kebocoran. Untuk model linear, lihat koefisien setelah scaling. Untuk tree, pakai impurity-based importance. Untuk model apa pun, permutation importance lebih konsisten.
from sklearn.inspection import permutation_importance
result = permutation_importance(
pipeline, X_test, y_test, n_repeats=10, random_state=42, scoring="roc_auc"
)
for i in result.importances_mean.argsort()[::-1]:
print(f"fitur {i}: {result.importances_mean[i]:.3f} ± {result.importances_std[i]:.3f}")Importance bukan bukti kausalitas. Sebuah fitur bisa penting karena kebetulan berkorelasi dengan target di data latih, lalu kehilangan pengaruhnya saat distribusi bergeser. Pakai importance untuk hipotesis, lalu validasi dengan eksperimen atau pemahaman domain.
Data leakage adalah sumber skor palsu yang paling umum. Fitur yang memuat informasi target secara tidak langsung, seperti ID yang mengodekan waktu atau kategori, akan membuat model kelihatan jenius di test dan tumpul di produksi.
Split time series pakai split berdasarkan indeks waktu, bukan train_test_split acak.
from sklearn.model_selection import TimeSeriesSplit
tscv = TimeSeriesSplit(n_splits=5)
for train_idx, val_idx in tscv.split(X_sorted_by_time):
model.fit(X_sorted_by_time[train_idx], y_sorted_by_time[train_idx])
score = model.score(X_sorted_by_time[val_idx], y_sorted_by_time[val_idx])
print(score)Untuk masalah waktu, validasi silang biasa yang mencampur masa lalu dan masa depan memberi angka optimistis yang tidak bisa dipercaya.
| Istilah | Arti singkat |
|---|---|
| Classification | Tugas memprediksi kategori atau label. |
| Confusion matrix | Tabel TP, FP, FN, TN dari prediksi vs label asli. |
| Cross-validation | Melipat data jadi K bagian untuk estimasi performa yang stabil. |
| Data leakage | Informasi test atau masa depan bocor ke pelatihan. |
| Ensemble | Menggabungkan banyak model untuk prediksi lebih kuat. |
| Feature importance | Ukuran seberapa besar fitur memengaruhi prediksi model. |
| Hyperparameter | Setelan yang dipilih sebelum pelatihan, misalnya kedalaman pohon. |
| Overfitting | Model hafal pola latih dan gagal di data baru. |
| Precision | Proporsi prediksi positif yang benar. |
| Recall | Proporsi kasus positif yang tertangkap. |
| Regularization | Penalti yang menahan model supaya tidak terlalu kompleks. |
| Underfitting | Model terlalu sederhana untuk menangkap pola data. |
Login atau daftar akun gratis untuk membaca cheat sheet ini.