資料分群的目標,是把原本一大群的資料,分成一個個相似的小群體。最簡單的分群演算法,是 k-means clustering,這個演算法的基本步驟大致如下:

  1. 選出 k 個資料點,做為初始的中心
  2. 計算每個資料點到這 k 個中心的距離
  3. 把跟同一個中心最近的資料點視為一群,並以其平均做為新的中心
  4. 重複步驟 2,直到變化很小或不再變化

我們使用 scikit-learn 的 cluster.KMeans 來幫我們執行 k-means 演算法,使用的資料集是 Wine Data Set,但為了視覺化方便,範例將只使用前兩維特徵。

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

dataset = load_wine()
data = dataset.data[:, :2]
print('Data shapes:', data.shape)

model = KMeans(n_clusters=3)
cluster_labels = model.fit_predict(data)
cluster_centers = model.cluster_centers_

plt.subplot(1, 2, 1)
plt.plot(data[:, 0], data[:, 1], '.')

plt.subplot(1, 2, 2)
for clab in set(cluster_labels):
	idx = np.where(cluster_labels == clab)[0]
	plt.plot(data[idx, 0], data[idx, 1], '.')
	plt.plot(model.cluster_centers_[clab, 0], model.cluster_centers_[clab, 1], 'r.', markersize=10)

plt.show()

在上述範例中,我們事先設定把資料分成三群,並且將分群結果和每一群的中心點畫出來。若需要做更細節的控制,例如如何選擇初始點,以及演算法步驟要重複幾次等,請參考官方文件

如何選擇群體數目,是一個非常重要的問題。其中一種決定方式是,藉由每個點到各自中心的距離總和來評估,雖然這個總和會隨著群體數目變多而減少(數學上是可以證明的,但這裡空間太小了我寫不下不是本教材的關注點所以略過),但我們通常可以選擇變化突然趨緩的地方,作為群體數目即可。下面範例會畫出群體數目分別為 1 到 10 時的距離總和,以及斜率的變化比率:

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

dataset = load_wine()
data = dataset.data[:, :2]
print('Data shapes:', data.shape)

dist_sum_all = []
for n in range(1, 11):
	model = KMeans(n_clusters=n)
	model.fit(data)
	dist_sum_all.append(model.inertia_)
dist_sum_all = np.array(dist_sum_all)

slope_change_ratio = np.diff(dist_sum_all[:-1]) / np.diff(dist_sum_all[1:])

fig, ax1 = plt.subplots()
ax2 = ax1.twinx()
ax1.plot(np.arange(1, 11), dist_sum_all, 'b.-', label='Total distance')
ax2.plot(np.arange(2, 10), slope_change_ratio, 'r.-', label='Slope change ratio')
ax1.legend(loc='upper center')
ax2.legend(loc='upper right')

plt.show()

資料分群還有許多演算法,例如以階層式的方式來進行分群等等,在此處就暫不介紹。