K-means 算法試圖將數據集中的樣本劃分為若干個子集,每個子集稱為一個簇,通過該算法使得每個聚類內的數據點盡可能相似(即距離該聚類的中心點最近),而不同聚類之間的數據點盡可能不相似。
算法步驟如下:
-
從樣例數據中隨機選擇
k
個點作為初始質心,k
表示簇的個數。 -
根據質心點循環進行計算分類。當質心點不發生變化時,結束循環,返回最終的質心點。詳細計算步驟如下:
- 根據質心計算每個點到質心的歐氏距離。
- 對于每個數據點,尋找距離最近的質點歸類。
- 計算每個簇中數據點的平均距離。
- 以該平均值作為新的質點,繼續計算。
舉個例子,假設計算得到的歐式距離數據如下:
[[1,2,3],[2,3,1],[4,5,6],[7,6,4]....[3,1,2]]
表示有 3 個簇,樣本數據的第一個點距離這三個質點的距離分別為 1、2、3,第二個點距離三個質點的距離分別為 2、3、1,后邊的數據依次類推。那么會將第一個點分類到簇 1,第二點分類到簇 3,依次類推。
-
根據第 2 步驟得到的質心點,計算獲取簇數據。參考 2.1-2.2 步驟。
如下是根據你的需求給出的 Python 示例代碼,請在你的環境上提前安裝pandas
庫和numpy
庫。
import random
import numpy as np
import pandas as pd# 計算歐氏距離
def euclidean_distance(dataset, centroids, k):clalist = []for data in dataset:# 平鋪數據,計算每個點到質心的距離diff = np.tile(data, (k, 1)) - centroidssquared_diff = diff ** 2squared_dist = np.sum(squared_diff, axis=1)distance = squared_dist ** 0.5clalist.append(distance)# 返回一個每個點到質點的距離的數組clalist = np.array(clalist)return clalist# 分類并計算變化量
def classify(dataset, centroids, k):# 計算單個點到每個質心的的距離# 數據結構為:[[1,2,3],[2,3,1],[4,5,6],[7,6,4]....[3,1,2]]# 表示有三個質心,數組中的第一個元素表示樣本的第一個點分別到三個質心的距離clalist = euclidean_distance(dataset, centroids, k)# 對于每個點,將會分配到距離它最近的質心,這里給出的是分類結果的索引min_dist_indices = np.argmin(clalist, axis=1)# 按照 min_dist_indices 進行統計分類,對分類結果求均值new_centro_ids = pd.DataFrame(dataset).groupby(min_dist_indices).mean()new_centro_ids = new_centro_ids.values# 計算變化量changed = new_centro_ids - centroidsreturn changed, new_centro_ids# k-means 算法
def kmeans(dataset, k):# 隨機取質心centroids = random.sample(dataset, k)# 更新質心,直到變化量全為 0changed, new_centro_ids = classify(dataset, centroids, k)while np.any(changed != 0):changed, new_centro_ids = classify(dataset, new_centro_ids, k)centroids = sorted(new_centro_ids.tolist())# 根據質心計算每個集群cluster = []clalist = euclidean_distance(dataset, centroids, k)min_dist_indices = np.argmin(clalist, axis=1)for _ in range(k):cluster.append([])for data_idx, cluster_idx in enumerate(min_dist_indices):cluster[cluster_idx].append(dataset[data_idx])return centroids, cluster# 創建數據集
dataset = [[1, 1], [1, 2], [2, 1], [6, 4], [6, 3], [5, 4]]
# k-means 算法
centroids, cluster = kmeans(dataset, 2)
print('質心為:{}'.format(centroids))
print('集群為:{}'.format(cluster))
上述代碼中,定義了一個主函數kmeans
和兩個輔助函數classify
和euclidean_distance
,創建了一個數據集dataset
,主函數接受數據集dataset
和聚類的類別數k
作為輸入,然后調用兩個輔助函數實現聚類計算的功能。
需要注意的是,K-means 算法雖然有效,但是容易受到初始簇質心的情況而影響,有可能陷入局部最優解。