Clustering method 2
By: Yuki Liu
Tags: Clustering, Machine Learning, Clustering Algorithm, Unsupervised Learning, Mean Shift

Mean Shift算法會沿著 KDE 的梯度方向尋找機率最大值，因此考慮

令 g(s) = -k’(s)，則

前一項為核函數，後一項則為 mean shift vector

利用迭代的方式更新中心點：

計算當前的 mean shift vector，也就是 m_h(center_old) 中心點沿著平均偏移向量移動做為新的中心點，意即 center_new = center_old + mean shift。

直到收斂便會找到核密度估計最大值的地方。

－ 演算法 －

輸入：資料集 D，以及帶寬 bandwidth

輸出：目標分群集合 Clusters

從未被分群的資料點中選擇一起始點做為中心。

2. 將距離中心點小於 bandwidth 的資料點分為同一群，記為集合 M 。

紅色點為集合 M 裡的 element

3. 計算從中心點到集合 M 中每個元素的向量，並做向量平均相加得到平均偏移向量 mean shift vector。

橘色向量即為 mean shift vector

4. 中心點沿著平均偏移向量移動做為新的中心點，意即 center = center + mean shift。

橘色點為新的中心點（會往 KDE 的最大值方向移動）

5. 重複步驟 2、3、4，直到中心點不再更動為止（也就是找到局部極大值）。若此群的中心點已被歸於先前所分的群中，便將兩群合併為同一群。

6. 重複以上步驟直到所有點都被歸類為止。

－ 算法實作 －

使用Sklearn.cluster.MeanShift套件：

import numpy as np

import matplotlib.pyplot as plt

from sklearn.cluster import MeanShift, estimate_bandwidth

from sklearn import datasets #create datasets

X,y = datasets.make_blobs(n_samples=50, centers=3, n_features=2, random_state= 20, cluster_std = 1.5) #estimate bandwidth

bandwidth = estimate_bandwidth(X, quantile=0.2, n_samples=1000) #Mean Shift method

model = MeanShift(bandwidth = bandwidth, bin_seeding = True)

model.fit(X)

labels = model.fit_predict(X) #results visualization

plt.figure()

plt.scatter(X[:,0], X[:,1], c = labels)

plt.axis('equal')

plt.title('Prediction') plt.show()

右圖預測的結果依照bandwidth的選取會有所不同，在此估計bandwidth為 2.92

用於影像分割 …

import numpy as np

import matplotlib.pyplot as plt

from skimage.transform import rescale

from sklearn.cluster import MeanShift, estimate_bandwidth

import cv2 #load image

img = cv2.imread('AIA.png')

img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

img = rescale(img, 0.2)

rows, cols, chs= img.shape #convert image shape [rows, cols, 3] into [rows*cols, 3]

feature_img = np.reshape(img, [-1, 3]) #estimate bandwidth

bandwidth = estimate_bandwidth(feature_img, quantile=0.2, n_samples=1000) #Mean Shift method

model = MeanShift(bandwidth = bandwidth, bin_seeding = True)

model.fit(feature_img)

labels = model.fit_predict(feature_img) #results visualization

fig = plt.figure(figsize = (20, 12))

ax = fig.add_subplot(121)

ax1 = fig.add_subplot(122)



ax.imshow(img)

ax1.imshow(np.reshape(labels, [rows, cols])) plt.show()

左圖為原圖；右圖選用 bandwidth = 0.17 的分割結果（在深灰的部分顏色差異不大被歸為同一類，白色也與淺灰歸為同一類，不易將亮度或色調差異不大的顏色分群）

左圖僅顯示被歸為背景藍色的像素；右圖則表示被歸為白色系的像素（因為灰色系的顏色差異不大，所以被歸為同一類）

完整程式：https://gitlab.aiacademy.tw/yuchi/2018December_blog.git

－ Mean shift算法總結－

優點：

此算法與基於距離的分群法不同，可以任意形狀分群（基於距離的算法大多以類似圓形或凸形的形狀分群）。 不須指定分群的數目。 可以利用 k-nearest neighbor 的方法去估計較適合的參數 bandwidth

缺點：

計算複雜度為 O( kN ²)，N 為資料集大小，k為每個資料點平均迭代的次數。 對於一些離群值無法找到合適的分群，即無法判別離群值（雜訊）。

－ 參考資料 －

[1] Fukunaga, Keinosuke, and Larry Hostetler. “The estimation of the gradient of a density function, with applications in pattern recognition.” IEEE Transactions on information theory 21.1 (1975): 32–40.

[2] Cheng, Yizong. “Mean shift, mode seeking, and clustering.” IEEE transactions on pattern analysis and machine intelligence17.8 (1995): 790–799.

Mean shift 維基百科：https://en.wikipedia.org/wiki/Mean_shift

Kernel density estimation 維基百科：https://en.wikipedia.org/wiki/Kernel_density_estimation

Kernel（statistics）維基百科：https://en.wikipedia.org/wiki/Kernel_(statistics)

sklearn.cluster.MeanShift套件：https://scikit-learn.org/stable/modules/generated/sklearn.cluster.MeanShift.html