Menguasai classification dengan logistic regression dan k-Nearest Neighbors, evaluasi menyeluruh via accuracy, precision/recall, F1, confusion matrix, dan ROC-AUC, plus penanganan data tidak seimbang memakai class_weight dan SMOTE pada studi kasus prediksi churn.

Setelah di episode 5 kita memprediksi angka kontinu dengan regression, pada episode ini target kita berubah menjadi label: apakah customer akan churn? Apakah email ini spam? Apakah transaksi ini penipuan?
Mengapa classification harus dipelajari secara hati-hati? Karena evaluasinya lebih rumit daripada regression. Mengatakan "akurasi 95%" terdengar mengesankan, tetapi jika 95% data adalah kelas mayoritas, model yang selalu menebak kelas mayoritas pun mendapat akurasi 95% — padahal tidak belajar apa-apa. Inilah masalah data tidak seimbang yang akan kita bedah di bagian akhir episode.
Terlepas dari namanya, logistic regression adalah model classification. Ia mengambil output linear w·x + b, lalu memetakannya ke probabilitas 0-1 melalui fungsi sigmoid.
from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
pipeline = Pipeline([
("scale", StandardScaler()),
("clf", LogisticRegression(max_iter=1000, random_state=42)),
])
pipeline.fit(X_train, y_train)
proba = pipeline.predict_proba(X_test)[:, 1] # P(churn)
print(proba[:5])predict_proba memberi probabilitas, bukan sekadar label — sangat berguna saat kita perlu memutuskan threshold sendiri (misalnya hanya menelpon customer dengan risiko churn di atas 70%). Seperti halnya Ridge di episode 5, logistic regression juga berbasis gradien sehingga wajib scaling.
kNN adalah model paling intuitif: untuk memprediksi titik baru, lihat k tetangga terdekat, lalu ambil suara mayoritas (atau rata-rata jarak). Tidak ada proses "belajar" — seluruh data disimpan dan dibandingkan saat prediksi.
from sklearn.neighbors import KNeighborsClassifier
knn = KNeighborsClassifier(n_neighbors=5)
knn.fit(X_train, y_train)
print(knn.score(X_test, y_test))Kelemahan kNN: sensitif pada skala fitur (wajib scaling), dan prediksi lambat untuk data besar karena harus menghitung jarak ke semua titik. Kelebihannya: sederhana, mudah dipahami, dan bekerja baik untuk data berdimensi rendah.
Accuracy saja tidak cukup. Perkenalan dengan empat komponen dasar:
| Komponen | Arti | Singkatan |
|---|---|---|
| True Positive | Prediksi positif, benar | TP |
| False Positive | Prediksi positif, salah (alarm palsu) | FP |
| True Negative | Prediksi negatif, benar | TN |
| False Negative | Prediksi negatif, salah (bahaya terlewat) | FN |
Confusion matrix merangkum keempatnya:
from sklearn.metrics import (
confusion_matrix, classification_report,
f1_score, roc_auc_score,
)
preds = pipeline.predict(X_test)
print(confusion_matrix(y_test, preds))
print(classification_report(y_test, preds))Metrik turunan yang harus kalian hafal:
(TP+TN) / total — cocok untuk data seimbang.TP / (TP+FP) — dari yang diprediksi positif, berapa yang benar. Penting saat false positive mahal (menuduh orang fraud).TP / (TP+FN) — dari yang positif sebenarnya, berapa yang tertangkap. Penting saat false negative mahal (kanker terlewat).Tip
Ada trade-off antara precision dan recall: menaikkan threshold akan menaikkan precision tapi menurunkan recall, dan sebaliknya. Kurva ROC dan precision-recall menunjukkan trade-off ini untuk semua threshold sekaligus.
Kembali ke masalah di pendahuluan: jika hanya 5% customer churn, model yang selalu menebak "tidak churn" mendapat accuracy 95%. Di sinilah accuracy menipu.
Dua pendekatan utama:
Beri bobot lebih pada kelas minoritas lewat parameter class_weight:
LogisticRegression(class_weight="balanced")SMOTE (Synthetic Minority Oversampling Technique) membuat sampel sintetis untuk kelas minoritas, sehingga data menjadi seimbang:
from imblearn.over_sampling import SMOTE
from imblearn.pipeline import Pipeline as ImbPipeline
pipeline = ImbPipeline([
("scale", StandardScaler()),
("smote", SMOTE(random_state=42)),
("clf", LogisticRegression()),
])
pipeline.fit(X_train, y_train)Warning
SMOTE harus berada di dalam pipeline dan setelah split — hanya data train yang boleh di-oversampling. Jika kalian membuat sampel sintetis dari seluruh data lalu split, informasi dari test set ikut terbawa ke training (leakage) dan evaluasi jadi tidak jujur. Gunakan imblearn.pipeline.Pipeline seperti contoh di atas.
Rangkai seluruh konsep dengan data churn sintetis:
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.metrics import precision_recall_curve, auc
df = pd.read_csv("churn.csv")
X = df.drop("churn", axis=1)
y = df["churn"]
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42, stratify=y
)
pipeline.fit(X_train, y_train)
proba = pipeline.predict_proba(X_test)[:, 1]
print(f"F1 = {f1_score(y_test, pipeline.predict(X_test)):.3f}")
print(f"ROC-AUC = {roc_auc_score(y_test, proba):.3f}")Perhatikan bahwa untuk data tidak seimbang, PR-AUC (area di bawah precision-recall curve) sering lebih informatif daripada ROC-AUC karena ia fokus pada kelas minoritas. Kita akan memperdalam metrik ini di episode 14.
Pada episode 6 ini, kalian telah menguasai classification dan evaluasinya.
Inti yang harus dibawa pulang:
class_weight atau SMOTE di dalam pipeline.Di episode 7 selanjutnya kita akan membahas tree-based models & ensemble — decision tree (Gini/entropy), bias-variance dan overfitting, lalu Random Forest, Gradient Boosting (XGBoost, LightGBM, CatBoost) yang menjadi workhorse data tabular 2026. Sampai jumpa di episode 7!