Regresi linear pada chapter sebelumnya memprediksi angka: berapa gelas terjual, berapa nilai transaksi. Padahal pertanyaan bisnis yang sama pentingnya berbentuk ya-tidak: pelanggan ini akan berhenti belanja atau tetap setia, transaksi ini penipuan atau bukan, pengunjung akan membeli atau pergi. Jawaban yang tepat untuk pertanyaan semacam itu bukan satu angka melainkan satu peluang, dan peluang harus berada di antara 0 dan 1 — wilayah yang tidak bisa dijamin garis lurus. Regresi logistik menyelesaikan masalah itu dengan satu kelengkungan berbentuk S, dan pada chapter ini kita memakainya untuk memperkirakan churn pelanggan Toko Kopi Kita: siapa yang berpeluang besar berhenti, dan fitur apa yang menahan pelanggan tetap tinggal.

Mengapa Garis Lurus Tidak Cukup untuk Hasil Biner #

Target biner dikodekan sebagai 0 dan 1 — misalnya churn = 1 berarti pelanggan berhenti. Bila kita memasangkan garis y = a + b*x pada target seperti itu, taksiran garis bisa jatuh di bawah 0 atau di atas 1, dan tidak ada cara membaca “peluang -0,3”. Regresi logistik mengganti garis dengan dua tahap: gabungan linear yang sama seperti regresi linear, lalu dipadatkan ke rentang 0 sampai 1 oleh fungsi sigmoid:

text
z = a + b1*x1 + b2*x2 + ...     gabungan linear, sama seperti regresi linear
p = 1 / (1 + e^(-z))            fungsi sigmoid: apa pun nilai z, hasil selalu 0..1

Kita lihat dulu wujud sigmoid itu sendiri sebelum memakai model utuh:

python
import numpy as np

def sigmoid(z):
    return 1 / (1 + np.exp(-z))

for z in [-4, -2, 0, 2, 4]:
    print("z = %3d -> peluang %.3f" % (z, sigmoid(z)))

Output yang Dihasilkan:

text
z =  -4 -> peluang 0.018
z =  -2 -> peluang 0.119
z =   0 -> peluang 0.500
z =   2 -> peluang 0.881
z =   4 -> peluang 0.982

Mari kita telaah baris-baris kode di atas:

  1. def sigmoid(z) mengimplementasikan rumus 1 / (1 + e^(-z)) langsung dari blok text — np.exp(-z) menghitung e^(-z).
  2. Sigmoid monoton naik: makin besar z, makin besar peluang, tetapi laju kenaikannya melambat di kedua ujung. Dari z = -4 ke z = -2 peluang naik 0,10; di sekitar nol peluang melompat dari 0,119 ke 0,881; setelah z = 2 peluang nyaris datar mendekati 1.
  3. z = 0 menghasilkan peluang tepat 0,500 — titik tengah inilah yang nanti menjadi ambang bawaan pengambilan keputusan.

Bentuk kurva S seperti ini wajar untuk peluang: di wilayah tengah, perubahan fitur menggeser peluang dengan cepat; di wilayah ujung, peluang sudah hampir pasti dan sulit digeser lagi.

Data Churn dan Pelatihan Model #

Kasus kita adalah 22 anggota klub kopi Toko Kopi Kita. Untuk tiap anggota tercatat frekuensi_belanja (kali per bulan), lama_member_bulan (berapa bulan terdaftar), dan status churn pada akhir periode: 1 berarti berhenti, 0 berarti masih aktif:

csv
nama,frekuensi_belanja,lama_member_bulan,churn
Budi,2,3,1
Siti,7,24,0
Dewi,1,6,1
Rani,5,18,0
Agus,3,4,1
Joko,6,30,0
Maya,2,9,1
Ririn,8,36,0
Fajar,4,12,0
Nina,1,2,1
Tono,3,8,1
Lina,6,20,0
Yoga,2,5,1
Sari,5,15,0
Dimas,4,6,1
Ratna,7,28,0
Gilang,3,14,0
Putri,1,4,1
Hendra,5,10,0
Ayu,6,16,0
Wulan,6,22,1
Bagas,2,12,0

Pola umumnya terbaca langsung: anggota yang jarang datang dan baru bergabung cenderung berhenti, sedangkan yang rutin dan sudah lama bertahan. Tetapi datanya tidak sempurna terpisah — Wulan rajin dan senior namun tetap berhenti, sedangkan Bagas jarang datang namun setia. Dua baris inilah yang membuat model belajar dari kecenderungan, bukan hafalan. Pelatihannya memakai kelas LogisticRegression dari scikit-learn:

python
import numpy as np
import pandas as pd
from sklearn.linear_model import LogisticRegression

member = pd.read_csv("member.csv")

fitur = ["frekuensi_belanja", "lama_member_bulan"]
model = LogisticRegression()
model.fit(member[fitur], member["churn"])

print("Intersep (log-odds): %.3f" % model.intercept_[0])
print("Koefisien (log-odds) dan odds ratio:")
for nama, koef in zip(fitur, model.coef_[0]):
    print("- %-18s: %6.3f  ->  odds ratio %.2f" % (nama, koef, np.exp(koef)))

Output yang Dihasilkan:

text
Intersep (log-odds): 3.687
Koefisien (log-odds) dan odds ratio:
- frekuensi_belanja : -0.181  ->  odds ratio 0.83
- lama_member_bulan : -0.273  ->  odds ratio 0.76

Tiga hal pada kode di atas:

  1. model.fit(member[fitur], member["churn"]) memakai pola yang sama dengan LinearRegression di chapter sebelumnya: X berupa data frame fitur dua dimensi, y kolom target. Kolom nama tidak ikut karena bukan fitur numerik — cara mengolah kolom teks menjadi fitur dibahas tuntas pada Section Feature Engineering .
  2. model.coef_[0] berbentuk larik karena jumlahnya mengikuti jumlah fitur; zip(fitur, model.coef_[0]) memasangkan tiap nama fitur dengan koefisiennya.
  3. np.exp(koef) mengubah koefisien menjadi odds ratio — terjemahan yang layak dibaca orang, yang kita bedah sekarang.

Koefisien sebagai Log-Odds dan Odds Ratio #

Koefisien regresi logistik tidak bisa dibaca seperti kemiringan regresi linear. Garis lurus mengubah y sebesar b tiap x naik satu satuan; sigmoid mengubah peluang dengan laju yang bergantung pada posisi awal, sehingga satu angka “perubahan peluang” tidak ada. Yang berubah tetap dan terukur adalah peluang ratio atau odds: perbandingan peluang kejadian terhadap peluang tidak kejadian, odds = p / (1 - p). Koefisien bekerja pada logaritma odds itu — disebut logit — dan e^koefisien menyatakan pengali odds tiap fitur naik satu satuan:

text
logit(p) = ln(p / (1 - p)) = z
odds ratio = e^b   (pengali odds tiap x naik satu satuan)

Baca hasil model kita dengan cara itu. Odds ratio frekuensi_belanja sebesar 0,83 berarti: setiap tambahan satu kali belanja per bulan mengalikan odds churn dengan 0,83 — odds berhentinya pelanggan menyusut menjadi 83% dari semula. Odds ratio lama_member_bulan 0,76 berarti setiap tambahan satu bulan menjadi member mengalikan odds churn dengan 0,76. Keduanya di bawah 1, artinya kedua fitur bergerak searah dengan kesetiaan: makin sering belanja dan makin lama menjadi member, makin kecil kecenderungan berhenti — persis pola yang kita duga dari data.

Prediksi Peluang dan Ambang Keputusan #

Model yang telah dilatih menjadi mesin peluang: berikan profil pelanggan, keluar taksiran peluang churn. Metode predict_proba() mengembalikan peluang tiap kelas, dan kolom kedua ([:, 1]) adalah peluang kelas 1 — churn:

python
import pandas as pd
from sklearn.linear_model import LogisticRegression

member = pd.read_csv("member.csv")

fitur = ["frekuensi_belanja", "lama_member_bulan"]
model = LogisticRegression()
model.fit(member[fitur], member["churn"])

calon = pd.DataFrame({
    "frekuensi_belanja": [1, 4, 7],
    "lama_member_bulan": [3, 10, 30],
})
peluang = model.predict_proba(calon)[:, 1]

for i in range(len(calon)):
    print("Frekuensi %d kali, member %2d bulan -> peluang churn %.3f"
          % (calon["frekuensi_belanja"][i], calon["lama_member_bulan"][i], peluang[i]))

print("Prediksi kelas (ambang 0.5):", (peluang >= 0.5).astype(int).tolist())
print("Akurasi pada data latih    : %.2f" % model.score(member[fitur], member["churn"]))

Output yang Dihasilkan:

text
Frekuensi 1 kali, member  3 bulan -> peluang churn 0.936
Frekuensi 4 kali, member 10 bulan -> peluang churn 0.558
Frekuensi 7 kali, member 30 bulan -> peluang churn 0.003
Prediksi kelas (ambang 0.5): [1, 1, 0]
Akurasi pada data latih    : 0.86

Cara membaca keluaran tersebut:

  1. Tiga profil mewakili tiga wilayah kurva: pendatang baru yang jarang belanja nyaris pasti berhenti (0,936); pelanggan tengah berada di wilayah curam kurva dengan peluang 0,558 — nyaris seimbang, keputusan paling rawan; pelanggan senior yang rutin praktis aman (0,003).
  2. Ambang 0,5 mengubah peluang menjadi keputusan kelas: dua profil pertama diprediksi churn. Ambang ini pilihan, bukan hukum — bila menghubungi pelanggan berisiko murah sedangkan kehilangan pelanggan mahal, kita bisa menurunkan ambang ke 0,3 supaya lebih banyak pelanggan diselamatkan.
  3. Akurasi 0,86 pada data latih berarti 3 dari 22 anggota salah diprediksi — di antaranya Wulan dan Bagas, dua baris yang memang melawan pola. Angka ini hanya ilustrasi kecocokan terhadap data yang dipakai melatih; menilai model secara sah menuntut data uji yang terpisah beserta metrik lengkap seperti precision dan recall, seluruhnya kita bahas pada Section Evaluasi dan Validasi Model .

Rangkuman #

  • Hasil biner dimodelkan lewat gabungan linear z yang dipadatkan ke rentang 0–1 oleh fungsi sigmoid 1 / (1 + e^(-z)); sigmoid berbentuk kurva S dengan titik tengah peluang 0,5 saat z = 0.
  • LogisticRegression scikit-learn dilatih dengan pola fit(X, y) yang sama dengan regresi linear; predict_proba() mengembalikan peluang tiap kelas.
  • Koefisien bekerja pada skala log-odds; np.exp(koefisien) mengubahnya menjadi odds ratio — pengali odds per kenaikan satu satuan fitur.
  • Odds ratio 0,83 untuk frekuensi belanja dan 0,76 untuk lama member: keduanya menurunkan kecenderungan churn, dengan besaran yang bisa dilaporkan.
  • Ambang 0,5 adalah pilihan keputusan yang bisa digeser sesuai biaya salah mengklasifikasikan; akurasi data latih bukan bukti mutu model.

Kita kini memegang dua model kakak beradik: regresi linear untuk menaksir angka dan regresi logistik untuk menaksir peluang. Keduanya bertumpu pada kolom numerik — harga, frekuensi, lama member — padahal sebagian besar kolom dunia nyata berupa kategori seperti menu, cabang, dan tingkat kepuasan. Bagaimana menganalisis dan menguji pola antar kolom kategorikal itu adalah tugas chapter berikutnya. Lanjut ke chapter Analisis Data Kategorikal .

Referensi #

  1. scikit-learn — FAQ
  2. NumPy — The absolute basics for beginners