1.K-means算法
1.基本定義
K-means算法的思想很簡單,對于給定的樣本集合,按照樣本之間的距離大小,將樣本劃分為K簇。讓簇內的點盡量緊密的聚集在一起,而讓簇間的距離盡量的大。
若用數學公式表達,即:假設簇劃分為,則目標函數是:
其中是簇
的均值向量(也稱為質心),表達式為:
該問題是一個NP難問題,是無法直接求目標函數最小值的,因此只能使用啟發式方法。
2.圖示原理
K-means采用的啟發式方法比較簡單,用下組圖(參考[1])可以詳細的表示:
圖示
圖a:設置K為2
圖b:隨機選擇2個對象作為當前的質心,例如圖中的紅點和藍點,分別求其余點與當前k個質心的距離,并標記每個點的類別為與該點距離最短的質心所屬的類別。
圖c:經過一輪計算后,得到每個點所屬的類別。
圖d:對已經新分類的每個簇,計算新的質心點。圖中可見,已經有了新的紅點和藍點。
圖e,f:重復圖c,d的過程,最終得到k個質心。
3.實現
import numpy as np
# 計算兩個向量的距離,用的是歐幾里得距離
def get_dis(vecA, vecB):
return np.linalg.norm(vecA - vecB)
# 隨機生成初始的質心(ng的課說的初始方式是隨機選K個點)
def randCent(dataSet, k):
p = np.shape(dataSet)[1] # 維度p
centroids = np.mat(np.zeros((k, p)))
# k個簇心
for j in range(p):
minJ = min(dataSet[:, j])
rangeJ = float(max(np.array(dataSet)[:, j]) - minJ)
centroids[:, j] = minJ + rangeJ * np.random.rand(k, 1)
return centroids
def kMeans(dataSet, k):
n = np.shape(dataSet)[0] # N個
p = np.shape(dataSet)[1]
clusterAssment = np.mat(np.zeros((n,p))) # 記錄每個點的簇心
# 隨機生成簇心
centroids = randCent(dataSet, k)
clusterChanged = True
while clusterChanged:
clusterChanged = False
for i in range(n): # 計算每個點簇心
minDist = np.inf
minIndex = -1
for j in range(k): # 當前點跟k個簇心的距離,選最近的簇心為自己的簇心
distJI = get_dis(centroids[j, :], dataSet[i, :])
print("distJI = ",distJI)
if distJI < minDist:
minDist = distJI
minIndex = j
if clusterAssment[i, 0] != minIndex:
clusterChanged = True # 循環標記
clusterAssment[i, :] = (minIndex, minDist)
for cent in range(k):
ptsInClust = dataSet[np.nonzero(clusterAssment[:, 0].A == cent)[0]] # matrix.A 將matrix轉換為array
centroids[cent, :] = np.mean(ptsInClust, axis=0)
return centroids, clusterAssment
def main():
# 1.隨機生成幾組數據(K = 2)
data_coord = np.asarray(((3, 3), (4, 3), (5, 5), (4, 5), (5, 4), (3, 5), (21, 22), (18, 23), (20, 23)))
dataMat = np.mat(data_coord)
myCentroids, clustAssing = kMeans(dataMat, 2)
print(myCentroids)
if __name__ == '__main__':
main()
參考與致謝:
[1] K-Means聚類算法原理