☀️Siang
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

Artikel: Ml K Means Clustering Artikel: Ml K Means Clustering


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

Visualisasi Per Iterasi

Diagram: K-Means per Iterasi
○○ ○ ★A △△△
○○○○ △△△△△
○○○ △★A △△
□□□□□ · △
□□★B□□
□□□ □□□★C
○○○○ △△△△
○○○○○ △△△△△
○○○ △★A△△
□□□□□ △
□□★B□□
□□□ □□★C
Iterasi 0 (Inisialisasi) Iterasi 1 (Assign+Update)
· · ★A ·
· · · · ·
· · · ★B ·
· · · · · ·
★C · · · · ·
· · · ·
Iterasi 2 (Converged!) Centroid bergerak ke pusat
massa masing-masing cluster
pada setiap iterasi.
Jarak yang digunakan:
Euclidean: √(Σ(xᵢ-yᵢ)²)

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

Diagram

Inertia (WCSS)

K

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
🔍 Zoom
100%
🎨 Tema