Model Klasifikasi
Logistic Regression Explained
Pahami bagaimana model klasifikasi paling fundamental bekerja — dari konsep probabilitas hingga fungsi sigmoid yang mengubah angka menjadi keputusan “Ya atau Tidak”.
Apa Itu Logistic Regression?
Meskipun namanya mengandung kata “Regression”, Logistic Regression adalah algoritma klasifikasi, bukan regresi. Tujuannya adalah memprediksi probabilitas suatu data termasuk ke dalam kelas tertentu (misal: spam/bukan spam, sakit/sehat, lulus/tidak lulus).
🎯 Linear Regression
Menghasilkan nilai kontinu (misal: harga rumah = Rp450 juta). Output bisa bernilai apa saja dari −∞ hingga +∞.
✅ Logistic Regression
Menghasilkan probabilitas antara 0 dan 1. Jika p ≥ 0.5 → Kelas 1, jika p < 0.5 → Kelas 0.
Fungsi Sigmoid — Jantung dari Logistic Regression
Logistic Regression menggunakan fungsi Sigmoid (σ) untuk memampatkan output Linear Regression ke rentang [0, 1]. Fungsi ini berbentuk kurva S yang elegan.
🎛️ Coba Sendiri — Simulator Sigmoid Interaktif
Decision Boundary
Logistic Regression membuat garis batas keputusan (decision boundary) yang memisahkan dua kelas. Semua data di satu sisi → Kelas 0, sisi lainnya → Kelas 1.
Kapan Menggunakan Logistic Regression?
| Situasi | Cocok? | Alasan |
|---|---|---|
| Klasifikasi biner (2 kelas) | ✅ Sangat Cocok | Dirancang khusus untuk ini |
| Data linear separable | ✅ Cocok | Boundary berupa garis lurus |
| Butuh interpretasi koefisien | ✅ Cocok | Koefisien mudah dijelaskan |
| Data non-linear kompleks | ⚠️ Kurang | Boundary tidak bisa melengkung |
| Banyak kelas (multi-class) | 🔄 Perlu modifikasi | Gunakan One-vs-Rest / Softmax |
🧠 Uji Pemahaman
Implementing Logistic Regression
Dari teori ke kode nyata — pelajari cara membangun, melatih, dan mengevaluasi model Logistic Regression menggunakan Scikit-learn dengan dataset dunia nyata.
Setup & Import Library
Kita akan menggunakan dataset Breast Cancer Wisconsin — dataset klasik untuk memprediksi apakah tumor bersifat ganas (malignant) atau jinak (benign). Dataset ini sudah tersedia di Scikit-learn.
# Import library yang diperlukan import numpy as np import pandas as pd import matplotlib.pyplot as plt from sklearn.datasets import load_breast_cancer from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler from sklearn.linear_model import LogisticRegression from sklearn.metrics import (accuracy_score, classification_report, confusion_matrix) # Load dataset data = load_breast_cancer() X = data.data # Fitur (30 kolom) y = data.target # Label: 0 = Malignant, 1 = Benign # Lihat struktur dataset df = pd.DataFrame(X, columns=data.feature_names) df['target'] = y print(df.head()) print(f"\nShape: {df.shape}") print(f"Distribusi kelas:\n{df['target'].value_counts()}")
Preprocessing: Split & Scaling
StandardScaler agar semua fitur berskala sama.# 1. Split data: 80% train, 20% test X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.2, random_state=42, stratify=y # Pastikan proporsi kelas seimbang ) print(f"Data latih: {X_train.shape}") print(f"Data uji : {X_test.shape}") # 2. Feature Scaling dengan StandardScaler scaler = StandardScaler() X_train_scaled = scaler.fit_transform(X_train) # fit + transform train X_test_scaled = scaler.transform(X_test) # HANYA transform test! # ✅ PENTING: Jangan fit scaler pada test data — itu data leakage!
Training Model
# Inisialisasi model model = LogisticRegression( C=1.0, # Regularization strength (lebih kecil = lebih regularized) max_iter=1000, # Iterasi maksimum untuk konvergensi random_state=42 ) # Training model model.fit(X_train_scaled, y_train) # Prediksi pada test set y_pred = model.predict(X_test_scaled) y_pred_proba = model.predict_proba(X_test_scaled)[:, 1] # predict_proba → probabilitas untuk kelas 1 (Benign) # Evaluasi dasar acc = accuracy_score(y_test, y_pred) print(f"Akurasi Model: {acc:.4f} ({acc*100:.2f}%)") # Laporan lengkap print("\nClassification Report:") print(classification_report(y_test, y_pred, target_names=['Malignant', 'Benign']))
Visualisasi Koefisien Model
# Koefisien model — fitur mana yang paling berpengaruh? coef_df = pd.DataFrame({ 'feature': data.feature_names, 'coefficient': model.coef_[0] }).sort_values('coefficient', ascending=False) # Plot plt.figure(figsize=(10, 6)) colors = ['#00d4aa' if c > 0 else '#ff6b6b' for c in coef_df['coefficient']] plt.barh(coef_df['feature'], coef_df['coefficient'], color=colors) plt.xlabel('Koefisien (Pengaruh terhadap prediksi Benign)') plt.title('Feature Importance – Logistic Regression') plt.tight_layout() plt.show()
📊 Interpretasi Koefisien
Koefisien positif → Nilai fitur yang tinggi meningkatkan probabilitas Kelas 1 (Benign). Koefisien negatif → Nilai tinggi menurunkan probabilitas Kelas 1 (kemungkinan Malignant lebih tinggi). Ini yang membuat Logistic Regression sangat interpretable!
🧠 Uji Pemahaman
scaler.transform() (bukan fit_transform()) pada data test?K-Nearest Neighbors (KNN)
Algoritma paling intuitif di ML — “katakan padaku siapa tetanggamu, dan aku akan tahu kamu siapa.” KNN mengklasifikasikan data berdasarkan kemiripan dengan data latih.
Cara Kerja KNN
KNN tidak membangun model saat training. Ia menyimpan semua data latih, lalu saat prediksi, ia mencari K tetangga terdekat dari data baru dan melakukan voting kelas mayoritas.
- 1Pilih nilai KTentukan berapa banyak tetangga yang akan dipertimbangkan. K=3 berarti ambil 3 data terdekat.
- 2Hitung JarakHitung jarak antara data baru dengan semua data latih (biasanya menggunakan Euclidean Distance).
- 3Temukan K Tetangga TerdekatUrutkan jarak dan ambil K data dengan jarak terkecil.
- 4Voting MayoritasKelas yang paling banyak muncul di antara K tetangga menjadi prediksi akhir.
Formula Euclidean Distance
📐 Euclidean Distance
Jarak garis lurus antara dua titik. Paling umum digunakan. Cocok untuk data kontinu.
🔷 Manhattan Distance
Jumlah selisih absolut. Seperti jarak tempuh di kota berikat. Lebih robust terhadap outlier.
🎛️ Pengaruh Nilai K — Coba Interaktif
K Terlalu Kecil (K=1)
Overfitting: sangat sensitif terhadap noise. Model “hafal” data latih.
K Terlalu Besar
Underfitting: boundary terlalu mulus, banyak detail yang hilang.
Implementasi KNN di Python
from sklearn.neighbors import KNeighborsClassifier from sklearn.model_selection import cross_val_score import matplotlib.pyplot as plt # Inisialisasi KNN dengan K=5 knn = KNeighborsClassifier( n_neighbors=5, # Jumlah tetangga metric='euclidean', # Jenis distance metric weights='uniform' # Semua tetangga bobotnya sama ) # Training & Evaluasi knn.fit(X_train_scaled, y_train) y_pred_knn = knn.predict(X_test_scaled) print(f"KNN Akurasi: {accuracy_score(y_test, y_pred_knn):.4f}") # ── Mencari K optimal dengan cross-validation ── k_range = range(1, 26) cv_scores = [] for k in k_range: knn_k = KNeighborsClassifier(n_neighbors=k) scores = cross_val_score(knn_k, X_train_scaled, y_train, cv=5, scoring='accuracy') cv_scores.append(scores.mean()) # Plot: Elbow curve untuk mencari K terbaik plt.figure(figsize=(10, 5)) plt.plot(k_range, cv_scores, 'o-', color='#6c63ff', linewidth=2) plt.xlabel('Nilai K') plt.ylabel('CV Accuracy') plt.title('Elbow Curve – Mencari K Optimal') plt.axvline(x=cv_scores.index(max(cv_scores))+1, color='#00d4aa', linestyle='--', label='K terbaik') plt.legend() plt.show()
🧠 Uji Pemahaman
Decision Trees – How Splits Work
Pahami bagaimana pohon keputusan memilih “pertanyaan terbaik” untuk memisahkan data — dari konsep Gini Impurity hingga Information Gain yang menggerakkan setiap percabangan.
Anatomi Decision Tree
Decision Tree membuat keputusan layaknya flowchart — dimulai dari root node, melakukan serangkaian pertanyaan di internal nodes, hingga mencapai leaf nodes yang berisi prediksi akhir.
Bagaimana Tree Memilih Split Terbaik?
Algoritma Decision Tree mencari fitur dan threshold yang paling memurnikan kelas di setiap node. Ada dua metrik utama yang digunakan:
🍩 Gini Impurity
Default Scikit-learn. Mengukur seberapa “kotor” node — nilai 0 berarti node murni (satu kelas). Formula: Gini = 1 − Σ(pᵢ)²
📊 Information Gain (Entropy)
Mengukur pengurangan ketidakpastian setelah split. Berbasis konsep entropi dari teori informasi. IG = H(parent) − Σ weighted H(child)
Implementasi Decision Tree
from sklearn.tree import DecisionTreeClassifier, plot_tree import matplotlib.pyplot as plt # Inisialisasi Decision Tree dt = DecisionTreeClassifier( criterion='gini', # Gini impurity (atau 'entropy') max_depth=4, # Batasi kedalaman pohon (cegah overfitting) min_samples_split=10, # Min sampel untuk split node min_samples_leaf=5, # Min sampel di leaf node random_state=42 ) # Training dt.fit(X_train, y_train) # DT tidak perlu scaling! # Evaluasi y_pred_dt = dt.predict(X_test) print(f"Decision Tree Akurasi: {accuracy_score(y_test, y_pred_dt):.4f}") # Visualisasi pohon plt.figure(figsize=(20, 8)) plot_tree(dt, feature_names=data.feature_names, class_names=data.target_names, filled=True, rounded=True, fontsize=9) plt.title("Decision Tree Visualization") plt.show() # Feature Importance importances = pd.Series(dt.feature_importances_, index=data.feature_names) importances.sort_values(ascending=False)[:10].plot(kind='bar', color='#6c63ff') plt.title("Top 10 Feature Importance") plt.show()
max_depth), tree akan tumbuh sampai setiap leaf berisi 1 sampel — artinya 100% akurasi di training tapi buruk di test. Selalu gunakan hyperparameter untuk memangkas pohon!| Hyperparameter | Fungsi | Nilai Umum |
|---|---|---|
max_depth | Batas kedalaman pohon | 3–10 |
min_samples_split | Min sampel untuk membagi node | 10–20 |
min_samples_leaf | Min sampel di leaf | 5–10 |
max_features | Fitur yang dipertimbangkan per split | ‘sqrt’, ‘log2’ |
criterion | Metrik kualitas split | ‘gini’ atau ‘entropy’ |
🧠 Uji Pemahaman
Classification Metrics Explained
Akurasi saja tidak cukup! Pelajari cara mengukur performa model klasifikasi secara menyeluruh — Confusion Matrix, Precision, Recall, F1-Score, dan ROC-AUC.
Confusion Matrix — Fondasi Semua Metrik
Confusion Matrix menampilkan detail prediksi model: berapa yang benar, berapa yang salah, dan jenis kesalahannya. Dari sinilah semua metrik klasifikasi diturunkan.
✅ Benar: 85+90 = 175
❌ Salah: 10+15 = 25
Akurasi: 175/200 = 87.5%
4 Metrik Utama yang Wajib Dikuasai
Meningkatkan Precision biasanya menurunkan Recall, dan sebaliknya. Pilih prioritas berdasarkan konteks bisnis:
• Deteksi Kanker → Prioritas Recall (jangan sampai ada yang missed)
• Filter Spam → Prioritas Precision (jangan hapus email penting)
Implementasi Metrics di Python
from sklearn.metrics import (confusion_matrix, classification_report, precision_score, recall_score, f1_score, roc_auc_score, roc_curve) import seaborn as sns import matplotlib.pyplot as plt # ── 1. Confusion Matrix ── cm = confusion_matrix(y_test, y_pred) plt.figure(figsize=(6, 4)) sns.heatmap(cm, annot=True, fmt='d', cmap='Blues', xticklabels=['Malignant','Benign'], yticklabels=['Malignant','Benign']) plt.xlabel('Prediksi'); plt.ylabel('Aktual') plt.title('Confusion Matrix'); plt.show() # ── 2. Classification Report ── print(classification_report(y_test, y_pred, target_names=['Malignant', 'Benign'])) # ── 3. Metrik individual ── 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_pred_proba):.4f}") # ── 4. ROC Curve ── fpr, tpr, thresholds = roc_curve(y_test, y_pred_proba) auc = roc_auc_score(y_test, y_pred_proba) plt.figure(figsize=(7, 5)) plt.plot(fpr, tpr, color='#6c63ff', lw=2, label=f'ROC Curve (AUC = {auc:.3f})') plt.plot([0,1], [0,1], '--', color='#546e7a', label='Random Classifier') plt.xlabel('False Positive Rate') plt.ylabel('True Positive Rate') plt.title('ROC Curve') plt.legend() plt.show()
Perbandingan Metrik — Kapan Menggunakan Yang Mana?
| Metrik | Gunakan Ketika | Contoh Kasus |
|---|---|---|
| Accuracy | Data balanced, semua error sama pentingnya | Klasifikasi buah: apel/jeruk/mangga |
| Precision | FP lebih mahal dari FN | Spam detection, fraud alert palsu |
| Recall | FN lebih mahal dari FP | Deteksi kanker, COVID screening |
| F1-Score | Data imbalanced, butuh balance P&R | Deteksi penipuan (imbalanced) |
| ROC-AUC | Membandingkan model, semua threshold | Benchmark perbandingan model |
🧠 Uji Pemahaman
Mini Project: Binary Classification Model
Saatnya menyatukan semua yang telah dipelajari! Bangun pipeline klasifikasi biner end-to-end — mulai dari eksplorasi data, preprocessing, training 3 model, evaluasi, hingga perbandingan dan kesimpulan.
Dataset: Customer Churn
📊 Dataset
Telco Customer Churn (Kaggle). 7043 baris, 20 fitur. Target: Churn (Yes/No) — imbalanced ~73% No, 27% Yes.
🎯 Target Metrik
Karena imbalanced, kita prioritaskan F1-Score dan ROC-AUC sebagai metrik utama, bukan Accuracy.
Langkah 1 — Load & EDA Singkat
import pandas as pd import numpy as np import matplotlib.pyplot as plt import seaborn as sns # Load dataset df = pd.read_csv('telco_churn.csv') print(df.head()) print(f"\nShape: {df.shape}") print(f"Missing values:\n{df.isnull().sum()}") print(f"\nDistribusi Target:\n{df['Churn'].value_counts(normalize=True)}") # Visualisasi distribusi target df['Churn'].value_counts().plot(kind='bar', color=['#00d4aa', '#ff6b6b'], rot=0) plt.title('Distribusi Target: Churn vs Tidak Churn') plt.xlabel('Churn'); plt.ylabel('Jumlah Pelanggan') plt.show()
Langkah 2 — Preprocessing Pipeline
from sklearn.preprocessing import LabelEncoder, StandardScaler from sklearn.model_selection import train_test_split # 1. Drop kolom tidak relevan df = df.drop(columns=['customerID']) # 2. Konversi TotalCharges ke numerik df['TotalCharges'] = pd.to_numeric(df['TotalCharges'], errors='coerce') df['TotalCharges'].fillna(df['TotalCharges'].median(), inplace=True) # 3. Label encode kolom biner binary_cols = ['gender', 'Partner', 'Dependents', 'PhoneService', 'PaperlessBilling', 'Churn'] le = LabelEncoder() for col in binary_cols: df[col] = le.fit_transform(df[col]) # 4. One-Hot Encoding untuk multi-kategori df = pd.get_dummies(df, drop_first=True) # 5. Pisahkan fitur dan target X = df.drop(columns=['Churn']) y = df['Churn'] # 6. Split & Scale X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.2, random_state=42, stratify=y ) scaler = StandardScaler() X_train_sc = scaler.fit_transform(X_train) X_test_sc = scaler.transform(X_test) print(f"Fitur: {X_train.shape[1]} | Train: {len(X_train)} | Test: {len(X_test)}")
Langkah 3 — Training 3 Model Sekaligus
from sklearn.linear_model import LogisticRegression from sklearn.neighbors import KNeighborsClassifier from sklearn.tree import DecisionTreeClassifier from sklearn.metrics import (accuracy_score, f1_score, roc_auc_score, classification_report) # Dictionary berisi semua model models = { 'Logistic Regression': LogisticRegression(C=1.0, max_iter=1000, random_state=42), 'KNN' : KNeighborsClassifier(n_neighbors=9), 'Decision Tree' : DecisionTreeClassifier(max_depth=5, random_state=42), } results = {} for name, model in models.items(): # Training model.fit(X_train_sc, y_train) # Prediksi y_pred = model.predict(X_test_sc) y_proba = model.predict_proba(X_test_sc)[:, 1] # Simpan hasil results[name] = { 'Accuracy': accuracy_score(y_test, y_pred), 'F1-Score': f1_score(y_test, y_pred), 'ROC-AUC' : roc_auc_score(y_test, y_proba), } print(f"\n{'='*40}") print(f" {name}") print(f" Accuracy : {results[name]['Accuracy']:.4f}") print(f" F1-Score : {results[name]['F1-Score']:.4f}") print(f" ROC-AUC : {results[name]['ROC-AUC']:.4f}") # Tampilkan perbandingan dalam DataFrame results_df = pd.DataFrame(results).T print("\n=== PERBANDINGAN AKHIR ===") print(results_df.round(4))
Langkah 4 — Visualisasi Perbandingan Model
# Plot perbandingan semua model ax = results_df.plot( kind='bar', figsize=(10, 5), color=['#6c63ff', '#00d4aa', '#ffd93d'], rot=0, edgecolor='none' ) plt.title('Perbandingan Model: Accuracy, F1-Score, ROC-AUC', fontsize=13) plt.ylabel('Score') plt.ylim(0.6, 1.0) plt.legend(loc='lower right') plt.tight_layout() plt.show() # ROC Curve semua model dalam satu plot plt.figure(figsize=(8, 6)) colors = ['#6c63ff', '#00d4aa', '#ffd93d'] for (name, model), color in zip(models.items(), colors): y_proba = model.predict_proba(X_test_sc)[:, 1] fpr, tpr, _ = roc_curve(y_test, y_proba) auc = roc_auc_score(y_test, y_proba) plt.plot(fpr, tpr, color=color, lw=2, label=f'{name} (AUC={auc:.3f})') plt.plot([0,1],[0,1], '--', color='#546e7a') plt.xlabel('False Positive Rate') plt.ylabel('True Positive Rate (Recall)') plt.title('ROC Curve — Semua Model') plt.legend() plt.show()
Hasil yang Diharapkan
| Model | Accuracy | F1-Score | ROC-AUC | Keunggulan |
|---|---|---|---|---|
| Logistic Regression | ~80.5% | ~0.598 | ~0.850 | Interpretable, baseline kuat |
| KNN (K=9) | ~77.0% | ~0.552 | ~0.815 | Sederhana, tidak perlu asumsi |
| Decision Tree | ~79.0% | ~0.585 | ~0.820 | Mudah divisualisasi |
Langkah Selanjutnya di Dunia Nyata
- 1Handle Imbalanced DataGunakan teknik seperti SMOTE (oversampling), class_weight=’balanced’, atau pengaturan threshold probabilitas.
- 2Hyperparameter TuningGunakan GridSearchCV atau RandomizedSearchCV untuk menemukan kombinasi parameter terbaik secara sistematis.
- 3Ensemble MethodsCoba Random Forest atau Gradient Boosting (XGBoost, LightGBM) yang sering mengungguli model tunggal.
- 4DeploymentSimpan model terbaik dengan
joblib.dump(model, 'best_model.pkl')dan buat API dengan FastAPI atau Flask.
import joblib # Simpan model terbaik best_model = models['Logistic Regression'] joblib.dump(best_model, 'best_churn_model.pkl') joblib.dump(scaler, 'scaler.pkl') print("✅ Model tersimpan: best_churn_model.pkl") # Load dan gunakan kembali loaded_model = joblib.load('best_churn_model.pkl') loaded_scaler = joblib.load('scaler.pkl') # Prediksi pada data baru new_customer = np.array([[1, 24, 0, 65.9, 1580.0]]) # contoh new_scaled = loaded_scaler.transform(new_customer) prediction = loaded_model.predict_proba(new_scaled)[0] print(f"Probabilitas Churn : {prediction[1]:.2%}") print(f"Probabilitas Retain : {prediction[0]:.2%}")
🎉 Selamat! Bab Classification Models Selesai
Kamu telah mempelajari seluruh fondasi klasifikasi dalam Machine Learning: Logistic Regression, KNN, Decision Tree, metrik evaluasi, dan membangun pipeline end-to-end. Bab berikutnya akan membahas Ensemble Methods (Random Forest, Gradient Boosting) yang akan membawa performa modelmu ke level berikutnya!