K-means聚類演算法,K-means又叫-k均值或者k-平均聚類演算法。演算法思想就是首先會隨機確定k個中心點作為聚類中心,然後把各個數據點分配給最鄰近的中心點,分配完成後將中心點移動到所表示的聚類的平均中心位置處,然後重複迭代上述步驟直到分配過程不再產生變化位置。
假設輸入樣本為T= , ,..., ;則演算法步驟為(使用歐幾里得距離公式):
中止條件:
迭代次數、最小平方誤差MSE、簇中心點變化率
3.當目標函數取最小值時取得最優解,對J函數求偏導數,可以得到簇中心點a更新的公式為:
4.如果K個質心不再發生變化,輸出簇劃分。
傳統K-means實現:
import random from sklearn import datasets import numpy as np
# 正規化數據集 X def normalize(X, axis=-1, p=2): lp_norm = np.atleast_1d(np.linalg.norm(X, p, axis)) lp_norm[lp_norm == 0] = 1 return X / np.expand_dims(lp_norm, axis)
# 計算一個樣本與數據集中所有樣本的歐氏距離的平方 def euclidean_distance(one_sample, X): one_sample = one_sample.reshape(1, -1) X = X.reshape(X.shape[0], -1) distances = np.power(np.tile(one_sample, (X.shape[0], 1)) - X, 2).sum(axis=1) return distances
class Kmeans(): def __init__(self, k=2, max_iterations=500, varepsilon=0.0001): self.k = k self.max_iterations = max_iterations self.varepsilon = varepsilon
# 從所有樣本中隨機選取self.k樣本作為初始的聚類中心 def init_random_centroids(self, X): n_samples, n_features = np.shape(X) centroids = np.zeros((self.k, n_features)) for i in range(self.k): centroid = X[np.random.choice(range(n_samples))] centroids[i] = centroid return centroids
# 返回距離該樣本最近的一個中心索引[0, self.k) def _closest_centroid(self, sample, centroids): distances = euclidean_distance(sample, centroids) closest_i = np.argmin(distances) return closest_i
# 將所有樣本進行歸類,歸類規則就是將該樣本歸類到與其最近的中心 def create_clusters(self, centroids, X): n_samples = np.shape(X)[0] clusters = [[] for _ in range(self.k)] for sample_i, sample in enumerate(X): centroid_i = self._closest_centroid(sample, centroids) clusters[centroid_i].append(sample_i) return clusters
# 對中心進行更新 def update_centroids(self, clusters, X): n_features = np.shape(X)[1] centroids = np.zeros((self.k, n_features)) for i, cluster in enumerate(clusters): centroid = np.mean(X[cluster], axis=0) centroids[i] = centroid return centroids
# 將所有樣本進行歸類,其所在的類別的索引就是其類別標籤 def get_cluster_labels(self, clusters, X): y_pred = np.zeros(np.shape(X)[0]) for cluster_i, cluster in enumerate(clusters): for sample_i in cluster: y_pred[sample_i] = cluster_i return y_pred
# 對整個數據集X進行Kmeans聚類,返回其聚類的標籤 def predict(self, X): # 從所有樣本中隨機選取self.k樣本作為初始的聚類中心 centroids = self.init_random_centroids(X)
# 迭代,直到演算法收斂(上一次的聚類中心和這一次的聚類中心幾乎重合)或者達到最大迭代次數 for _ in range(self.max_iterations): # 將所有進行歸類,歸類規則就是將該樣本歸類到與其最近的中心 clusters = self.create_clusters(centroids, X) former_centroids = centroids
# 計算新的聚類中心 centroids = self.update_centroids(clusters, X)
# 如果聚類中心幾乎沒有變化,說明演算法已經收斂,退出迭代 diff = centroids - former_centroids if diff.any() < self.varepsilon: break
return self.get_cluster_labels(clusters, X)
def main(): # Load the dataset X, y = datasets.make_blobs(n_samples=10000, n_features=3, centers=[[3,3, 3], [0,0,0], [1,1,1], [2,2,2]], cluster_std=[0.2, 0.1, 0.2, 0.2], random_state =9)
# 用Kmeans演算法進行聚類 clf = Kmeans(k=4) y_pred = clf.predict(X)
K-means演算法在迭代的過程中使用所有點的均值作為新的質點(中心點),如果簇中存在異常點,將導致均值偏差比較嚴重。比如一個簇中有2、4、6、8、100五個數據,那麼新的質點為24,顯然這個質點離絕大多數點都比較遠;在當前情況下,使用中位數6可能比使用均值的想法更好,使用中位數的聚類方式叫做K-Mediods聚類(K中值聚類)。對於極端數據,還可以先做異常點檢測,剔除異常點後再聚類。常用的異常點檢測方法比如 oneClassSVM。
K-means演算法是初值敏感的,選擇不同的初始值可能導致不同的簇劃分規則。為了避免這種敏感性導致的最終結果異常性,可以採用初始化多套初始節點構造不同的分類規則,然後選擇最優的構造規則。
為了解決K-means初值敏感、運行耗時問題,有了以下優化演算法:
解決K-Means演算法對初始簇心比較敏感、收斂於局部最小值的問題,二分K-Means演算法是一種弱化初始質心的一種演算法。具體思路步驟如下:
K-Means++演算法和K-Means演算法的區別主要在於初始的K個中心點的選擇方面,K-Means演算法使用隨機給定的方式,K-Means++演算法採用下列步驟給定K個初始質點:
由於聚類中心點選擇過程中的內在有序性,在擴展方面存在著性能方面的問題(第k個聚類中心點的選擇依賴前k-1個聚類中心點的值)。
為了解決K-Means++演算法缺點而產生的一種演算法。主要規則是改變每次遍歷時候的取樣規則,並非按照K-Means++演算法每次遍歷只獲取一個樣本而是每次獲取K個樣本,,重複該取樣操作O(logn)次,然後再將這些抽樣出來的樣本聚類出K個點,最後使用這K個點作為K-Means演算法的初始聚簇中心點。實踐證明:一般5次重複採樣就可以保證一個比較好的聚簇中心點。
在傳統的K-Means演算法中,我們每輪迭代時,計算所有的樣本點到所有的質心的距離,這樣比較耗時。elkan K-Means對於距離計算優化,減少不必要的距離的計算。elkan K-Means利用了兩邊之和大於等於第三邊,以及兩邊之差小於第三邊的三角形性質,來減少距離的計算。
第一種規律是對於一個樣本點x和兩個質心A、B。如果我們預先計算出了這兩個質心之間的距離D( , )D( , ),則如果計算髮現2D(x, )≤D( , ),我們立即就可以知道D(x, )≤D(x, )。此時我們不需要再計算D(x, ),也就是說省了一步距離計算。
第二種規律是對於一個樣本點xx和兩個質心A、B。我們可以得到D(x, )≥max{0,D(x, )?D( , )}。這個從三角形的性質也很容易得到。
利用上邊的兩個規律,迭代速度有很大的提高。但是如果特徵是稀疏的,有缺失值的話,這個方法就不適用了,此時某些距離無法計算,則不能使用該演算法。
Mini Batch K-Means演算法是K-Means演算法的一種優化變種,採用小規模的數據子集(每次訓練使用的數據集是在訓練演算法的時候隨機抽取的數據子集)減少計算時間,同時試圖優化目標函數;Mini Batch K-Means演算法可以減少K-Means演算法的收斂時間,而且產生的結果效果只是略差於標準K-Means演算法。
演算法步驟如下:
最後對對K-Means的優缺點做一個總結。
K-Means的主要優點有:
1、原理簡單,易實現,可解釋性強;
2、聚類效果較優,尤其當簇近似高斯分布;
3、主要需要調參的參數只有簇數K;
4、處理大數據集的時候,該演算法可以保證較好的伸縮性和高效率。
K-Means的主要缺點有:
1、不適合發現非凸形狀的簇或者大小差別較大的簇;
2、對雜訊和異常點比較敏感;
3、K值是用戶給定的,在進行數據處理前,K值是未知的,不同的K值得到的結果也不一 樣;
4、對初始簇的中心點敏感。