Dua chapter pertama Section ini memprediksi angka: harga rumah dan pendapatan harian. Sekarang kita menghadapi pertanyaan yang bentuknya berbeda — pelanggan aplikasi belanja ini akan berhenti (churn) atau tetap setia? Regresi logistik adalah model klasifikasi biner paling pertama yang layak dicoba: cepat, stabil, dan mengeluarkan peluang alih-alih sekadar label. Kita pernah membahasnya dari sisi statistik di Regresi Logistik pada Section Teknik Analisis Data
; kali ini sudut pandangnya machine learning — fokus pada alur fit()-predict()-evaluasi dengan data uji, pembacaan predict_proba(), dan batas keputusan model.
Dari Menaksir Angka ke Menaksir Peluang #
Regresi logistik memakai mesin yang sama dengan regresi linear — gabungan linear z = b0 + b1*x1 + b2*x2 — lalu memadatkannya ke rentang 0 sampai 1 dengan fungsi sigmoid. Hasilnya dibaca sebagai peluang kelas positif. Perbedaan pola pemakaiannya dengan regresi linear bisa dirangkum singkat:
| Aspek | Regresi linear | Regresi logistik |
|---|---|---|
| Jenis tugas | Regresi (target angka) | Klasifikasi biner (target 0/1) |
Keluaran predict() | Angka bergerak bebas | Label kelas 0 atau 1 |
| Keluaran tambahan | predict() itu sendiri | predict_proba() berisi peluang tiap kelas |
| Metrik awal yang cocok | R² | Akurasi |
Kenapa tidak memakai regresi linear untuk target 0/1? Karena garis lurus bisa mengeluarkan “peluang” -0,3 atau 1,7 — nilai yang tidak bisa dibaca sebagai peluang. Sigmoid memastikan keluaran selalu berada di antara 0 dan 1; pembahasan lengkap bentuk kurvanya sudah kita kerjakan di chapter statistik, jadi kita langsung ke pemakaian praktisnya.
Melatih Model Churn #
Kasus kita: 36 pelanggan aplikasi belanja “Keranjang Kita”. Dua fitur tercatat untuk tiap pelanggan — order_per_bulan (rata-rata jumlah pesanan per bulan) dan hari_sejak_order (berapa hari sejak pesanan terakhir) — beserta status churn di akhir kuartal: 1 berhenti berbelanja, 0 tetap setia. Ada 17 pelanggan berhenti dan 19 bertahan, cukup seimbang untuk latihan:
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
pelanggan = pd.DataFrame({
"order_per_bulan": [1, 7, 3, 8, 3, 6, 1, 2, 2, 2, 5, 6, 1, 4, 6, 7,
5, 5, 4, 3, 0, 2, 4, 7, 6, 10, 3, 9, 2, 8, 4, 9, 7, 8, 6, 9],
"hari_sejak_order": [10, 25, 5, 5, 15, 10, 30, 14, 26, 8, 15, 20, 18, 20,
4, 3, 5, 3, 8, 25, 22, 20, 12, 6, 2, 3, 8, 1, 3, 2,
3, 2, 9, 7, 8, 6],
"churn": [1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0,
0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
})
fitur = ["order_per_bulan", "hari_sejak_order"]
X = pelanggan[fitur]
y = pelanggan["churn"]
X_latih, X_uji, y_latih, y_uji = train_test_split(X, y, test_size=0.3,
stratify=y, random_state=42)
model = LogisticRegression()
model.fit(X_latih, y_latih)
print("Intersep (log-odds): %6.2f" % model.intercept_[0])
for nama, koef in zip(fitur, model.coef_[0]):
print("%-16s: koef %6.2f -> odds ratio %.2f" % (nama, koef, np.exp(koef)))
print("Akurasi data latih : %.2f" % model.score(X_latih, y_latih))
print("Akurasi data uji : %.2f" % model.score(X_uji, y_uji))Output yang Dihasilkan:
Intersep (log-odds): 0.17
order_per_bulan : koef -1.15 -> odds ratio 0.32
hari_sejak_order: koef 0.58 -> odds ratio 1.78
Akurasi data latih : 0.96
Akurasi data uji : 0.91Mari kita telaah baris-baris kode di atas:
train_test_split(..., test_size=0.3, stratify=y, random_state=42): 25 pelanggan menjadi data latih dan 11 menjadi data uji. Argumenstratify=ymenjaga proporsi kelas di kedua bagian tetap menyerupai data asli — penting untuk klasifikasi agar data uji tidak kebetulan berisi satu kelas saja.model.score(X_uji, y_uji)pada model klasifikasi mengembalikan akurasi: porsi prediksi yang tepat. Model kita benar pada 10 dari 11 pelanggan uji (0,91) — satu-satunya yang salah adalah pelanggan dengan 4 order per bulan dan 8 hari tanpa belanja, tepat di wilayah abu-abu antara dua kelas.model.coef_[0]berbentuk larik dua nilai karena ada dua fitur dan satu kelas positif;np.exp(koef)mengubahkannya menjadi odds ratio yang manusiawi dibaca.
Membaca Koefisien dan Odds Ratio #
Koefisien regresi logistik bekerja pada skala log-odds, sehingga cara membacanya berbeda dari kemiringan regresi linear. Odds ratio hasil np.exp(koefisien) mengubahnya menjadi pengali:
| Fitur | Koefisien | Odds ratio | Cara membacanya |
|---|---|---|---|
order_per_bulan | -1,15 | 0,32 | Tiap tambahan 1 order/bulan mengalikan odds churn dengan 0,32 — makin rajin order, makin kecil kecenderungan berhenti |
hari_sejak_order | +0,58 | 1,78 | Tiap tambahan 1 hari tanpa belanja mengalikan odds churn dengan 1,78 — makin lama diam, makin besar kecenderungan berhenti |
Kedua angka itu masuk akal secara bisnis dan searah dengan pola data yang kita lihat. Jika butuh pendalaman teori log-odds, tabel uji formal, dan cara melaporkannya, pembahasan penuhnya ada di chapter statistik ; pada alur machine learning, koefisien biasanya cukup dipakai sebagai pemeriksaan arah.
Peluang Tiap Pelanggan dan Batas Keputusan #
predict() hanya mengembalikan label akhir, padahal informasi paling berharga justru di tengah prosesnya. Metode predict_proba() memperlihatkan peluang lengkap; kolom [:, 1] adalah peluang kelas 1 (churn). Kita uji empat profil pelanggan:
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
pelanggan = pd.DataFrame({
"order_per_bulan": [1, 7, 3, 8, 3, 6, 1, 2, 2, 2, 5, 6, 1, 4, 6, 7,
5, 5, 4, 3, 0, 2, 4, 7, 6, 10, 3, 9, 2, 8, 4, 9, 7, 8, 6, 9],
"hari_sejak_order": [10, 25, 5, 5, 15, 10, 30, 14, 26, 8, 15, 20, 18, 20,
4, 3, 5, 3, 8, 25, 22, 20, 12, 6, 2, 3, 8, 1, 3, 2,
3, 2, 9, 7, 8, 6],
"churn": [1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0,
0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
})
fitur = ["order_per_bulan", "hari_sejak_order"]
X_latih, X_uji, y_latih, y_uji = train_test_split(
pelanggan[fitur], pelanggan["churn"], test_size=0.3,
stratify=pelanggan["churn"], random_state=42)
model = LogisticRegression()
model.fit(X_latih, y_latih)
calon = pd.DataFrame({
"order_per_bulan": [7, 4, 4, 2],
"hari_sejak_order": [3, 6, 9, 25],
})
peluang = model.predict_proba(calon)[:, 1]
for i in range(len(calon)):
print("Order %d kali/bln, tidak belanja %2d hari -> peluang churn %.2f"
% (calon["order_per_bulan"][i], calon["hari_sejak_order"][i], peluang[i]))
b0 = model.intercept_[0]
b1, b2 = model.coef_[0]
print()
print("Batas keputusan (z = 0):")
for order in [2, 4, 8]:
hari_batas = -(b0 + b1 * order) / b2
print(" order %d kali/bln -> peluang churn melewati 0.5 setelah %.0f hari tanpa belanja"
% (order, hari_batas))Output yang Dihasilkan:
Order 7 kali/bln, tidak belanja 3 hari -> peluang churn 0.00
Order 4 kali/bln, tidak belanja 6 hari -> peluang churn 0.27
Order 4 kali/bln, tidak belanja 9 hari -> peluang churn 0.68
Order 2 kali/bln, tidak belanja 25 hari -> peluang churn 1.00
Batas keputusan (z = 0):
order 2 kali/bln -> peluang churn melewati 0.5 setelah 4 hari tanpa belanja
order 4 kali/bln -> peluang churn melewati 0.5 setelah 8 hari tanpa belanja
order 8 kali/bln -> peluang churn melewati 0.5 setelah 16 hari tanpa belanjaTiga hal dari keluaran tersebut:
- Dua profil tengah memperlihatkan batas keputusan bekerja: pelanggan 4 order per bulan bernilai peluang 0,27 pada 6 hari tanpa belanja, lalu 0,68 pada 9 hari — peluangnya menyeberangi 0,5 di antara keduanya.
predict()hanya mengembalikan kelas 0 untuk yang pertama dan kelas 1 untuk yang kedua, padahal jarak keduanya tipis. - Batas keputusan adalah tempat
z = 0— peluang tepat 0,5. Dengan dua fitur, batas itu berupa garisb0 + b1*order + b2*hari = 0; kita tinggal membalik rumusnya menjadihari_batas = -(b0 + b1*order)/b2. Pelanggan di atas garis (makin lama diam) masuk wilayah churn. - Garis batas ini bisa langsung dipakai tim operasional: “pelanggan 4 order per bulan yang telah 8 hari tidak belanja masuk daftar tindak lanjut”. Angka hasil model menjadi aturan kerja yang konkret — dan hanya regresi logistik yang mengeluarkan garis lurus semacam ini secara alami.
Kekuatan dan Kelemahan Regresi Logistik #
| Aspek | Keterangan |
|---|---|
| Cepat dan stabil | Pelatihan sekejap walau data besar; jarang bermasalah |
| Keluaran peluang | Bisa diranking dan diberi ambang sesuai biaya keputusan |
| Batas keputusan garis lurus | Hanya memisahkan kelas yang bisa dipisah garis |
| Koefisien bisa dibaca | Odds ratio memberi arah pengaruh tiap fitur |
| Perlu fitur numerik siap pakai | Fitur kategori harus diolah dulu (feature engineering) |
Kapan Kita Memakainya #
Regresi logistik adalah baseline wajib untuk klasifikasi biner: skor spam atau bukan, gagal bayar atau tidak, churn atau setia. Ia menonjol ketika kita butuh peluang yang bisa diatur ambangnya, ketika batas keputusan berbentuk garis sudah memadai, dan ketika hasil harus bisa dijelaskan ke pihak non-teknis. Ketika batas antar kelas berbentuk bertingkat — misalnya “setia bila order tinggi ATAU baru saja belanja” — kita perlu model yang menggambar aturan bertingkat itu sendiri. Model itulah bintang chapter berikutnya.
Rangkuman #
- Regresi logistik memadatkan gabungan linear
zke rentang 0-1 dengan sigmoid;predict()memberi label,predict_proba()[:, 1]memberi peluang kelas positif. - Alur ML-nya baku:
train_test_split()denganstratify=y,fit(), lalu akurasi lewatscore()— contoh kita mencapai 0,91 pada data uji. - Koefisien dibaca lewat odds ratio
np.exp(koef): 0,32 per order tambahan dan 1,78 per hari tanpa belanja. - Batas keputusan adalah tempat
z = 0; dengan dua fitur ia garis lurus yang bisa dibalik menjadi aturan operasional. - Ambang 0,5 bisa digeser sesuai biaya kesalahan; akurasi saja belum cukup untuk data timpang.
Selama ini kita memakai satu rumus linear untuk semua pelanggan. Bagaimana jika pola keputusannya memang bertingkat-tingkat — pelanggan istimewa bila belanja di atas 500 ribu, atau bila datang lebih dari enam kali sebulan? Model yang menulis aturan seperti itu sendiri menunggu kita di chapter Decision Tree .