Bab 8 ~4 jam

Unsupervised Learning

Temukan struktur tersembunyi dalam data tanpa label — melalui clustering dan reduksi dimensi.

8.1 Clustering K-Means

K-Means mempartisi data ke dalam K cluster dengan meminimalkan jumlah kuadrat dalam-cluster. Sederhana, cepat, tapi perlu menentukan K.

min Σᵢ Σⱼ ||xⱼ - μᵢ||² di mana μᵢ adalah centroid cluster i
from sklearn.cluster import KMeans from sklearn.metrics import silhouette_score # Cari K optimal dengan metode elbow inertias = [] silhouettes = [] K_range = range(2, 11) for k in K_range: km = KMeans(n_clusters=k, n_init=10, random_state=42) labels = km.fit_predict(X_scaled) inertias.append(km.inertia_) silhouettes.append(silhouette_score(X_scaled, labels)) # Plot kurva elbow plt.plot(K_range, inertias, 'bo-') plt.xlabel('K'); plt.ylabel('Inersia') # Model final km_final = KMeans(n_clusters=4, n_init=10, random_state=42) df['cluster'] = km_final.fit_predict(X_scaled)
Keterbatasan: K-Means mengasumsikan cluster berbentuk bulat dengan ukuran serupa. Kesulitan dengan bentuk tidak reguler, kepadatan berbeda, dan data berdimensi tinggi. Selalu scaling fitur terlebih dahulu.

8.2 Clustering Hierarkis

Membangun pohon cluster (dendrogram). Tidak perlu menentukan K — potong pohon pada level yang diinginkan.

from sklearn.cluster import AgglomerativeClustering from scipy.cluster.hierarchy import dendrogram, linkage # Dendrogram (gunakan subset untuk keterbacaan) Z = linkage(X_scaled[:100], method='ward') plt.figure(figsize=(12, 5)) dendrogram(Z, leaf_rotation=90) # Agglomerative clustering agg = AgglomerativeClustering(n_clusters=4, linkage='ward') labels = agg.fit_predict(X_scaled) # Opsi linkage: 'ward', 'complete', 'average', 'single'

8.3 DBSCAN

Clustering berbasis kepadatan yang bisa menemukan cluster berbentuk apa saja dan mengidentifikasi titik noise. Tidak perlu menentukan K.

from sklearn.cluster import DBSCAN # eps = radius tetangga, min_samples = titik minimum dbscan = DBSCAN(eps=0.5, min_samples=5) labels = dbscan.fit_predict(X_scaled) n_clusters = len(set(labels)) - (1 if -1 in labels else 0) n_noise = list(labels).count(-1) print(f"Cluster: {n_clusters}, Noise: {n_noise}")
Memilih eps: Gunakan grafik k-distance — plot jarak ke tetangga ke-k untuk setiap titik (k = min_samples). Carilah "siku" sebagai nilai eps.

8.4 Analisis Komponen Utama (PCA)

PCA menemukan arah ortogonal varians maksimum. Ini adalah metode go-to untuk reduksi dimensi.

from sklearn.decomposition import PCA # Fit PCA pca = PCA(n_components=0.95) # Pertahankan 95% varians X_pca = pca.fit_transform(X_scaled) print(f"Komponen: {pca.n_components_}") print(f"Varians yang dijelaskan: {pca.explained_variance_ratio_}") # Scree plot pca_full = PCA().fit(X_scaled) plt.plot(range(1, len(pca_full.explained_variance_ratio_)+1), np.cumsum(pca_full.explained_variance_ratio_), 'bo-') plt.axhline(y=0.95, color='r', linestyle='--') plt.xlabel('Komponen'); plt.ylabel('Varians Kumulatif')
Kapan menggunakan PCA: Sebelum K-Means (kurangi noise), untuk visualisasi (2-3 komponen), untuk mempercepat algoritma, atau menghapus multikolinearitas. Selalu scaling terlebih dahulu — PCA berbasis varians.

8.5 t-SNE & UMAP

Reduksi dimensi non-linier untuk visualisasi. Mempertahankan struktur lokal dengan baik tapi tidak cocok sebagai langkah preprocessing.

from sklearn.manifold import TSNE # t-SNE (selalu kurangi dimensi dulu dengan PCA!) X_pca_50 = PCA(n_components=50).fit_transform(X_scaled) tsne = TSNE(n_components=2, perplexity=30, random_state=42) X_tsne = tsne.fit_transform(X_pca_50) plt.scatter(X_tsne[:, 0], X_tsne[:, 1], c=labels, cmap='viridis', alpha=0.6) # UMAP (pip install umap-learn) import umap reducer = umap.UMAP(n_neighbors=15, min_dist=0.1, random_state=42) X_umap = reducer.fit_transform(X_scaled)
Peringatan: t-SNE/UMAP hanya untuk visualisasi. Jarak dan ukuran cluster di plot 2D tidak bermakna. Jangan pernah menarik kesimpulan kuantitatif dari geometri plot.
Latihan: Pada dataset digit MNIST, bandingkan K-Means, hierarkis, dan DBSCAN. Visualisasikan dengan t-SNE. Algoritma mana yang paling baik menangkap 10 kelas digit?