Clustering buatan tangan pada chapter sebelumnya bekerja, tetapi tiga keputusannya masih kita pegang: memilih jangkar, menetapkan jumlahnya, dan membiarkan posisinya diam. K-Means adalah algoritma yang mengambil alih keputusan ketiga — jangkarnya (kini bernama centroid) digeser terus-menerus ke rata-rata anggotanya sampai berhenti bergerak. Algoritma ini menjadi clustering paling populer karena cepat, mudah dipahami, dan cukup baik untuk kebanyakan data berbentuk gumpalan. Pada chapter ini kita jalankan dulu algoritmanya secara manual dua putaran, lalu memakainya untuk men-segment 20 pelanggan Toko Kopi Kita lewat scikit-learn, dan menutup dengan kelemahan-kelemahan yang harus kita ketahui sebelum memakainya sungguhan.
Algoritma Empat Langkah #
K-Means menjawab satu pertanyaan berulang: kalau pusat kelompok ada di sini, siapa saja anggotanya? Empat langkahnya:
- Pilih
kcentroid awal —kadalah jumlah kelompok yang kita tetapkan di awal; posisi awal centroid bisa acak atau dengan strategi k-means++. - Tugaskan setiap titik ke centroid terdekat menurut jarak (biasanya Euclidean pada data yang sudah distandarisasi).
- Geser setiap centroid ke rata-rata seluruh titik yang menempel padanya.
- Ulangi langkah 2-3 sampai tidak ada titik yang berpindah kelompok dan centroid berhenti bergerak — disebut konvergen.
Langkah 2 dan 3 saling menopang seperti ayam dan telur: keanggotaan menentukan posisi centroid, posisi centroid menentukan keanggotaan. Iterasi inilah yang membuat K-Means “belajar” dari data — bukan dari label, melainkan dari konvergensi kedua langkah tersebut.
K-Means Manual: Dua Putaran Pertama #
Kita ambil enam pelanggan dari chapter sebelumnya dan jalankan mesinnya tanpa library, dua centroid dengan tebakan awal yang sengaja kurang tepat:
import numpy as np
# Enam pelanggan: (belanja ribu Rp/bulan, kunjungan/bulan)
titik = np.array([
[40, 2], [55, 1], [45, 4], # pengunjung sesekali
[150, 11], [160, 12], [140, 10], # pengunjung rutin
])
# Tebakan awal posisi centroid (dua titik di sekitar masing-masing gumpalan)
centroid = np.array([[42.0, 3.0], [145.0, 9.0]])
for putaran in range(1, 4):
# Langkah 2: tiap titik bergabung ke centroid terdekat
jarak = np.linalg.norm(titik[:, None, :] - centroid[None, :, :], axis=2)
label = jarak.argmin(axis=1)
# Langkah 3: centroid pindah ke rata-rata anggotanya
baru = np.array([titik[label == c].mean(axis=0) for c in range(len(centroid))])
print("Putaran %d: label = %s" % (putaran, label.tolist()))
print(" centroid baru = %s" % np.round(baru, 2).tolist())
if np.abs(centroid - baru).max() < 1e-9:
print(" centroid tidak berubah -> algoritma berhenti")
break
centroid = baruOutput yang Dihasilkan:
Putaran 1: label = [0, 0, 0, 1, 1, 1]
centroid baru = [[46.67, 2.33], [150.0, 11.0]]
Putaran 2: label = [0, 0, 0, 1, 1, 1]
centroid baru = [[46.67, 2.33], [150.0, 11.0]]
centroid tidak berubah -> algoritma berhentiMari kita telaah baris-baris kode di atas:
titiksebagai array NumPy memungkinkan penghitungan jarak semua titik ke semua centroid sekaligus lewat broadcasting.titik[:, None, :] - centroid[None, :, :]menghasilkan tabel selisih berukuran 6×2×2 — tiap titik dikurangi tiap centroid;np.linalg.norm(..., axis=2)meringkasnya menjadi matriks jarak 6×2.jarak.argmin(axis=1)memilih indeks centroid terdekat bagi tiap titik — inilah langkah penugasan.titik[label == c].mean(axis=0)menghitung rata-rata anggota klastercper fitur — inilah langkah penggeseran centroid.np.abs(centroid - baru).max() < 1e-9mendeteksi konvergensi: bila pergeseran terbesar nyaris nol, iterasi dihentikan.
Pada putaran pertama label langsung benar (tiga titik kiri ke centroid 0, tiga titik kanan ke centroid 1), centroid bergeser ke pusat gumpalannya masing-masing, dan putaran kedua tidak mengubah apa pun — konvergen. Pada data nyata, konvergensi jarang sesegera ini; penugasan awal yang kurang beruntung bisa membutuhkan banyak putaran atau berhenti di pembagian yang buruk. Masalah itu kita tangani lewat parameter n_init sebentar lagi.
K-Means scikit-learn pada 20 Pelanggan #
Sekarang skala yang lebih realistis: 20 pelanggan dengan dua fitur yang sama — belanja (ribu rupiah per bulan) dan frekuensi (kunjungan per bulan). Kita standarisasi dulu dengan StandardScaler (ingat pelajaran chapter sebelumnya: skala menentukan jarak), lalu memanggil KMeans:
import pandas as pd
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler
# 20 pelanggan Toko Kopi Kita: belanja (ribu Rp/bulan), frekuensi (kali/bulan)
pelanggan = pd.DataFrame({
"belanja": [40, 55, 35, 60, 45, 50,
150, 170, 160, 140, 175, 165,
380, 420, 350, 400, 390, 360, 410, 370],
"frekuensi": [2, 1, 3, 2, 4, 2,
11, 9, 12, 10, 8, 10,
6, 8, 7, 5, 9, 6, 7, 5],
})
fitur = ["belanja", "frekuensi"]
skala = StandardScaler()
fitur_z = skala.fit_transform(pelanggan[fitur])
model = KMeans(n_clusters=3, random_state=42, n_init="auto")
label = model.fit_predict(fitur_z)
pelanggan["cluster"] = label
profil = pelanggan.groupby("cluster").agg(
jumlah=("belanja", "size"),
belanja_rata2=("belanja", "mean"),
frekuensi_rata2=("frekuensi", "mean"),
).round(1)
print(profil)
print()
pusat_asli = skala.inverse_transform(model.cluster_centers_)
for c, (b, f) in enumerate(pusat_asli):
print("centroid cluster %d: belanja %.1f, frekuensi %.1f" % (c, b, f))
print()
print("inertia (pada data z-skor): %.2f" % model.inertia_)
print()
print(pelanggan.sort_values(["cluster", "belanja"]).to_string(index=False))Output yang Dihasilkan:
jumlah belanja_rata2 frekuensi_rata2
cluster
0 6 160.0 10.0
1 8 385.0 6.6
2 6 47.5 2.3
centroid cluster 0: belanja 160.0, frekuensi 10.0
centroid cluster 1: belanja 385.0, frekuensi 6.6
centroid cluster 2: belanja 47.5, frekuensi 2.3
inertia (pada data z-skor): 3.09
belanja frekuensi cluster
140 10 0
150 11 0
160 12 0
165 10 0
170 9 0
175 8 0
350 7 1
360 6 1
370 5 1
380 6 1
390 9 1
400 5 1
410 7 1
420 8 1
35 3 2
40 2 2
45 4 2
50 2 2
55 1 2
60 2 2Bedah kode dan hasilnya:
StandardScaler().fit_transformmengubah kedua fitur ke z-skor sebelum jarak dihitung; tanpa langkah ini, kolom belanja (rentang 35-420) akan menenggelamkan kolom frekuensi (rentang 1-12) persis seperti simulasi chapter sebelumnya.KMeans(n_clusters=3, random_state=42, n_init="auto")memuat tiga pengaturan penting sekaligus — lihat tabel di bawah.fit_predictmenjalankan pelatihan lalu mengembalikan label klaster setiap baris — gabunganfit()+predict()dalam satu panggilan.groupby("cluster").agg(...)memrofil hasilnya: jumlah anggota dan rata-rata tiap fitur. Tiga kelompok terbaca jelas — pelanggan hemat sesekali (belanja 47,5; frekuensi 2,3), pelanggan rutin hemat (160; 10,0), dan pelanggan rutin dengan belanja besar (385; 6,6).skala.inverse_transform(model.cluster_centers_)menerjemahkan posisi centroid dari ruang z-skor kembali ke rupiah dan kunjungan, sehingga bisa dibaca tim pemasaran.model.inertia_adalah jumlah kuadrat jarak semua titik ke centroid klasternya — angka 3,09 pada data z-skor; makin kecil makin rapat klaster. Ukuran ini menjadi bahan elbow method di chapter Evaluasi Clustering .
Tiga parameter yang wajib kita pahami:
| Parameter | Peran | Nilai pada contoh |
|---|---|---|
n_clusters | jumlah kelompok k — ditetapkan di awal | 3 |
random_state | seed untuk posisi awal centroid, agar hasil bisa direproduksi | 42 |
n_init | berapa kali algoritma diulang dari posisi awal berbeda; hasil terbaik yang dipakai | "auto" |
Kelemahan yang Perlu Kita Waspadai #
K-Means punya tiga asumsi yang tidak selalu berlaku pada data nyata:
| Asumsi K-Means | Akibat bila dilanggar | Penangkalnya |
|---|---|---|
| Klaster berbentuk gumpalan bulat yang sama ukurannya | klaster memanjang/lengkung terbelah paksa | DBSCAN (chapter Density-Based Clustering ) |
Jumlah k sudah diketahui di awal | k yang salah menghasilkan potongan yang menyesatkan | elbow method & silhouette (chapter Evaluasi Clustering ) |
| Setiap titik wajib masuk suatu klaster | pencilan menarik centroid dan merusak pembagian | DBSCAN menandai pencilan sebagai noise |
Tidak ada satupun algoritma clustering yang unggul untuk semua bentuk data — itulah mengapa Section ini membawa beberapa keluarga sekaligus. Kalau asumsi bulat terpenuhi dan k bisa diperkirakan, K-Means sulit ditanding kecepatannya; kalau bentuk datamu aneh-aneh, keluarga lain menunggu di chapter berikutnya.
Rangkuman #
- K-Means berputar pada empat langkah: pilih
kcentroid, tugaskan titik ke centroid terdekat, geser centroid ke rata-rata anggota, ulang sampai konvergen. - Versi manual memperlihatkan mekanismenya: setelah penugasan, centroid bergerak ke pusat gumpalan dan iterasi berikutnya tidak mengubah apa pun.
- Pada scikit-learn, standarisasi dikerjakan lebih dulu, lalu
KMeans(n_clusters=3, random_state=42, n_init="auto");fit_predictmenghasilkan label,cluster_centers_posisi centroid,inertia_ukuran kerapatan. - Nomor klaster hanyalah penanda tanpa urutan; kelemahan utama K-Means adalah asumsi bentuk bulat, keharusan menetapkan
kdi awal, dan kewajiban memasukkan semua titik.
Salah satu kelemahan itu — keharusan memilih k sebelum melihat hasilnya — dijawab oleh keluarga clustering berikutnya: hierarchical clustering membangun seluruh pohon pengelompokan lebih dulu, dan jumlah kelompok tinggal dipilih belakangan dengan memotong pohonnya. Lanjut ke chapter Hierarchical Clustering
.