轉自:作者:LY豪
鏈接:https://www.jianshu.com/p/caef1926adf7
聚類
聚類試圖將數據集中的樣本划分為若干個通常是不相交的子集,每個子集成為一個“簇”。通過這樣的划分,每個簇可能對應於一些潛在的概念(也就是類別),如“淺色瓜” “深色瓜”,“有籽瓜” “無籽瓜”,甚至“本地瓜” “外地瓜”等;需說明的是,這些概念對聚類算法而言事先是未知的,聚類過程僅能自動形成簇結構,簇對應的概念語義由使用者來把握和命名。
聚類和分類的區別?
聚類是無監督的學習算法,分類是有監督的學習算法。所謂有監督就是有已知標簽的訓練集(也就是說提前知道訓練集里的數據屬於哪個類別),機器學習算法在訓練集上學習到相應的參數,構建模型,然后應用到測試集上。而聚類算法是沒有標簽的,聚類的時候,我們並不關心某一類是什么,我們需要實現的目標只是把相似的東西聚到一起。
性能度量
聚類的目的是把相似的樣本聚到一起,而將不相似的樣本分開,類似於“物以類聚”,很直觀的想法是同一個簇中的相似度要盡可能高,而簇與簇之間的相似度要盡可能的低。
性能度量大概可分為兩類: 一是外部指標, 二是內部指標 。
外部指標:將聚類結果和某個“參考模型”進行比較。
內部指標:不利用任何參考模型,直接考察聚類結果。
K-Means的原理
對於給定的樣本集,按照樣本之間的距離大小,將樣本集划分為K個簇。讓簇內的點盡量緊密的連在一起,而讓簇間的距離盡量的大
K-Means算法
給定樣本集D,k-means算法針對聚類所得簇划分C最小化平方誤差。

這條公式在一定程度上刻畫了簇內樣本圍繞簇均值向量的緊密程度,E值越小則簇內樣本相似度越高。
最小化上面的公式並不容易,找到它的最優解需考察樣本集D內所有可能的簇划分,這是一個 NP難問題。因此,k-means算法采用了貪心策略,通過迭代優化來近似求解上面的公式。算法流程如下:
其中第一行對均值向量進行初始化,在第4-8行與第9-16行依次對當前簇划分及均值向量迭代更新,若迭代更新后聚類結果保持不變,則在第18行將當前簇划分結果返回。
下面以西瓜數據集4.0為例來演示k-means算法的學習過程。我們將編號為i的樣本稱為xi,這是一個包含“密度”與“含糖率”兩個屬性值的二維向量。


考察樣本x1=(0.697;0.460),它與當前均值向量u1,u2,u3的距離分別是0.369,0.506,0.166,因此x1將被划入簇C3中。類似的,對數據集中所有的樣本考察一遍后,可得當前簇划分為



K-Means與KNN
初學者會很容易就把K-Means和KNN搞混,其實兩者的差別還是很大的。
K-Means是無監督學習的聚類算法,沒有樣本輸出;而KNN是監督學習的分類算法,有對應的類別輸出。KNN基本不需要訓練,對測試集里面的點,只需要找到在訓練集中最近的k個點,用這最近的k個點的類別來決定測試點的類別。而K-Means則有明顯的訓練過程,找到k個類別的最佳質心,從而決定樣本的簇類別。
當然,兩者也有一些相似點,兩個算法都包含一個過程,即找出和某一個點最近的點。兩者都利用了最近鄰(nearest neighbors)的思想。
K-Means的優點與缺點
優點:
簡單,易於理解和實現;收斂快,一般僅需5-10次迭代即可,高效
缺點:
1,對K值得選取把握不同對結果有很大的不同
2,對於初始點的選取敏感,不同的隨機初始點得到的聚類結果可能完全不同
3,對於不是凸的數據集比較難收斂
4,對噪點過於敏感,因為算法是根據基於均值的
5,結果不一定是全局最優,只能保證局部最優
6,對球形簇的分組效果較好,對非球型簇、不同尺寸、不同密度的簇分組效果不好。
代碼部分
讀取數據
import numpy as np import pandas as pd import matplotlib.pyplot as plt dataset = pd.read_csv('watermelon_4.csv', delimiter=",") data = dataset.values print(dataset)
K-Means算法
import random def distance(x1, x2): return sum((x1-x2)**2) def Kmeans(D,K,maxIter): m, n = np.shape(D) if K >= m: return D initSet = set() curK = K while(curK>0): # 隨機選取k個樣本 randomInt = random.randint(0, m-1) if randomInt not in initSet: curK -= 1 initSet.add(randomInt) U = D[list(initSet), :] # 均值向量 C = np.zeros(m) curIter = maxIter while curIter > 0: curIter -= 1 for i in range(m): p = 0 minDistance = distance(D[i], U[0]) for j in range(1, K): if distance(D[i], U[j]) < minDistance: p = j minDistance = distance(D[i], U[j]) C[i] = p newU = np.zeros((K, n)) cnt = np.zeros(K) for i in range(m): newU[int(C[i])] += D[i] cnt[int(C[i])] += 1 changed = 0 for i in range(K): newU[i] /= cnt[i] for j in range(n): if U[i, j] != newU[i, j]: changed = 1 U[i, j] = newU[i, j] if changed == 0: return U, C, maxIter-curIter return U, C, maxIter-curIter
作圖查看結果
U, C, iter = Kmeans(data,3,10) # print(U) # print(C) # print(iter) f1 = plt.figure(1) plt.title('watermelon_4') plt.xlabel('density') plt.ylabel('ratio') plt.scatter(data[:, 0], data[:, 1], marker='o', color='g', s=50) plt.scatter(U[:, 0], U[:, 1], marker='o', color='r', s=100) # plt.xlim(0,1) # plt.ylim(0,1) m, n = np.shape(data) for i in range(m): plt.plot([data[i, 0], U[int(C[i]), 0]], [data[i, 1], U[int(C[i]), 1]], "c--", linewidth=0.3) plt.show()