AI & Data Science

K-Means Clustering: Panduan Lengkap

TOKEN

Panduan lengkap K-Means Clustering โ€” konsep dasar, algoritma langkah demi langkah, elbow method, silhouette score, implementasi scikit-learn, dan studi kasus segmentasi pelanggan

1. Pengenalan Clustering

Clustering adalah teknik unsupervised learning yang bertujuan mengelompokkan data ke dalam beberapa kelompok (cluster) berdasarkan kemiripan fitur. Berbeda dengan supervised learning, clustering tidak memiliki label โ€” model harus menemukan struktur tersembunyi dalam data secara mandiri.

K-Means Clustering adalah salah satu algoritma clustering yang paling populer dan banyak digunakan. Algoritma ini mempartisi data menjadi K kelompok di mana setiap titik data termasuk ke cluster dengan centroid (pusat cluster) terdekat.

Kapan Menggunakan Clustering?

Aplikasi Deskripsi Contoh Nyata
Segmentasi PelangganMengelompokkan pelanggan berdasarkan perilaku belanjaPelanggan premium, reguler, hemat
Document ClusteringMengelompokkan dokumen berdasarkan topikGrup artikel berita per kategori
Image SegmentationMemisahkan objek dalam gambarSegmentasi citra medis
Deteksi AnomaliMenemukan data yang tidak lazimDeteksi transaksi penipuan
RekomendasiMengelompokkan pengguna serupaSistem rekomendasi film
BioinformatikaMengelompokkan gen dengan ekspresi serupaAnalisis ekspresi gen

Visualisasi Konsep Clustering

Diagram: Konsep K-Means Clustering
  Sebelum Clustering               Sesudah Clustering (K=3)
  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”         โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
  โ”‚  ยท  ยท    ยท   ยท      โ”‚         โ”‚  โ—‹โ—‹โ—‹โ—‹    โ–ณโ–ณโ–ณโ–ณ       โ”‚
  โ”‚    ยท  ยท   ยท  ยท  ยท   โ”‚         โ”‚  โ—‹โ—‹โ—‹โ—‹โ—‹  โ–ณโ–ณโ–ณโ–ณโ–ณ      โ”‚
  โ”‚  ยท   ยท  ยท     ยท     โ”‚    โ”€โ”€โ–บ  โ”‚  โ—‹โ—‹โ—‹โ—‹    โ–ณโ–ณโ–ณโ–ณ       โ”‚
  โ”‚      ยท  ยท ยท  ยท  ยท   โ”‚         โ”‚     โ–กโ–กโ–กโ–ก   โ–ณโ–ณ       โ”‚
  โ”‚   ยท    ยท   ยท ยท ยท    โ”‚         โ”‚    โ–กโ–กโ–กโ–กโ–ก            โ”‚
  โ”‚     ยท   ยท ยท    ยท    โ”‚         โ”‚   โ–กโ–กโ–กโ–ก              โ”‚
  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜         โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
  
  Data tersebar tanpa pola          3 kelompok terbentuk:
  yang jelas                        โ—‹ Cluster 1, โ–ณ Cluster 2, โ–ก Cluster 3
                                    โ˜… = Centroid masing-masing cluster

2. Algoritma K-Means Langkah demi Langkah

Algoritma K-Means bekerja secara iteratif untuk mempartisi dataset menjadi K cluster non-overlapping. Setiap titik data dimiliki oleh tepat satu cluster. Berikut adalah langkah-langkah detailnya:

Langkah-Langkah Algoritma K-Means

Diagram: Algoritma K-Means Iterasi
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                    ALGORITMA K-MEANS                                โ”‚
โ”‚                                                                     โ”‚
โ”‚  INPUT: Dataset X (n titik), Jumlah cluster K                      โ”‚
โ”‚                                                                     โ”‚
โ”‚  1. INISIALISASI: Pilih K titik awal sebagai centroid               โ”‚
โ”‚     Cโ‚, Cโ‚‚, ..., Cโ‚– (random atau K-Means++)                       โ”‚
โ”‚                                                                     โ”‚
โ”‚  2. ASSIGNMENT STEP:                                                โ”‚
โ”‚     Untuk setiap titik data xแตข:                                    โ”‚
โ”‚       Hitung jarak ke semua centroid                                โ”‚
โ”‚       Assign xแตข ke cluster dengan centroid terdekat                โ”‚
โ”‚       cluster(xแตข) = argmin โ€–xแตข - Cโ‚–โ€–ยฒ                            โ”‚
โ”‚                                                                     โ”‚
โ”‚  3. UPDATE STEP:                                                    โ”‚
โ”‚     Untuk setiap cluster k:                                         โ”‚
โ”‚       Hitung ulang centroid sebagai rata-rata semua titik           โ”‚
โ”‚       Cโ‚– = (1/|Sโ‚–|) ฮฃ xแตข  untuk semua xแตข โˆˆ cluster k             โ”‚
โ”‚                                                                     โ”‚
โ”‚  4. KONVERGENSI:                                                    โ”‚
โ”‚     Ulangi langkah 2-3 sampai:                                      โ”‚
โ”‚       โ€ข Centroid tidak berubah (atau perubahan < threshold)         โ”‚
โ”‚       โ€ข Atau mencapai maksimum iterasi                              โ”‚
โ”‚                                                                     โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Visualisasi Per Iterasi

Diagram: K-Means per Iterasi
  Iterasi 0 (Inisialisasi)     Iterasi 1 (Assign+Update)
  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
  โ”‚ ยท  ยท    โ˜…A   ยท       โ”‚    โ”‚ โ—‹โ—‹ โ—‹  โ˜…A  โ–ณโ–ณโ–ณ       โ”‚
  โ”‚   ยท  ยท    ยท  ยท  ยท    โ”‚    โ”‚ โ—‹โ—‹โ—‹โ—‹   โ–ณโ–ณโ–ณโ–ณโ–ณ       โ”‚
  โ”‚ ยท   ยท  ยท    โ˜…B  ยท    โ”‚    โ”‚ โ—‹โ—‹โ—‹    โ–ณโ˜…A โ–ณโ–ณ      โ”‚
  โ”‚    ยท  ยท ยท  ยท  ยท  ยท   โ”‚    โ”‚  โ–กโ–กโ–กโ–กโ–ก  ยท  โ–ณ        โ”‚
  โ”‚  โ˜…C  ยท   ยท ยท ยท  ยท    โ”‚    โ”‚ โ–กโ–กโ˜…Bโ–กโ–ก              โ”‚
  โ”‚    ยท   ยท ยท    ยท      โ”‚    โ”‚  โ–กโ–กโ–ก โ–กโ–กโ–กโ˜…C          โ”‚
  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

  Iterasi 2 (Converged!)      Centroid bergerak ke pusat
  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    massa masing-masing cluster
  โ”‚ โ—‹โ—‹โ—‹โ—‹    โ–ณโ–ณโ–ณโ–ณ        โ”‚    pada setiap iterasi.
  โ”‚ โ—‹โ—‹โ—‹โ—‹โ—‹  โ–ณโ–ณโ–ณโ–ณโ–ณ        โ”‚
  โ”‚ โ—‹โ—‹โ—‹    โ–ณโ˜…Aโ–ณโ–ณ        โ”‚    Jarak yang digunakan:
  โ”‚   โ–กโ–กโ–กโ–กโ–ก   โ–ณ         โ”‚    Euclidean: โˆš(ฮฃ(xแตข-yแตข)ยฒ)
  โ”‚  โ–กโ–กโ˜…Bโ–กโ–ก             โ”‚
  โ”‚   โ–กโ–กโ–ก โ–กโ–กโ˜…C          โ”‚
  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Matematika di Balik K-Means

K-Means meminimalkan Within-Cluster Sum of Squares (WCSS), yaitu total jarak kuadrat dari setiap titik ke centroid cluster-nya:

๐Ÿ“ Rumus WCSS (Inertia)

WCSS = ฮฃโ‚– ฮฃโ‚“แตขโˆˆCโ‚– โ€–xแตข - ฮผโ‚–โ€–ยฒ

Di mana:

  • K = jumlah cluster
  • Cโ‚– = himpunan titik data dalam cluster ke-k
  • ฮผโ‚– = centroid (rata-rata) dari cluster ke-k
  • โ€–xแตข - ฮผโ‚–โ€–ยฒ = jarak Euclidean kuadrat dari titik xแตข ke centroid ฮผโ‚–

3. Implementasi Dasar K-Means dengan Scikit-learn

Mari kita implementasikan K-Means dari nol dan menggunakan scikit-learn. Kita akan menggunakan dataset buatan yang mudah divisualisasikan.

K-Means dengan Dataset Buatan

Python โ€” K-Means Clustering Dasar
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs
from sklearn.preprocessing import StandardScaler

# === GENERATE DATASET ===
# Membuat dataset sintetis dengan 3 cluster
np.random.seed(42)
X, y_true = make_blobs(
    n_samples=300,          # 300 titik data
    centers=4,              # 4 pusat cluster asli
    cluster_std=0.60,       # Standar deviasi tiap cluster
    random_state=42
)

print(f"Dataset shape: {X.shape}")
print(f"Fitur: 2 (x1, x2)")
print(f"Cluster asli: {len(np.unique(y_true))}")

# Visualisasi data asli (tanpa label)
plt.figure(figsize=(10, 5))

plt.subplot(1, 2, 1)
plt.scatter(X[:, 0], X[:, 1], s=30, alpha=0.7, c='gray')
plt.title('Data Asli (Tanpa Label)')
plt.xlabel('Fitur 1')
plt.ylabel('Fitur 2')
plt.grid(True, alpha=0.3)

# === TERAPKAN K-MEANS ===
kmeans = KMeans(
    n_clusters=4,           # Jumlah cluster
    init='k-means++',       # Inisialisasi cerdas
    n_init=10,              # Jalankan 10x, pilih terbaik
    max_iter=300,           # Maks iterasi
    random_state=42
)

# Fit model
kmeans.fit(X)

# Hasil clustering
labels = kmeans.labels_             # Label cluster tiap titik
centroids = kmeans.cluster_centers_ # Koordinat centroid
inertia = kmeans.inertia_           # WCSS value

print(f"\nHasil Clustering:")
print(f"  Jumlah cluster: {kmeans.n_clusters}")
print(f"  Inertia (WCSS): {inertia:.2f}")
print(f"  Iterasi: {kmeans.n_iter_}")
print(f"\nCentroid:")
for i, c in enumerate(centroids):
    print(f"  Cluster {i}: ({c[0]:.2f}, {c[1]:.2f})")

# Distribusi cluster
unique, counts = np.unique(labels, return_counts=True)
print(f"\nDistribusi cluster:")
for u, c in zip(unique, counts):
    print(f"  Cluster {u}: {c} titik ({c/len(X)*100:.1f}%)")

# Visualisasi hasil
plt.subplot(1, 2, 2)
colors = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4']
for i in range(4):
    mask = labels == i
    plt.scatter(X[mask, 0], X[mask, 1], s=30, alpha=0.7,
                c=colors[i], label=f'Cluster {i}')
plt.scatter(centroids[:, 0], centroids[:, 1], s=200, c='black',
            marker='โ˜…', edgecolors='white', linewidth=2,
            label='Centroid', zorder=5)
plt.title(f'K-Means Clustering (K=4, Inertia={inertia:.0f})')
plt.xlabel('Fitur 1')
plt.ylabel('Fitur 2')
plt.legend()
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()

Prediksi Cluster untuk Data Baru

Python โ€” Prediksi Data Baru
# Prediksi cluster untuk data baru
data_baru = np.array([
    [0, 4],    # Titik baru 1
    [-3, -2],  # Titik baru 2
    [5, 2],    # Titik baru 3
])

cluster_baru = kmeans.predict(data_baru)
jarak_centroid = kmeans.transform(data_baru)  # Jarak ke semua centroid

print("Prediksi cluster data baru:")
for i, (point, cluster) in enumerate(zip(data_baru, cluster_baru)):
    jarak = jarak_centroid[i]
    print(f"  Titik {point} โ†’ Cluster {cluster}")
    print(f"    Jarak ke centroid: {[f'{d:.2f}' for d in jarak]}")

4. Elbow Method โ€” Menentukan Jumlah Cluster Optimal

Salah satu tantangan terbesar dalam K-Means adalah menentukan jumlah cluster (K) yang optimal. Terlalu sedikit cluster = underfitting, terlalu banyak = overfitting. Elbow Method adalah teknik populer untuk memilih K terbaik.

Cara Kerja Elbow Method

  1. Jalankan K-Means untuk berbagai nilai K (misal K=1 sampai K=10)
  2. Catat nilai Inertia (WCSS) untuk setiap K
  3. Plot K vs Inertia
  4. Cari "siku" (elbow) โ€” titik di mana penurunan inertia mulai melambat secara signifikan
  5. K pada titik siku adalah jumlah cluster optimal
Diagram: Elbow Method
  Inertia (WCSS)
  โ”‚
  โ”‚โ˜…
  โ”‚ โ•ฒ
  โ”‚  โ•ฒ
  โ”‚   โ•ฒ
  โ”‚    โ•ฒ___         โ† Titik "siku" (elbow)
  โ”‚        โ•ฒ____       Di sini K=3 atau K=4
  โ”‚             โ•ฒ___
  โ”‚                 โ•ฒ______
  โ”‚                        โ•ฒ_______________
  โ”‚
  โ””โ”€โ”€โ”ฌโ”€โ”€โ”ฌโ”€โ”€โ”ฌโ”€โ”€โ”ฌโ”€โ”€โ”ฌโ”€โ”€โ”ฌโ”€โ”€โ”ฌโ”€โ”€โ”ฌโ”€โ”€โ”ฌโ”€โ”€โ”ฌโ”€โ”€โ”ฌโ”€โ”€โ”€โ”€ K
     1  2  3  4  5  6  7  8  9  10 11

  Penjelasan:
  โ€ข K=1โ†’2โ†’3: Inertia turun DRAMATIS (cluster baru sangat membantu)
  โ€ข K=3โ†’4โ†’5: Inertia masih turun tapi MELAMBAT
  โ€ข K>5: Inertia hampir DATAR (tidak ada manfaat tambahan)
  โ€ข K optimal = titik di mana kurva mulai "melengkung"

Implementasi Elbow Method

Python โ€” Elbow Method
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs

# Generate dataset
X, y_true = make_blobs(n_samples=300, centers=4, cluster_std=0.60, random_state=42)

# === ELBOW METHOD ===
K_range = range(1, 11)
inertias = []

for k in K_range:
    kmeans = KMeans(n_clusters=k, init='k-means++', n_init=10, random_state=42)
    kmeans.fit(X)
    inertias.append(kmeans.inertia_)
    print(f"K={k:2d} โ†’ Inertia: {kmeans.inertia_:.2f}")

# Hitung penurunan persentase
print("\nPenurunan Inertia:")
for i in range(1, len(inertias)):
    drop = (inertias[i-1] - inertias[i]) / inertias[i-1] * 100
    print(f"  K={i}โ†’{i+1}: {drop:.1f}% penurunan")

# Plot Elbow
plt.figure(figsize=(10, 6))
plt.plot(K_range, inertias, 'bo-', linewidth=2, markersize=8)
plt.fill_between(K_range, inertias, alpha=0.1, color='blue')

# Tandai elbow point
elbow_k = 4
elbow_idx = elbow_k - 1
plt.annotate(f'Elbow Point\nK={elbow_k}',
             xy=(elbow_k, inertias[elbow_idx]),
             xytext=(elbow_k + 1.5, inertias[elbow_idx] + 50),
             fontsize=12, fontweight='bold', color='red',
             arrowprops=dict(arrowstyle='->', color='red', lw=2))

plt.xlabel('Jumlah Cluster (K)', fontsize=12)
plt.ylabel('Inertia (WCSS)', fontsize=12)
plt.title('Elbow Method โ€” Menentukan K Optimal', fontsize=14)
plt.xticks(K_range)
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()

print(f"\nโœ“ K optimal berdasarkan Elbow Method: {elbow_k}")

Elbow Method Automatis

Python โ€” Deteksi Elbow Otomatis dengan KneeLocator
# pip install kneed
from kneed import KneeLocator

# Deteksi elbow secara otomatis
kneedle = KneeLocator(
    list(K_range),
    inertias,
    curve='convex',      # Bentuk kurva (convex = cembung)
    direction='decreasing' # Arah penurunan
)

optimal_k = kneedle.elbow
print(f"K optimal (otomatis): {optimal_k}")
print(f"Inertia pada K optimal: {inertias[optimal_k - 1]:.2f}")

# Plot dengan elbow yang ditandai otomatis
plt.figure(figsize=(10, 6))
plt.plot(K_range, inertias, 'bo-', linewidth=2, markersize=8)
kneedle.plot_knee()  # Plot dari kneed library
plt.xlabel('Jumlah Cluster (K)')
plt.ylabel('Inertia (WCSS)')
plt.title(f'Elbow Method โ€” K Optimal = {optimal_k}')
plt.grid(True, alpha=0.3)
plt.show()

5. Silhouette Score โ€” Evaluasi Kualitas Cluster

Elbow Method kadang ambigu โ€” siku tidak selalu jelas. Silhouette Score adalah metrik alternatif yang mengukur seberapa baik setiap titik data "cocok" dengan cluster-nya dibandingkan cluster lain.

Rumus Silhouette Score

๐Ÿ“ Rumus Silhouette per Titik

s(i) = (b(i) - a(i)) / max(a(i), b(i))

  • a(i) = rata-rata jarak titik i ke semua titik lain dalam cluster yang sama (intra-cluster)
  • b(i) = rata-rata jarak titik i ke semua titik dalam cluster terdekat lain (nearest-cluster)
  • s(i) bernilai antara -1 dan +1
Diagram: Interpretasi Silhouette Score
  Silhouette Score Interpretasi:

  +1  โ•‘โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•‘  Sempurna!
      โ•‘                                    โ•‘  Titik sangat cocok
      โ•‘                                    โ•‘  di cluster-nya
   0  โ•‘โ–“โ–“โ–“โ–“โ–“โ–“โ–“โ–“โ–“โ–“โ–“โ–“โ–“โ–“โ–“โ–“โ–“โ–“โ–“โ–“โ–“โ–“โ–“โ–“โ–“โ–“โ–“โ–“โ–“โ–“โ–“โ–“โ–“โ–“โ•‘  Netral
      โ•‘                                    โ•‘  Titik di batas 2 cluster
      โ•‘                                    โ•‘
  -1  โ•‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ•‘  Salah cluster!
      โ•‘                                    โ•‘  Titik lebih dekat
      โ•‘                                    โ•‘  ke cluster lain

  Panduan Interpretasi:
  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
  โ”‚ 0.71 - 1.00  โ†’ Struktur kuat, cluster bagus โ”‚
  โ”‚ 0.51 - 0.70  โ†’ Struktur wajar               โ”‚
  โ”‚ 0.26 - 0.50  โ†’ Struktur lemah                โ”‚
  โ”‚ < 0.25       โ†’ Tidak ada struktur cluster    โ”‚
  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Implementasi Silhouette Score

Python โ€” Silhouette Analysis
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs
from sklearn.metrics import silhouette_score, silhouette_samples

# Generate dataset
X, y_true = make_blobs(n_samples=300, centers=4, cluster_std=0.60, random_state=42)

# === SILHOUETTE SCORE UNTUK BERBAGAI K ===
K_range = range(2, 11)
sil_scores = []

for k in K_range:
    kmeans = KMeans(n_clusters=k, init='k-means++', n_init=10, random_state=42)
    labels = kmeans.fit_predict(X)
    score = silhouette_score(X, labels)
    sil_scores.append(score)
    print(f"K={k:2d} โ†’ Silhouette Score: {score:.4f}")

# Plot Silhouette Score vs K
plt.figure(figsize=(10, 6))
plt.plot(K_range, sil_scores, 'go-', linewidth=2, markersize=8)
plt.fill_between(K_range, sil_scores, alpha=0.1, color='green')

best_k = K_range[np.argmax(sil_scores)]
best_score = max(sil_scores)
plt.annotate(f'K Terbaik = {best_k}\nScore = {best_score:.3f}',
             xy=(best_k, best_score),
             xytext=(best_k + 1, best_score - 0.03),
             fontsize=12, fontweight='bold', color='red',
             arrowprops=dict(arrowstyle='->', color='red', lw=2))

plt.xlabel('Jumlah Cluster (K)', fontsize=12)
plt.ylabel('Silhouette Score', fontsize=12)
plt.title('Silhouette Score โ€” Menentukan K Optimal', fontsize=14)
plt.xticks(K_range)
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()

print(f"\nโœ“ K optimal berdasarkan Silhouette: {best_k} (score: {best_score:.4f})")

Silhouette Plot per Cluster

Python โ€” Silhouette Plot Detail
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_samples, silhouette_score

# Fungsi untuk membuat silhouette plot
def plot_silhouette(X, n_clusters, ax):
    kmeans = KMeans(n_clusters=n_clusters, init='k-means++',
                    n_init=10, random_state=42)
    cluster_labels = kmeans.fit_predict(X)
    
    sil_avg = silhouette_score(X, cluster_labels)
    sample_sil_values = silhouette_samples(X, cluster_labels)
    
    y_lower = 10
    colors = plt.cm.Set2(np.linspace(0, 1, n_clusters))
    
    for i in range(n_clusters):
        ith_sil = sample_sil_values[cluster_labels == i]
        ith_sil.sort()
        
        size_cluster = ith_sil.shape[0]
        y_upper = y_lower + size_cluster
        
        ax.fill_betweenx(np.arange(y_lower, y_upper),
                         0, ith_sil,
                         facecolor=colors[i], edgecolor=colors[i],
                         alpha=0.7)
        ax.text(-0.05, y_lower + 0.5 * size_cluster, str(i),
                fontweight='bold', fontsize=11)
        y_lower = y_upper + 10
    
    ax.axvline(x=sil_avg, color='red', linestyle='--', linewidth=2,
               label=f'Rata-rata = {sil_avg:.3f}')
    ax.set_xlabel('Silhouette Coefficient')
    ax.set_ylabel('Cluster')
    ax.set_title(f'K = {n_clusters} (Avg Silhouette: {sil_avg:.3f})')
    ax.legend()

# Plot untuk beberapa nilai K
fig, axes = plt.subplots(2, 2, figsize=(14, 10))
axes = axes.flatten()

for idx, k in enumerate([2, 3, 4, 5]):
    plot_silhouette(X, k, axes[idx])

plt.suptitle('Silhouette Plot untuk Berbagai Nilai K', fontsize=14, y=1.02)
plt.tight_layout()
plt.show()

6. Studi Kasus: Segmentasi Pelanggan

Sekarang kita terapkan K-Means pada kasus nyata: segmentasi pelanggan berdasarkan perilaku belanja. Dataset yang kita gunakan adalah Mall Customer Segmentation โ€” dataset populer yang berisi data pelanggan pusat perbelanjaan.

Python โ€” Segmentasi Pelanggan dengan K-Means
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler

# === BUAT DATASET PELANGGAN ===
np.random.seed(42)
n = 200

data_pelanggan = pd.DataFrame({
    'customer_id': range(1, n + 1),
    'annual_income': np.concatenate([
        np.random.normal(25, 5, 50),   # Income rendah
        np.random.normal(55, 8, 60),   # Income menengah
        np.random.normal(85, 10, 50),  # Income tinggi
        np.random.normal(45, 6, 40),   # Income menengah-rendah
    ]).round(1),
    'spending_score': np.concatenate([
        np.random.normal(20, 8, 50),   # Spending rendah
        np.random.normal(50, 10, 60),  # Spending menengah
        np.random.normal(75, 8, 50),   # Spending tinggi
        np.random.normal(35, 7, 40),   # Spending rendah-menengah
    ]).clip(1, 100).round(1),
    'age': np.random.randint(18, 65, n),
})

print("Dataset Pelanggan:")
print(data_pelanggan.describe())
print(f"\nSample data:")
print(data_pelanggan.head(10))

# === PREPROCESSING ===
# Pilih fitur untuk clustering
fitur = ['annual_income', 'spending_score']
X_pelanggan = data_pelanggan[fitur].values

# Normalisasi (PENTING untuk K-Means!)
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X_pelanggan)

print(f"\nData sebelum scaling:")
print(f"  Mean: {X_pelanggan.mean(axis=0)}")
print(f"  Std:  {X_pelanggan.std(axis=0)}")
print(f"\nData setelah scaling:")
print(f"  Mean: {X_scaled.mean(axis=0).round(4)}")
print(f"  Std:  {X_scaled.std(axis=0).round(4)}")

# === ELBOW METHOD ===
K_range = range(1, 11)
inertias = []
sil_scores = []

for k in K_range:
    km = KMeans(n_clusters=k, init='k-means++', n_init=10, random_state=42)
    km.fit(X_scaled)
    inertias.append(km.inertia_)
    if k >= 2:
        from sklearn.metrics import silhouette_score
        sil = silhouette_score(X_scaled, km.labels_)
        sil_scores.append(sil)
        print(f"K={k}: Inertia={km.inertia_:.1f}, Silhouette={sil:.3f}")
    else:
        print(f"K={k}: Inertia={km.inertia_:.1f}")

# Plot Elbow & Silhouette berdampingan
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 5))

ax1.plot(K_range, inertias, 'bo-', linewidth=2)
ax1.set_xlabel('K')
ax1.set_ylabel('Inertia')
ax1.set_title('Elbow Method')
ax1.grid(True, alpha=0.3)

ax2.plot(range(2, 11), sil_scores, 'go-', linewidth=2)
ax2.set_xlabel('K')
ax2.set_ylabel('Silhouette Score')
ax2.set_title('Silhouette Analysis')
ax2.grid(True, alpha=0.3)

plt.tight_layout()
plt.show()

# === CLUSTERING DENGAN K OPTIMAL ===
K_OPTIMAL = 5  # Berdasarkan elbow + silhouette
kmeans_final = KMeans(n_clusters=K_OPTIMAL, init='k-means++',
                       n_init=10, random_state=42)
data_pelanggan['cluster'] = kmeans_final.fit_predict(X_scaled)

# Profil setiap cluster
print(f"\n{'='*60}")
print(f"PROFIL CLUSTER (K={K_OPTIMAL})")
print(f"{'='*60}")
for i in range(K_OPTIMAL):
    cluster_data = data_pelanggan[data_pelanggan['cluster'] == i]
    print(f"\n--- Cluster {i} ({len(cluster_data)} pelanggan) ---")
    print(f"  Income rata-rata:  ${cluster_data['annual_income'].mean():.1f}k")
    print(f"  Spending rata-rata: {cluster_data['spending_score'].mean():.1f}")
    print(f"  Usia rata-rata:    {cluster_data['age'].mean():.0f} tahun")

# Visualisasi scatter plot berwarna cluster
plt.figure(figsize=(10, 8))
colors = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FFEAA7']
cluster_names = [
    'Budget Conscious', 'Average Spenders', 'Premium Customers',
    'High Income Low Spend', 'Young Big Spenders'
]

for i in range(K_OPTIMAL):
    mask = data_pelanggan['cluster'] == i
    plt.scatter(data_pelanggan[mask]['annual_income'],
                data_pelanggan[mask]['spending_score'],
                s=60, alpha=0.7, c=colors[i],
                label=f'Cluster {i}: {cluster_names[i]}',
                edgecolors='white', linewidth=0.5)

# Plot centroid
centroids_orig = scaler.inverse_transform(kmeans_final.cluster_centers_)
plt.scatter(centroids_orig[:, 0], centroids_orig[:, 1],
            s=250, c='black', marker='โ˜…', edgecolors='white',
            linewidth=2, label='Centroid', zorder=5)

plt.xlabel('Annual Income ($k)', fontsize=12)
plt.ylabel('Spending Score (1-100)', fontsize=12)
plt.title('Segmentasi Pelanggan โ€” K-Means Clustering', fontsize=14)
plt.legend(fontsize=9)
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()

7. Kelebihan, Kekurangan & Tips Praktis

Kelebihan K-Means

Kelebihan Penjelasan
Sederhana & IntuitifMudah dipahami dan diimplementasikan
SkalabelBekerja efisien untuk dataset besar (O(nยทKยทdยทi))
CepatKonvergensi relatif cepat dibanding algoritma lain
Garansi KonvergensiDijamin konvergen (walau mungkin ke local minimum)
Mudah DiinterpretasiCentroid memberikan "representasi" tiap cluster

Kekurangan K-Means

Kekurangan Penjelasan Solusi
Perlu K ditentukan di awalJumlah cluster harus ditentukan sebelumnyaElbow method, Silhouette
Sensitif inisialisasiHasil bisa berbeda tergantung centroid awalGunakan k-means++, n_init
Asumsi cluster bulatMengasumsikan cluster berbentuk sphericalGunakan DBSCAN/GMM
Sensitif outlierOutlier bisa mempengaruhi centroidGunakan K-Medoids
Hanya cluster convexTidak bisa menemukan bentuk non-convexSpectral clustering
Skala fitur berpengaruhFitur dengan skala besar mendominasiStandarisasi (StandardScaler)

Tips Praktis K-Means

๐Ÿ’ก Tips Best Practice K-Means
  • Selalu lakukan normalisasi/standarisasi โ€” K-Means berbasis jarak, skala fitur sangat berpengaruh
  • Gunakan init='k-means++' โ€” Inisialisasi cerdas yang menghindari local minimum
  • Set n_init=10 atau lebih โ€” Jalankan beberapa kali dengan inisialisasi berbeda
  • Gunakan Elbow + Silhouette bersamaan โ€” Keduanya saling melengkapi
  • Visualisasikan hasilnya โ€” Plot cluster dan centroid untuk validasi intuitif
  • Cek distribusi cluster โ€” Cluster yang sangat timpang perlu investigasi
  • Hapus outlier terlebih dahulu โ€” Outlier bisa mendistorsi centroid

8. K-Means vs Algoritma Clustering Lainnya

K-Means bukan satu-satunya algoritma clustering. Berikut perbandingan dengan beberapa alternatif populer:

Perbandingan Algoritma Clustering

Aspek K-Means DBSCAN Hierarchical Gaussian Mixture
Input K?โœ… YaโŒ TidakโŒ Tidak (cut tree)โœ… Ya
Bentuk ClusterSphericalArbitraryArbitraryElliptical
Handling OutlierโŒ Burukโœ… Bagusโš ๏ธ Sedangโš ๏ธ Sedang
Skalabilitasโœ… Sangat baikโš ๏ธ SedangโŒ Lambat O(nยณ)โš ๏ธ Sedang
DeterministikโŒ Tidakโœ… Yaโœ… YaโŒ Tidak
Best ForCluster bulat, data besarCluster arbitrary, noiseEksplorasi hierarkiCluster overlap

Variasi K-Means

Variasi Perbedaan Kegunaan
K-Means++Inisialisasi centroid lebih cerdasHindari local minimum
Mini-Batch K-MeansGunakan mini-batch untuk updateDataset sangat besar
K-Medoids (PAM)Centroid = titik data aktualLebih robust terhadap outlier
Bisecting K-MeansTop-down: split satu cluster jadi duaHasil lebih stabil
Kernel K-MeansGunakan kernel trickCluster non-linear

Mini-Batch K-Means untuk Dataset Besar

Python โ€” Mini-Batch K-Means
import time
import numpy as np
from sklearn.cluster import KMeans, MiniBatchKMeans
from sklearn.datasets import make_blobs

# Dataset besar
X_big, y_big = make_blobs(n_samples=100000, centers=10,
                           cluster_std=1.0, random_state=42)
print(f"Dataset: {X_big.shape[0]} titik, {X_big.shape[1]} fitur")

# Bandingkan K-Means vs Mini-Batch
for name, Model in [('K-Means', KMeans), ('Mini-Batch K-Means', MiniBatchKMeans)]:
    start = time.time()
    model = Model(n_clusters=10, init='k-means++', n_init=3,
                  random_state=42, batch_size=1024 if name == 'Mini-Batch K-Means' else None)
    model.fit(X_big)
    elapsed = time.time() - start
    print(f"\n{name}:")
    print(f"  Waktu: {elapsed:.2f} detik")
    print(f"  Inertia: {model.inertia_:.2f}")
    print(f"  Iterasi: {model.n_iter_}")

9. Quiz Pemahaman

Uji pemahaman kamu tentang K-Means Clustering dengan menjawab pertanyaan berikut:

๐Ÿง  Quiz: K-Means Clustering

1. Apa yang diukur oleh Inertia (WCSS) dalam K-Means?

2. Pada Elbow Method, titik "siku" menunjukkan:

3. Mengapa normalisasi/standarisasi PENTING sebelum K-Means?

4. Silhouette Score bernilai -1 sampai +1. Score 0.85 menunjukkan:

5. Apa keunggulan k-means++ dibanding inisialisasi random biasa?

๐ŸŽฏ Ringkasan Artikel
  • K-Means mengelompokkan data ke K cluster berdasarkan jarak ke centroid
  • Elbow Method membantu menentukan K optimal dari plot Inertia vs K
  • Silhouette Score mengukur kualitas clustering (range -1 sampai +1)
  • Normalisasi sangat penting karena K-Means berbasis jarak
  • k-means++ lebih baik dari inisialisasi random biasa
  • K-Means cepat dan sederhana, tetapi asumsi cluster berbentuk spherical