機器學習 K均值聚類(K-means) 鳶尾花數據集

聚類的目標是使聚類後的各個簇,具有簇內聚合,簇間分離的特點。

如何度量簇之間,簇內樣本之間的差異度?常用距離計算,最常用的是“閔可夫斯基距離”(Minkowski distance),其與向量範數相對應。

K均值算法的優化目標是最大化:簇內樣本圍繞簇均值向量的緊密程度

即最大化簇內樣本的相似度

簇均值向量的定義如下:

設總樣本集D=\left \{ x_{1},x_{2},\cdots ,x_{m} \right \},劃分爲k個簇爲C=\left \{ C_{1},C_{2},\cdots ,C_{k} \right \},則簇C_{i}的均值向量定義如下

                                                                                       \mu _{i}=\frac{1}{\left | c_{i} \right |}\sum_{x\in C_{i}}x

爲了求得最優解,需要考察樣本的所有劃分,這是一個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類鳶尾花的劃分是效果最好的,其他兩類有劃分交集,但是結果是可以接受的

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章