什么是聚類
聚類試圖將數(shù)據(jù)集中的樣本劃分為若干個通常是不相交的子集硼控,每個子集成為一個“簇”疫鹊。通過這樣的劃分蔑穴,每個簇可能對應于一些潛在的概念(也就是類別),如“淺色瓜” “深色瓜”烙博,“有籽瓜” “無籽瓜”,甚至“本地瓜” “外地瓜”等烟逊;需說明的是渣窜,這些概念對聚類算法而言事先是未知的,聚類過程僅能自動形成簇結構宪躯,簇對應的概念語義由使用者來把握和命名乔宿。
聚類和分類的區(qū)別?
聚類是無監(jiān)督的學習算法访雪,分類是有監(jiān)督的學習算法详瑞。所謂有監(jiān)督就是有已知標簽的訓練集(也就是說提前知道訓練集里的數(shù)據(jù)屬于哪個類別),機器學習算法在訓練集上學習到相應的參數(shù)臣缀,構建模型坝橡,然后應用到測試集上。而聚類算法是沒有標簽的精置,聚類的時候计寇,我們并不關心某一類是什么,我們需要實現(xiàn)的目標只是把相似的東西聚到一起脂倦。
性能度量
聚類的目的是把相似的樣本聚到一起番宁,而將不相似的樣本分開,類似于“物以類聚”赖阻,很直觀的想法是同一個簇中的相似度要盡可能高蝶押,而簇與簇之間的相似度要盡可能的低。
性能度量大概可分為兩類: 一是外部指標政供, 二是內部指標 播聪。
外部指標:將聚類結果和某個“參考模型”進行比較朽基。
內部指標:不利用任何參考模型,直接考察聚類結果离陶。
K-Means的原理
對于給定的樣本集稼虎,按照樣本之間的距離大小,將樣本集劃分為K個簇招刨。讓簇內的點盡量緊密的連在一起霎俩,而讓簇間的距離盡量的大
K-Means算法
給定樣本集D,k-means算法針對聚類所得簇劃分C最小化平方誤差沉眶。
這條公式在一定程度上刻畫了簇內樣本圍繞簇均值向量的緊密程度打却,E值越小則簇內樣本相似度越高。
最小化上面的公式并不容易谎倔,找到它的最優(yōu)解需考察樣本集D內所有可能的簇劃分柳击,這是一個NP難問題。因此片习,k-means算法采用了貪心策略捌肴,通過迭代優(yōu)化來近似求解上面的公式。算法流程如下:
其中第一行對均值向量進行初始化藕咏,在第4-8行與第9-16行依次對當前簇劃分及均值向量迭代更新状知,若迭代更新后聚類結果保持不變,則在第18行將當前簇劃分結果返回孽查。
假定簇數(shù)k=3西设,算法開始是隨機選取三個樣本x6,x12,x27作為初始均值向量,即
K-Means與KNN
初學者會很容易就把K-Means和KNN搞混阵漏,其實兩者的差別還是很大的驻民。
K-Means是無監(jiān)督學習的聚類算法,沒有樣本輸出履怯;而KNN是監(jiān)督學習的分類算法回还,有對應的類別輸出。KNN基本不需要訓練叹洲,對測試集里面的點柠硕,只需要找到在訓練集中最近的k個點,用這最近的k個點的類別來決定測試點的類別运提。而K-Means則有明顯的訓練過程仅叫,找到k個類別的最佳質心,從而決定樣本的簇類別糙捺。
當然,兩者也有一些相似點笙隙,兩個算法都包含一個過程洪灯,即找出和某一個點最近的點。兩者都利用了最近鄰(nearest neighbors)的思想竟痰。
K-Means的優(yōu)點與缺點
優(yōu)點:
簡單签钩,易于理解和實現(xiàn);收斂快坏快,一般僅需5-10次迭代即可铅檩,高效
缺點:
1,對K值得選取把握不同對結果有很大的不同
2莽鸿,對于初始點的選取敏感昧旨,不同的隨機初始點得到的聚類結果可能完全不同
3,對于不是凸的數(shù)據(jù)集比較難收斂
4祥得,對噪點過于敏感兔沃,因為算法是根據(jù)基于均值的
5,結果不一定是全局最優(yōu)级及,只能保證局部最優(yōu)
6乒疏,對球形簇的分組效果較好,對非球型簇饮焦、不同尺寸怕吴、不同密度的簇分組效果不好窍侧。
代碼部分
讀取數(shù)據(jù)
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()
輸出如下:上圖劃分了三個簇,每個簇的命名都是由我們來命名转绷,例如伟件,我們可以把它們分別命名為:好瓜、中等瓜暇咆、壞瓜锋爪。
數(shù)據(jù)以及代碼可以到我碼云下載