K-Means原理分析與手動實現

K-Means將所給數據進行分類(聚類,clustering),演算法是無監督學習(unsupervised),步驟如下:

首先要給個分類的類別數目,最開始的分類中心。

一(1):

計算其中一個點到所有分類中心的距離,將這個點與最近的中心劃分為一類

一(2):

將所有的點重複一(1)

二:

每個分類中,所有點的平均值作為新的分類中心

三:

重複迭代一、二兩步

手動實現代碼如下:

# -*- coding: utf-8 -*-"""Created on Wed Dec 6 17:05:34 2017@author: Administrator"""import numpy as npimport matplotlib.pyplot as pltimport pandas as pdfrom sklearn.cluster import KMeansfrom sklearn.datasets import make_blobsif __name__ == "__main__": n_samples = 1500 random_state = 170 X, y = make_blobs(n_samples=n_samples, random_state=random_state)# center = [X[10], X[365], X[666]] center = [X[100], X[365], X[666]] distance = list(np.zeros(3)) temp_data = pd.DataFrame(X) times = 4 for j in range(times): temp_y = [] for i in range(len(X)): distance[0] = np.square(center[0][0]-X[i][0]) + np.square(center[0][1]-X[i][1]) distance[1] = np.square(center[1][0]-X[i][0]) + np.square(center[1][1]-X[i][1]) distance[2] = np.square(center[2][0]-X[i][0]) + np.square(center[2][1]-X[i][1]) max_loc = distance.index(min(distance)) temp_y.append(max_loc) temp_data[y] = temp_y #update center temp = temp_data[temp_data[y] == 0] center[0] = [temp[0].mean(), temp[1].mean()] temp = temp_data[temp_data[y] == 1] center[1] = [temp[0].mean(), temp[1].mean()] temp = temp_data[temp_data[y] == 2] center[2] = [temp[0].mean(), temp[1].mean()] #plot the data plt.figure(figsize=(12, 12)) plt.subplot(221) plt.scatter(X[:, 0], X[:, 1], c=temp_y) plt.title("clustering data") plt.subplot(222) plt.scatter(X[:, 0], X[:, 1], c=y) plt.title("original data")

結果如下:

代碼解釋:

X, y = make_blobs(n_samples=n_samples, random_state=random_state)

生成用於聚類實驗的數據,數據是高斯分布,樣本點是n_samples個。

times:樣本迭代次數

distance[0] = np.square(center[0][0]-X[i][0]) + np.square(center[0][1]-X[i][1]) distance[1] = np.square(center[1][0]-X[i][0]) + np.square(center[1][1]-X[i][1]) distance[2] = np.square(center[2][0]-X[i][0]) + np.square(center[2][1]-X[i][1])

計算樣本點到聚類中心的距離

#update center temp = temp_data[temp_data[y] == 0] center[0] = [temp[0].mean(), temp[1].mean()] temp = temp_data[temp_data[y] == 1] center[1] = [temp[0].mean(), temp[1].mean()] temp = temp_data[temp_data[y] == 2] center[2] = [temp[0].mean(), temp[1].mean()]

更新聚類中心

迭代一次的結果:

迭代四次的結果:


數學原理分析:

1.步驟一的目的是:使得聚類中所有點到聚類中心的距離只和最小

迭代的最終目的是使J()最小化:

2.為何每次都是設置平均值為新的聚類中心呢?

我們的最終目的是使得J()函數最小,但是每一步怎麼走?

我們的每一步更新類似使用梯度下降演算法,這樣使得最快取得J()最小。可以認為,其本身是使用梯度下降法解目的函數。

3.這樣是不是全局最優解?

不是!這樣的只是局部最優解,與初始值的設置有極大關係,所以K-Means++應運而生。

4.補充

(1)手動實現的代碼是迭代times次,在實際中可以以中心點變得幅度,或整體方差作為是否停止的限制條件

(2)在數據量較大時,在

#update center temp = temp_data[temp_data[y] == 0] center[0] = [temp[0].mean(), temp[1].mean()]

在部分,可以使用隨機梯度下降(SGD)或批量梯度下降(MBGD)最為修改中心點或停止的條件,在數據量較大時可以提升速度。


在劃分樣本間差異,或者作為分類的依據,我們使用的是歐式距離:計算點與點間的距離。在實際用也可使用其他劃分標準,如:相關係數等。


推薦閱讀:

神經網路的梯度下降演算法:梯度矩陣的鏈式法則(便於向量化代碼實現)
30本最受歡迎的人工智慧書籍(Stack Overflow數據)
機器學習開放課程(一):使用Pandas探索數據分析
AIQ | 人工智慧的全面科普

TAG:機器學習 | 聚類演算法 |