# 机器学习：K-Means聚类算法

### K-Means算法原理

K-Means算法的K指的是输出类别的数目。该算法是一个迭代过程，每一次迭代分为两个步骤，第一步为分类成簇，第二步为移动簇中心，直到簇中心不变。

### K-Means算法实现

``````import numpy as np
import matplotlib.pyplot as plt

# Input data set
X = np.array([
[-4, -3.5], [-3.5, -5], [-2.7, -4.5],
[-2, -4.5], [-2.9, -2.9], [-0.4, -4.5],
[-1.4, -2.5], [-1.6, -2], [-1.5, -1.3],
[-0.5, -2.1], [-0.6, -1], [0, -1.6],
[-2.8, -1], [-2.4, -0.6], [-3.5, 0],
[-0.2, 4], [0.9, 1.8], [1, 2.2],
[1.1, 2.8], [1.1, 3.4], [1, 4.5],
[1.8, 0.3], [2.2, 1.3], [2.9, 0],
[2.7, 1.2], [3, 3], [3.4, 2.8],
[3, 5], [5.4, 1.2], [6.3, 2]
])

# K-Means
def k_means(data, k=2):
if not isinstance(k, int) or k <= 0 or len(data) < k:
return

# Select first K points as centroids
centroids = {0: data[0], 1: data[1]}

# configurations
limit = 0.0001
max_loop_count = 300
total_steps = []
# Loop
for i in range(max_loop_count):
# Classification data into K groups
groups = {}

for j in range(k):
groups[j] = []

for item in data:
dist = [np.linalg.norm(centroids[centroid] - item) for centroid in centroids]
index = dist.index(min(dist))
groups[index].append(item)

# Calculate new centroids
new_centroids = [np.average(groups[i], axis=0) for i in groups]
# Store data for matplotlib
total_steps.append({
'loop': i,
'groups': groups,
'centroids': centroids.copy()
})

# Check whether they change or not
stop_loop = True
for c in centroids:
if abs(np.sum((new_centroids[c] - centroids[c])/centroids[c]*100.0)) > limit:
stop_loop = False
break

if stop_loop:
break

# Update centroids
for c in centroids:
centroids[c] = new_centroids[c]

# Draw pictures
colors = k*['g', 'r', 'b', 'c', 'm', 'y', 'k', 'w']
fig = plt.figure()
for step in total_steps:
# This may cause error if len(total_steps) > 9
ax = fig.add_subplot(1, len(total_steps), step['loop'] + 1)
for g in step['groups']:
for point in step['groups'][g]:
ax.scatter(point[0], point[1], s=20, color=colors[g])
ax.scatter(step['centroids'][g][0], step['centroids'][g][1], marker='x', s=30, color=colors[g])
plt.show()

k_means(X)
``````

### `scikit-learn`中的KMeans

`scikit-learn`中的KMeans存在cluster模块中，在官方有关KMeans的API文档中可以看到，数据处理结果存放在‘cluster_centers_’、‘labels_’和‘ inertia_’中。下面用到了前两者，分别是聚类中心点和标签。

``````import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans

# Input data set
X = np.array([
[-4, -3.5], [-3.5, -5], [-2.7, -4.5],
[-2, -4.5], [-2.9, -2.9], [-0.4, -4.5],
[-1.4, -2.5], [-1.6, -2], [-1.5, -1.3],
[-0.5, -2.1], [-0.6, -1], [0, -1.6],
[-2.8, -1], [-2.4, -0.6], [-3.5, 0],
[-0.2, 4], [0.9, 1.8], [1, 2.2],
[1.1, 2.8], [1.1, 3.4], [1, 4.5],
[1.8, 0.3], [2.2, 1.3], [2.9, 0],
[2.7, 1.2], [3, 3], [3.4, 2.8],
[3, 5], [5.4, 1.2], [6.3, 2]
])

clf = KMeans(n_clusters=2)
clf.fit(X)
centroids = clf.cluster_centers_
labels = clf.labels_

colors = ['r', 'g']
for i in range(len(X)):
plt.scatter(X[i][0], X[i][1], color=colors[labels[i]], s=20)
plt.scatter(centroids[:, 0], centroids[:, 1], marker='x', s=30)
plt.show()
``````

sklearn的KMeans执行结果