聚類的目標是使聚類後的各個簇,具有簇內聚合,簇間分離的特點。
如何度量簇之間,簇內樣本之間的差異度?常用距離計算,最常用的是“閔可夫斯基距離”(Minkowski distance),其與向量範數相對應。
K均值算法的優化目標是最大化:簇內樣本圍繞簇均值向量的緊密程度
即最大化簇內樣本的相似度
簇均值向量的定義如下:
設總樣本集,劃分爲k個簇爲,則簇的均值向量定義如下
爲了求得最優解,需要考察樣本的所有劃分,這是一個NP難問題,K均值算法採用貪心策略迭代的求出近似的最優解。
算法流程如下:
隨機在樣本集中找k個樣本作爲初始的簇均值向量,k個樣本代表劃分爲k個簇
k = 4
import random
a = range(n)
b = random.sample(a, k)
變量b以列表形式記錄了k個隨機數,提取k個樣本作爲初始的簇均值向量,並將數據形式從pandas.DataFrame轉換爲numpy.array,以便後續計算
U = []
for i in b:
U.append(np.array(data.loc[i].loc[[0, 1, 2, 3]]))
k個初始簇均值向量如下:
[array([5.8, 2.7, 5.1, 1.9], dtype=object),
array([4.9, 3.1, 1.5, 0.1], dtype=object),
array([4.4, 3.2, 1.3, 0.2], dtype=object),
array([5.2, 2.7, 3.9, 1.4], dtype=object)]
分別計算各個樣本數據與這k個簇均值向量的差異(距離),將這個樣本劃分到距離最近的那個簇
C = [[] for _ in range(k)]#存儲簇劃分
dist = [0 for _ in range(k)]#存儲距離
for i in range(n):
x = np.array(data.loc[i].loc[[0, 1, 2, 3]])
for j in range(k):
d = sum((x - U[j]) ** 2)
dist[j] = d
z = dist.index(min(dist))
C[z].append(data.loc[i])
重新計算各個簇的均值向量,重新計算各個樣本與各個簇均值向量之間的差異(距離),重新劃分樣本數據,得到新的簇劃分,
重複這個過程,直到簇劃分逐漸趨於穩定,從而得到近似的最優簇劃分。
U_new = [0 for _ in range(k)]
for i in range(k):
sumn = [0 for _ in range(4)]
for j in C[i]:
sumn = sumn + np.array(j.loc[[0, 1, 2, 3]])
sumn = sumn / len(C[i])
U_new[i] = sumn
U_new
for _ in range(100):
U = U_new
C = [[] for _ in range(k)]
dist = [0 for _ in range(k)]
for i in range(n):
x = np.array(data.loc[i].loc[[0, 1, 2, 3]])
for j in range(k):
d = sum((x - U[j]) ** 2)
dist[j] = d
z = dist.index(min(dist))
C[z].append(data.loc[i])
U_new = [0 for _ in range(k)]
for i in range(k):
sumn = np.array([0 for _ in range(4)])
for j in C[i]:
sumn = sumn + np.array(j.loc[[0, 1, 2, 3]])
sumn = sumn / len(C[i])
U_new[i] = sumn
在這裏我沒有設置迭代的終止條件,而是直接做了100次迭代,我們來看一下,最終劃分的結果:
C0 = pd.DataFrame(C[0])
C0[4].value_counts()
Iris-virginica 36
Iris-versicolor 3
Name: 4, dtype: int64
第一個簇中,39個樣本,36個是virginica,3個是versicolor,簇的純度是比較高的,這符合我們對聚類結果的期望,用同樣的方法,看看其他簇的樣本分佈:
C1 = pd.DataFrame(C[1])
C1[4].value_counts()
C2 = pd.DataFrame(C[2])
C2[4].value_counts()
C3 = pd.DataFrame(C[3])
C3[4].value_counts()
Iris-setosa 27
Name: 4, dtype: int64
Iris-setosa 23
Name: 4, dtype: int64
Iris-versicolor 47
Iris-virginica 14
Name: 4, dtype: int64
可以看到setosa類鳶尾花的劃分是效果最好的,其他兩類有劃分交集,但是結果是可以接受的