Fitur sudah dibuat dan disekalakan; kini giliran mesinnya bekerja. Pada bagian ini kita menjalankan K-Means pada 30 pelanggan dengan dua fitur ternormalisasi, menempelkan label cluster ke setiap pelanggan, lalu membaca pusat tiap cluster dalam satuan yang bisa dibaca manusia. Kita memakai k=3 sejak awal — tiga gerombolan terlihat pada eksplorasi Bagian 4 dan Bu Rina punya tiga ide program — tetapi pilihan ini belum boleh diterima begitu saja; ia akan diadili dengan angka silhouette dan elbow pada Bagian 7.
Cara Kerja K-Means dalam Singkat #
K-Means mengelompokkan titik dengan cara yang bisa diceritakan dalam empat langkah. Pertama, ia meletakkan k buah pusat (centroid) awal pada data — penempatan awal cerdas k-means++ menjauhkan pusat-pusat itu satu sama lain. Kedua, setiap pelanggan ditugaskan ke pusat terdekatnya berdasarkan jarak Euclidean. Ketiga, setiap pusat digeser ke rata-rata seluruh anggotanya. Keempat, langkah kedua dan ketiga diulang sampai tidak ada pelanggan yang berpindah kelompok. Detail algoritmenya sudah dibedah pada chapter K-Means Clustering
dan panduan clustering scikit-learn
.
Dua parameter praktis perlu kita pegang: random_state=42 membekukan unsur acak pada pemilihan pusat awal sehingga siapa pun yang menjalankan ulang kode ini mendapat hasil yang persis sama, dan n_init="auto" memakai konvensi scikit-learn modern untuk jumlah inisialisasi yang dijalankan. Keterulangan seperti ini bukan hiasan — laporan akhir kita berdiri di atas klaim bahwa seluruh angkanya bisa direproduksi.
Melatih Model dan Menempelkan Label #
Alur penuhnya pendek: muat data bersih, buat fitur, sekalakan, latih model, lalu tempelkan labelnya ke data. Label itulah yang mengubah sekumpulan titik menjadi segmen:
import pandas as pd
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler
def muat_bersih(path):
"""Muat data mentah pelanggan dan terapkan seluruh langkah pembersihan."""
df = pd.read_csv(path)
df = df.drop_duplicates().reset_index(drop=True)
df["kunjungan_30hari"] = pd.to_numeric(df["kunjungan_30hari"], errors="coerce")
df = df.dropna(subset=["kunjungan_30hari"]).reset_index(drop=True)
df["kota"] = df["kota"].str.strip().str.title()
df["kunjungan_30hari"] = df["kunjungan_30hari"].astype(int)
return df
bersih = muat_bersih("../data/pelanggan.csv")
bersih["belanja_per_kunjungan"] = (
bersih["belanja_ribu"] / bersih["kunjungan_30hari"]
)
fitur = bersih[["kunjungan_30hari", "belanja_per_kunjungan"]]
skala = StandardScaler().fit_transform(fitur)
model = KMeans(n_clusters=3, random_state=42, n_init="auto")
label = model.fit_predict(skala)
bersih["cluster"] = label
for nomor, n in bersih["cluster"].value_counts().sort_index().items():
print(f"cluster {nomor}: {n} pelanggan")
print("\nSepuluh pelanggan pertama beserta label clusternya:")
tampil = bersih[["pelanggan", "kunjungan_30hari",
"belanja_per_kunjungan", "cluster"]].head(10)
print(tampil.to_string(index=False))Output yang Dihasilkan:
cluster 0: 10 pelanggan
cluster 1: 8 pelanggan
cluster 2: 12 pelanggan
Sepuluh pelanggan pertama beserta label clusternya:
pelanggan kunjungan_30hari belanja_per_kunjungan cluster
Siti Rahmawati 25 20.0 0
Bambang Sutrisno 4 120.0 1
Andi Firmansyah 10 40.0 2
Budi Santoso 22 21.0 0
Nurul Aini 12 35.0 2
Ratna Dewi 5 140.0 1
Dewi Lestari 20 19.0 0
Dimas Prasetyo 8 55.0 2
Agus Pratama 24 24.0 0
Ayu Kusuma 11 45.0 2Mari kita bedah hasilnya:
- Tiga cluster terbentuk: 10, 8, dan 12 pelanggan — komposisi yang persis menggemakan tiga gerombolan eksplorasi Bagian 4 (8-12-10 pada rentang kunjungan rendah-menengah-tinggi). Mata kita dan algoritme sepakat.
fit_predictmenjalankan pelatihan sekaligus mengembalikan label untuk setiap baris — setara dengan memanggilfitlalupredictsecara terpisah.- Label terbaca masuk akal baris demi baris. Siti (25 kunjungan, 20 ribu per kunjungan) masuk cluster 0 bersama Budi dan Dewi yang profilnya serupa; Bambang (4 kunjungan, 120 ribu) masuk cluster 1 bersama Ratna; Andi dan Nurul yang menengah masuk cluster 2. Pola yang sama seperti panel kanan scatter plot Bagian 4.
Membaca Pusat Cluster dalam Satuan Asli #
Label menunjuk kelompok, tetapi angka yang bisa dibaca pemangku kepentingan adalah pusat tiap cluster dalam satuan asli. Objek scaler menyimpan rata-rata dan simpangan baku dari proses fit, sehingga inverse_transform bisa mengembalikan pusat ternormalisasi ke satuan kunjungan dan rupiah ribu:
import pandas as pd
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler
def muat_bersih(path):
"""Muat data mentah pelanggan dan terapkan seluruh langkah pembersihan."""
df = pd.read_csv(path)
df = df.drop_duplicates().reset_index(drop=True)
df["kunjungan_30hari"] = pd.to_numeric(df["kunjungan_30hari"], errors="coerce")
df = df.dropna(subset=["kunjungan_30hari"]).reset_index(drop=True)
df["kota"] = df["kota"].str.strip().str.title()
df["kunjungan_30hari"] = df["kunjungan_30hari"].astype(int)
return df
bersih = muat_bersih("../data/pelanggan.csv")
bersih["belanja_per_kunjungan"] = (
bersih["belanja_ribu"] / bersih["kunjungan_30hari"]
)
fitur = bersih[["kunjungan_30hari", "belanja_per_kunjungan"]]
pensekala = StandardScaler()
skala = pensekala.fit_transform(fitur)
model = KMeans(n_clusters=3, random_state=42, n_init="auto").fit(skala)
pusat_asli = pensekala.inverse_transform(model.cluster_centers_)
pusat = pd.DataFrame(
pusat_asli.round(2),
columns=["kunjungan_pusat", "belanja_per_kunjungan_pusat"],
)
pusat.insert(0, "cluster", range(3))
print("Pusat tiap cluster, dikembalikan ke satuan asli:")
print(pusat.to_string(index=False))Output yang Dihasilkan:
Pusat tiap cluster, dikembalikan ke satuan asli:
cluster kunjungan_pusat belanja_per_kunjungan_pusat
0 21.40 21.30
1 4.50 115.00
2 10.58 43.58Tabel pusat tersebut adalah ringkasan perilaku paling ringkas dari seluruh proyek:
- Cluster 0 berporos pada 21,40 kunjungan dengan 21,30 ribu per kunjungan — pengunjung rutin yang belanja kecil-kecil. Karena pusat cluster adalah rata-rata anggotanya, angka ini sekaligus janji bahwa anggota cluster ini memang berdekatan di titik itu.
- Cluster 1 berporos pada 4,50 kunjungan dengan 115,00 ribu per kunjungan — kebalikan sempurna dari cluster 0: jarang datang, tetapi sekali datang belanja besar.
- Cluster 2 di tengah: 10,58 kunjungan dan 43,58 ribu per kunjungan.
Pusat-pusat itu memang terpisah jelas, dan komposisi 10-8-12 terasa benar. Tetapi perasaan benar bukan barang bukti. Berapa pun k yang kita pilih, K-Means selalu menghasilkan kelompok — termasuk k yang salah. Kita adili pilihan k=3 dengan dua alat ukur pada Bagian 7: Mengevaluasi Clustering
.