Writing

Machine Learning (7) — Clustering Algorithms

Unsupervised clustering: distance metrics, K-Means, improvements, density clustering, and evaluation.

Clustering algorithms

Previous chapters covered supervised methods. This chapter introduces unsupervised learning—clustering. There is no target label “y”; we partition data by internal structure so within-cluster samples are similar.

Different clustering ideas yield different algorithms. This chapter covers three main ideas and their algorithms.

Topics:

  • “Distance”

  • K-Means

  • K-Means variants

  • Density clustering

Algorithm idea: “birds of a feather flock together”

We introduce similarity and basic similarity measures.

Algorithm idea

“Birds of a feather flock together.” Classification appears everywhere in nature and society—a class is a set of similar elements. Parents teach categories with cards: “This is a car.” “This is a plane.” “This is a fish.” “This is a bird.” “This is a circle.” “This is a rectangle.” Science often discovers new things and names classes. Categories we know come from common sense; for computers and clustering, algorithms group similar data. Our task: partition data into categories with minimal between-category similarity.

Partitioning by similarity

Compute pairwise similarity; group high-similarity samples. Common measures:

  • Minkowski distance (norm distance). p=1: Manhattan (2D example):

image

image

Manhattan distance

p=2: Euclidean:

image

p→∞: Chebyshev:

image

Euclidean is most common; Chebyshev when data are flattened.

  • Cosine similarity

Two features → cosine:

image

Common for text: bag-of-words vectors, cosine similarity—effective in practice.

  • Jaccard coefficient — for binary (0,1) features:

image

In item-based collaborative filtering, Jaccard improves on cosine when user ratings alone miss other signal—good for sparse data.

Clusters

ML names a category a cluster. Splitting M samples into k clusters requires k

image

K-Means procedure

Illustrated:

image

K-Means illustrated

In words and formulas:

  • N samples; choose two centers manually.

  • Distance from each sample to each center (often Euclidean, §9.1):

image

Split into two clusters; new centers = cluster means:

image

Repeat until stop condition. ### 8.1.1 K-Means loss

Minimize sum of distances to centers. Per-sample distance:

image

Minimize loss; partial derivatives give center update:

image

K-Means issues

Two major issues:

K-Means uses the mean as centroid; outliers skew the mean. Example: cluster {2,4,6,8,100} → mean 24, far from most points; median 6 (K-Medoids) may be better.

  • Initialization sensitivity

K-Means depends on initial centers. Fix: multiple random inits and pick best, or better init (below). Example: four obvious regions:

image

Clustering dataset

Random centers A,B,C,D:

image

K-Means result:

image

K-Means example

Use sklearn simulated data; K-Means clustering and centers.

  • Build data

Gaussian blobs, 4 clusters, 1000 samples:

from sklearn.datasets import make_blobs
N = 1000
centers = 4

Two features:

X, Y = make_blobs(n_samples=N, n_features=2, centers=centers, random_state=0)
  • Model
from sklearn.cluster import KMeans

Specify k, max iterations, or center change threshold.

km = KMeans(n_clusters=centers, init='random', random_state=28)

km.fit(X)
  • Predict
y_hat = km.predict(X)
  • Centers and inertia (loss)
print("所有样本距离所属簇中心点的总距离和为:%.5f" % km.inertia_)  print("所有的中心点聚类中心坐标:")  cluter_centers = km.cluster_centers_  print(cluter_centers)  print("score其实就是所有样本点离所属簇中心点距离和的相反数:")  print(km.score(X))

Output:

所有样本距离所属簇中心点的总距离和为:1764.19457

所有的中心点聚类中心坐标:

[[-6.32351035  7.09545595]

 [-7.51888142 -2.01003574]

 [ 6.0528514   0.24636947]

 [ 4.26881816  1.08317321]]

score其实就是所有样本点离所属簇中心点距离和的相反数:

-1764.19457007324
  • Plot
import matplotlib.pyplot as plt  import matplotlib as mpl

cm = mpl.colors.ListedColormap(list('rgby'))  plt.figure(figsize=(15, 9), facecolor='w')  plt.subplot(121)  plt.title(u'原始数据')  plt.grid(True)  plt.scatter(X[:, 0], X[:, 1], c=Y, s=30, cmap=cm, edgecolors='none')  plt.subplot(122)  plt.scatter(X[:, 0], X[:, 1], c=y_hat, s=30, cmap=cm, edgecolors='none')  plt.title(u'K-Means算法聚类结果')  plt.grid(True)  plt.show()

Result:

image

Original vs K-Means

With k=3 and k=5:

image

K-Means with different k

K-Means improvements

K-Means is simple and widely used, but k must be chosen and init matters. Variants below.

K-Means++

Init centers as far apart as possible to reduce bad random starts. Steps:

q Pick one point as first center

q For each x, compute D(x) = sum of distances to existing centers; pick next center with probability proportional to D(x)²

q Repeat until k centers

Works well unless data are very scattered.

Reference: Bahman Bahmani, Benjamin Moseley, Andrea Vattani. Scalable K-Means++.

K-Means||

k-means++ is sequential (k passes)—hard to parallelize on huge data.

K-Means|| samples k points per round, repeat O(k log n) times, cluster those k points, use as K-Means init. Often a few rounds suffice.

Bisecting K-Means

Another init fix: start with one cluster, bisect one cluster (largest SSE or largest cluster) repeatedly until k clusters.

Steps:

q Start with all samples in one cluster

q Bisect one cluster with K-Means into two; add to queue

q Repeat until stop (cluster count, SSE, iterations)

q Queue holds final clusters

Split rule:

(1)Pick cluster with largest SSE:

image

(2)Split largest cluster by size

Canopy algorithm

Canopy (2000), popular with Hadoop, pre-clusters for algorithms like k-means—reduces distance computations.

(1)Samples L=x₁…xₘ, thresholds T₁, T₂ (T₁>T₂)

(2)Take P from L; distance to all canopy centers (first point starts a canopy); min distance D(P,aⱼ)

(3)If D < T₁, add P to that canopy

(4)If D < T₂, also recompute center, remove P from L

(5)If D > T₁, P starts new canopy

(6)Repeat until L stable or empty

Flowchart:

image

Canopy flowchart

Canopies may overlap; every point belongs to some canopy. Canopy + k-means: T₁, T₂ critical—too large T₁ → too many iterations/canopies; too small → poor accuracy.

image

Canopy illustration

Mini Batch K-Means

Uses mini-batches instead of full data each step—faster, slightly less accurate; good for huge datasets. Same idea as mini-batch SGD.

(1)Sample subset; K-Means for k centers

(2)Sample more points; assign to nearest center

(3)Update centers

(4)Repeat until stable

Similar use cases to K-Means; below we compare speed.

8.1.1 Clustering evaluation

Supervised metrics: accuracy, precision, recall. Unsupervised: clusters need not match labels unless distribution aligns or within-cluster similarity > between-cluster.

Common metrics:

  • Homogeneity (completeness) — one cluster, one true class; homogeneity ≈ per-cluster purity:

image

  • Rand index (RI)

Given true labels C, clustering K; a = pairs same in both, b = pairs different in both:

image

Numerator: agreeing pairs. Denominator: all pairs. RI ∈ [0,1]; higher is better. Random clustering may not be ~0; Adjusted Rand Index (ARI):

image

ARI ∈ [-1,1]; higher = better agreement.

Pros: (1) random ARI ≈ 0; (2) [-1,1]; (3) compare algorithms. Cons: needs true labels.

  • Silhouette coefficient

No labels needed.

a = mean intra-cluster distance for i (smaller → i fits cluster). b = min mean distance to other clusters (larger → i not in those). Silhouette s:

image

s near 1: good; near -1: wrong cluster; ~0: boundary. sklearn: metrics.silhouette_score.

from sklearn import metrics  from sklearn.metrics import pairwise_distances
from sklearn import datasets
dataset = datasets.load_iris()
X = dataset.data
 y = dataset.target
import numpy as np
from sklearn.cluster import KMeans
kmeans_model = KMeans(n_clusters=3, random_state=1).fit(X)
labels = kmeans_model.labels_
metrics.silhouette_score(X, labels, metric='euclidean')

Output:

兰德系数为:

0.5730973570083832

Example: Mini Batch K-Means vs K-Means

Compare speed on larger data; evaluate with metrics above.

API: http://scikit-learn.org/0.19/modules/generated/sklearn.cluster.KMeans.html#sklearn.cluster.KMeans

# n_clusters, init, n_init (multiple inits), max_iter

sklearn.cluster.KMeans(n_clusters=8, init='k-means++', n_init=10, max_iter=300) [](#sklearn.cluster.MiniBatchKMeans "Permalink to this definition")

1. Imports

import time  import numpy as np  import matplotlib.pyplot as plt  import matplotlib as mpl  from sklearn.cluster import MiniBatchKMeans, KMeans  from sklearn.metrics.pairwise import pairwise_distances_argmin  from sklearn.datasets.samples_generator import make_blobs

2. Data

# 3 blobs, 3000 samples, 2 features

# centers = [[1, 1], [-1, -1], [1, -1]]  clusters = len(centers)  # k=3  # X, Y = make_blobs(n_samples=3000, centers=centers, cluster_std=0.7, random_state=0)

3. Models

k_means = KMeans(init='k-means++', n_clusters=clusters, random_state=28)  t0 = time.time()  k_means.fit(X)  km_batch = time.time() - t0  print ("K-Means算法模型训练消耗时间:%.4fs" % km_batch)

batch_size = 100  mbk = MiniBatchKMeans(init='k-means++', n_clusters=clusters, batch_size=batch_size, random_state=28)  t0 = time.time()  mbk.fit(X)  mbk_batch = time.time() - t0  print ("Mini Batch K-Means算法模型训练消耗时间:%.4fs" % mbk_batch)

# Output:

L- Means算法模型训练消耗时间:0.0416s

M- Mini Batch K-Means算法模型训练消耗时间:0.0150s

4. Predict

km_y_hat = k_means.predict(X)  mbkm_y_hat = mbk.predict(X)  print(km_y_hat[:10])  print(mbkm_y_hat[:10])  print(k_means.cluster_centers_)  print(mbk.cluster_centers_)

# Output:

[0 1 0 2 1 1 1 1 2 1]

[[-1.07159013 -1.00648645]

 [ 0.96700708  1.01837274]

 [ 1.07705469 -1.06730994]]

[[ 1.02538969 -1.08781328]

 [-1.06046903 -1.01509453]

 [ 0.97734743  1.08610316]]

5. Sort centers

k_means_cluster_centers = k_means.cluster_centers_  mbk_means_cluster_centers = mbk.cluster_centers_  print ("K-Means算法聚类中心点:\ncenter=", k_means_cluster_centers)  print ("Mini Batch K-Means算法聚类中心点:\ncenter=", mbk_means_cluster_centers)  order = pairwise_distances_argmin(k_means_cluster_centers,                                    mbk_means_cluster_centers)

K-Means centers:

center= [[-1.07159013 -1.00648645]

 [ 0.96700708  1.01837274]

 [ 1.07705469 -1.06730994]]

### Mini Batch K-Means centers:

center= [[ 1.02538969 -1.08781328]

 [-1.06046903 -1.01509453]

 [ 0.97734743  1.08610316]]

6–8. Plots and difference subplot (code as in source)

different = list(map(lambda x: (x!=0) & (x!=1) & (x!=2), mbkm_y_hat))  for k in range(clusters):      different += ((km_y_hat == k) != (mbkm_y_hat == order[k]))  identic = np.logical_not(different)  different_nodes = len(list(filter(lambda x:x, different)))  plt.subplot(224)  plt.plot(X[identic, 0], X[identic, 1], 'w', markerfacecolor='#bbbbbb', marker='.')  plt.plot(X[different, 0], X[different, 1], 'w', markerfacecolor='m', marker='.')  plt.title(u'Mini Batch K-Means和K-Means算法预测结果不同的点')  plt.xticks(())  plt.yticks(())  plt.text(-3.8, 2,  'different nodes: %d' % (different_nodes))  plt.show()

Output:

image

Comparison

Mini Batch is more than 2× faster with similar quality.

Non-convex data (below) breaks K-Means; need other methods (next chapter).

image

Non-convex clustering

Chapter summary

K-Means and variants for unsupervised clustering via clusters. We covered workflow, init sensitivity, and Mini Batch for scale. When K-Means fails, other ideas follow in the next chapter.