機器學習:K-means算法進行分類 兩種初始化簇中心的方法


一、第一種初始化簇中心的方法:隨機產生k個簇中心,保證簇中心的每個維度的取值都在這個緯度所有值的最小值與最大值的左閉右開區間內

import numpy as np
class KMeans_1:
    def __init__(self,k_clusters,tol=1e-4,max_iter=300):
        self.k_clusters=k_clusters
        self.tol=tol
        self.max_iter=max_iter
    
    #生成隨機的k個聚類中心,每個維度都在最小最大值范圍內
    def _init_centers_random(self,X,k_clusters):
        _,n=X.shape
        xmin=np.min(X,axis=0)
        xmax=np.max(X,axis=0)
        
        return xmin+(xmax-xmin)*np.random.rand(k_clusters,n)
    
    
    def _kmeans(self,X):
        '''K-Means核心算法'''
        m,n=X.shape
        
        #label存儲對每一個實例的划分標記
        labels=np.zeros(m,dtype=np.int)
        #distance為m*k的矩陣,表示每個樣本到每個簇中心的距離
        distances = np.empty((m,self.k_clusters))
        #centers_old存儲之前的質心點
        centers_old = np.empty((self.k_clusters,n))
        
        #初始化簇中心
        centers=self._init_centers_random(X,self.k_clusters)
        
        for _ in range(self.max_iters):
            #1、分類標簽
            for i in range(self.k_clusters):
                #計算m個實例到質心點的距離
                np.sum((X-centers[i])**2,axis=1,out=distances[:,i])
            
            #將m個實例划分到距離最小的那個類中
            np.argmin(distances,axis=1,out=labels)
            
            #2、計算質心點
            #保存之前的質心點
            np.copyto(centers_old,centers)
            for i in range(self.k_clusters):
                cluster = X[labels==i]
                if cluster.size==0:
                    return None
                #計算新的簇中心
                np.mean(cluster,axis=0,out=centers[i])
            
            #3、判斷是否收斂,求每個簇中心與原來的位置的距離和
            delta_centers = np.sqrt(np.sum((centers-centers_old)**2,axis=1))
            
            #每個簇中心點的變化都小於閾值
            if np.all(delta_centers < self.tol):
                break
            
        #計算簇內誤差平方和
        sse=np.sum(distances[range(m),labels])
            
        return labels,centers
        
    def predict(self,X):
      
        res = None
        while not res:
            res=self._kmeans(X)
            
        labels,self.centers_= res
        
        return labels

二、第二種K-Means算法,初始化簇中心的時候使用了概率模型,能夠選出k個相聚較遠的點。在這個算法中,我們通過十次有效的划分,計算出最少的損失函數SSE的值,將這個值對應的分類返回

 

import numpy as np
class KMeans_2:
    def __init__(self,k_clusters,tol=1e-4,max_iter=300,n_init=10):
        self.k_clusters=k_clusters
        self.tol=tol
        self.max_iter=max_iter
        self.n_init = n_init
    
    def _init_centers_kpp(self,X,n_clusters):
        
        '''k-means++核心初始化算法'''
        m,n=X.shape
        #第一個點是隨機產生的,所以只需要計算n_clusters-1個點
        distances = np.empty((m,n_clusters-1))
        centers=np.empty((n_clusters,n))
        
        #隨機產生一個[0,m-1]的下標,將這個樣本作為第一個聚類中心點
        np.copyto(centers[0],X[np.random.randint(m)])
        
        for j in range(1,n_clusters):
            for i in range(j):
                np.sum((X-centers[j])**2,axis=1,out=distances[:,i])
            
            #計算各點到最近質心點的距離平方
            nds=np.min(distances[:,:j],axis=1)
            #1、以各點到最近質心的距離平方構成的加權概率進行分布,產生下一簇質心點
            r=np.sum(nds)*np.random.random()
            
            #2、判斷概率點落入那個區域,對應的樣本就是簇中心
            for k in range(m):
                r-=nds[k]
                if r < 0:
                    break
            np.copyto(centers[j],X[k])
            
        return centers
    
    def _kmeans(self,X):
        '''K-Means++核心算法'''
        m,n=X.shape
        
        #label存儲對每一個實例的划分標記
        labels=np.zeros(m,dtype=np.int)
        #distance為m*k的矩陣,表示每個樣本到每個簇中心的距離
        distances = np.empty((m,self.k_clusters))
        #centers_old存儲之前的質心點
        centers_old = np.empty((self.k_clusters,n))
        
        #初始化簇中心
        centers=self._init_centers_kpp(X,self.k_clusters)
        
        for _ in range(self.max_iter):
            #1、分類標簽
            for i in range(self.k_clusters):
                #計算m個實例到質心點的距離
                np.sum((X-centers[i])**2,axis=1,out=distances[:,i])
            
            #將m個實例划分到距離最小的那個類中
            np.argmin(distances,axis=1,out=labels)
            
            #2、計算質心點
            #保存之前的質心點
            np.copyto(centers_old,centers)
            for i in range(self.k_clusters):
                cluster = X[labels==i]
                if cluster.size==0:
                    return None
                #計算新的簇中心
                np.mean(cluster,axis=0,out=centers[i])
            
            #3、判斷是否收斂,求每個簇中心與原來的位置的距離和
            delta_centers = np.sqrt(np.sum((centers-centers_old)**2,axis=1))
            
            #每個簇中心點的變化都小於閾值
            if np.all(delta_centers < self.tol):
                break
            
        #計算簇內誤差平方和
        sse=np.sum(distances[range(m),labels])
            
        return labels,centers,sse
        
    def predict(self,X):
        
        result = np.empty((self.n_init,3),dtype=np.object)
        
        #運行self.n_init次
        for i in range(self.n_init):
            #調用self.k_means直到成功
            res = None
            while res is None:
                res=self._kmeans(X)
            result[i]=res
            
        #選出sse最小的分類結果
        k=np.argmin(result[:,-1])
        labels,self.centers_,sse_ = result[k]
        
        return labels

三、加載數據

數據來源

http://archive.ics.uci.edu/ml/machine-learning-databases/00236/
import numpy as np
X=np.genfromtxt('F:/python_test/data/seeds_dataset.txt',usecols=range(7))
print(X)
labels=np.genfromtxt('F:/python_test/data/seeds_dataset.txt',usecols=7,dtype=np.int)
print(labels)

三類標簽分別有七十個

print(labels[:70])
print(labels[70:140])
print(labels[140:210])

kmeans=KMeans_2(3)
label_pred=kmeans.predict(X)
print(label_pred)

 

 

大體上分成了三類,但是效果怎么樣還有待評估,使用ARI指標進行評估,

 

from sklearn.metrics import adjusted_rand_score
ari=adjusted_rand_score(labels,label_pred)
print(ari)

 

得到ARI=0.7166198557361053

再考察外部指標FM 

from sklearn.metrics import fowlkes_mallows_score
fm=fowlkes_mallows_score(labels,label_pred)
print(fm)

 

 性能可以說還不錯,我們緊接着對每個屬性的取值都標准化再使用K-means算法

from sklearn .preprocessing import StandardScaler
ss=StandardScaler()
X_std=ss.fit_transform(X)
kmeans = KMeans_2(3)
label_pred=kmeans.predict(X_std)
ari=adjusted_rand_score(labels,label_pred)
print(ari)
fm=fowlkes_mallows_score(labels,label_pred)
print(fm)

可見ARI指標和FM指標分別提高到了77.3%和84.8%

 下面測試一下上述兩種算法的能力

第一種:

w=range(200)
ari_arr=[]
fm_arr=[]
import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
for i in w:
    ss=StandardScaler()
    X_std=ss.fit_transform(X)
    kmeans = KMeans_1(3)
    label_pred=kmeans.predict(X_std)
    ari=adjusted_rand_score(labels,label_pred)
    ari_arr.append(ari)
    fm=fowlkes_mallows_score(labels,label_pred)
    fm_arr.append(fm)
plt.plot(w,ari_arr,label='ari',linestyle='--',color='red')
plt.plot(w,fm_arr,label='fm',linestyle='-.',color='blue')
plt.show()

可以發現平均下來還是很不錯的

第二種:(非常穩定,但是好像沒有上面第一種方法好)

w=range(200)
ari_arr=[]
fm_arr=[]
import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
for i in w:
    ss=StandardScaler()
    X_std=ss.fit_transform(X)
    kmeans = KMeans_2(3)
    label_pred=kmeans.predict(X_std)
    ari=adjusted_rand_score(labels,label_pred)
    ari_arr.append(ari)
    fm=fowlkes_mallows_score(labels,label_pred)
    fm_arr.append(fm)
plt.plot(w,ari_arr,label='ari',linestyle='--',color='red')
plt.plot(w,fm_arr,label='fm',linestyle='-.',color='blue')
plt.xlabel('iterations')
plt.ylabel('ratio')
plt.legend()
plt.show()

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM