1. 程式人生 > 其它 >Python 非調包實現K中心聚類演算法

Python 非調包實現K中心聚類演算法

技術標籤:人工智慧python機器學習深度學習聚類

Python 非調包實現K中心聚類演算法

文章目錄


前言

終於結束一學期的學業,有時間靜下心來學自己感興趣的領域,寫寫部落格記錄學習心得了。
聚類是機器學習中經典的一類演算法,大家廣為熟知的是Kmeans演算法,而K中心卻少有聽說,大多數機器學習書籍中也少有提到這個演算法。
今天就來講講K中心聚類演算法是怎麼回事。

一、K中心聚類演算法是什麼?

1.K中心點聚類演算法的基本思想為:

對於K中心點聚類演算法,首先隨意選擇初始代表物件(或種子)。代表物件也被稱為是中心點,其他物件則被稱為非代表物件。
最初隨機選擇k個物件作為中心點,該演算法反覆地用非代表物件來代替代表物件,試圖找出更好的中心點,以改進聚類的質量。

2.K中心聚類與Kmeans的主要區別:

初始化聚類中心上的不同,Kmeans是選擇樣本空間中隨機座標點作為中心,這些點並不一定就代表某個樣本點物件;而K中心則是選擇樣本點物件作為聚類中心;
距離計算公式上的不同,Kmeans通常使用歐式距離,K中心則使用曼哈頓距離;
更新聚類中心上的不同,Kmeans使用簇內樣本點求均值方式更新中心,K中心則是先產生中心點和非中心點的組合,然後求哪個組合的代價函式最小再決定新的中心。

3.K-中心點聚類演算法流程描述:

輸入:簇的數目k和包含n個物件的資料庫
輸出:k個簇,使得所有物件與其最近中心點的相異度總和最小
(1)任意選擇k個物件作為初始的簇中心點
(2)Repeat
(3)指派每個剩餘物件給離他最近的中心點所表示的簇
(4)Repeat
(5)選擇一個未被選擇的中心點
(6)Repeat
(7)選擇一個未被選擇過的非中心點物件Orandom
(8)計算用Orandom代替Oi的總代價並記錄在S中
(9)Until 所有非中心點都被選擇過
(10)Until 所有的中心點都被選擇過
(11)If 在S中的所有非中心點代替所有中心點後的計算出總代價有小於0的存在,then找出S中的用非中心點替代中心點後代價最小的一個,並用該非中心點替代對應的中心點,形成一個新的k箇中心點的集合;

(12)Until 沒有再發生簇的重新分配,即所有的S都大於0

4.舉例說明

假如空間中的五個點{ABCDE},各點之間的距離關係如表所示,根據所給的資料對其執行K中心點演算法實現聚類劃分(設K=2)。
在這裡插入圖片描述
(1)首先隨機選取中心,以{AB}為例,則屬於簇被分為{ACD}和{BE},分簇這一步其實分法有很多,這裡只是為了分得均勻,答案不唯一。
(2)計算出以AB為中心的代價函式Cost(AB)=d(AC)+d(AD)+d(BE)=2+2+3=7,有必要一提的是這裡代價函式的定義也有多種,K中心的目的就是為了找出和簇內其他點距離之和最小的點作為新的中心
(3)分別對中心{AB}和非中心{CDE}進行組合得出待計算代價的中心點集合{AC,AD,AE,BC,BD,BE},然後一一求這些中心組的代價函式,然後和原中心代價函式相減,得出最小值的那一組為新中心,例:Cost(AC)=d(AB)+d(AE)+d(CD)=5,Cost(AC)-Cost(AB)=-2。由於這題特殊,可以有很多組新中心。
(4)不斷進行上面步驟直到代價差值不再減少。
PS:不懂還可以在參考一下K-中心點聚類演算法(K-Medoide)

二、程式碼實現

import random
import numpy as np

class Kmedoid:
    def __init__(self, data, k):
    """
    data:訓練資料,矩陣形式
    k:聚類個數
    """
        self.data = data
        self.k = k

    def randCent(self):  # 隨機選取一個點
        random_index = random.randint(0, self.data.shape[0]-1)
        return random_index, self.data[random_index, :]

    def distance(self, vecA, vecB):  # 計算曼哈頓距離
        return sum(abs(vecA - vecB))

    def run(self):
        init_centers = []  # 初始化中心的列表
        init_indexs = []  # 被選中作為中心的點的下標
        while len(init_centers) < self.k:
            index, center = self.randCent()
            if index not in init_indexs:  # 保證選點不重複
                init_centers.append(center)
                init_indexs.append(index)
            else:
                continue

        while True:
            cluster_category = []  # 記錄聚類結果
            for i in range(self.data.shape[0]):  # 遍歷每一個點
                minv = np.inf  # 最小距離,初始為正無窮
                cluster_index = 0  # 所屬簇的下標
                for index, center in enumerate(init_centers):  # 遍歷每個中心
                    # 選取離得最近的中心作為歸屬簇
                    dist = self.distance(center, self.data[i, :])
                    if dist < minv:
                        minv = dist
                        cluster_index = index
                cluster_category.append(cluster_index)

            # 重新計算中心點
            new_indexs = [0 for i in range(len(init_centers))]  # 更新被選中作為中心的點的下標
            min_dists = [np.inf for i in range(len(init_centers))]  # 中心點對應最小距離
            for i in range(self.data.shape[0]):
                min_dist = 0  # 求與當前簇其他點的距離之和
                for j in range(self.data.shape[0]):  # 遍歷每一個點
                    if cluster_category[i] == cluster_category[j]:  # 屬於同一個簇才進行累加
                        min_dist += self.distance(self.data[i, :], self.data[j, :])
                if min_dist < min_dists[cluster_category[i]]:  # 儲存資料到列表
                    min_dists[cluster_category[i]] = min_dist
                    new_indexs[cluster_category[i]] = i

            init_centers = []  # 新的聚類中心
            for index in new_indexs:
                init_centers.append(self.data[index, :])

            if new_indexs == init_indexs:  # 如果新的中心與上次相同則結束迴圈
                return cluster_category, init_centers
            else:
                init_indexs = new_indexs  # 更新聚類中心下標

總結

學習機器學習演算法就要學習掌握其原理,並且最好自己用基本庫實現一下,而不要光是使用第三方庫調包的形式,機器學習是深度學習、強化學習的基礎,萬丈高樓平地起,基礎不牢地動山搖,祝大家寒假愉快!