聚類cluster

一,k均值算法

(一)自己寫程序

舉例,在excel中有四個點的座標如下,表示樣本集 D=(x1,x2,x3,x4)D=(x_1,x_2,x_3,x_4)(分別對應下圖中的最左邊標籤對應的數,x1=(2.2,2.3)...x_1=(2.2,2.3)...)
在這裏插入圖片描述
現在將這四個點畫出來

import numpy as np
import xlrd
import matplotlib.pyplot as plt

workbook = xlrd.open_workbook('C:/users/Lenovo/Desktop/test.xlsx')
sheet = workbook.sheet_by_name('Sheet1')

dot_x = sheet.col_values(0)
dot_y = sheet.col_values(1)

plt.scatter(dot_x,dot_y)
plt.show()

在這裏插入圖片描述
隨機選擇兩個樣本作爲初始均值向量,(機器學習西瓜書中隨機選樣本集中的數,而此處是隨機生成範圍內的數,未必是樣本集中存在的x1x4x_1到x_4):
在上面得到了點的橫縱座標之後(即dot_x,dot_y),現在組合成數據集(注意dot_x,dot_y)都是行矢量,所以組成矩陣數據集後要轉置

dot_x = sheet.col_values(0)
dot_y = sheet.col_values(1)
dataSet = np.mat([dot_x,dot_y]).T

在這裏插入圖片描述
現在開始隨機生成聚類中心

def randcenters(dataSet,k):    #輸入數據集和k
    n = np.shape(dataSet)[1]   #查看k有多少列,實際上就是點的座標的維度,比如兩維x,y
    centroids = np.matrix(np.zeros((k,n)))  #zeros得到的是數組,一定要變成矩陣,否則centroids[:,0]並不表示第一列
    for J in range(n):
        rangeJ = float(max(dataSet[:,J])-min(dataSet[:,J])) #求出範圍,注意 A
        centroids[:,J] = min(dataSet[:,J]) + rangeJ*np.random.rand(k,1) #生成聚類中心
    return centroids

上面中注意“A”部分:rangeJ=float…, 此處float一定不能少,因爲max(dataSet[:,J])還是矩陣,是1×11\times 1矩陣。
在這裏插入圖片描述
經過float之後變成浮點數。
測試一下

test = randcenters(dataSet,2)

在這裏插入圖片描述
所以這裏得到的兩個質心就是初始均值向量,即
μ1=(5.000,4.939);μ2=(3.924,6.698)\mu _1=(5.000,4.939);\mu_2=(3.924,6.698)
現在計算上面的數據集到質心的距離(歐氏距離)

def distEclud(vecA,vecB):     #輸入的是數組,不能用list形式
    return np.sqrt(sum(np.power(vecA-vecB,2)))

開始着手聚類算法:

def kMeans(dataSet,k): #不妨以k=2舉例
    m = np.shape(dataSet)[0]  #顯示數據集的個數,即有多少個數據需要處理
    ClustDist = np.mat(np.zeros((m,2))) #聚類最小距離的索引值和此距離。第一列放索引值,第二列放最小距離
    clustercents = randcenters(dataSet,k)  #調用生成隨機聚類
    clusterChanged = True
    while clusterChanged:     #用while進行迭代
        clusterChanged = False # 設置初始爲False
        # 計算每個數據與隨機初始得到的質心的距離,比如假設只有兩個質心,即k=2,那麼找到每個數據分別到這兩個
        # 點的距離,並保留距離小的那個。比如x1到質心Cent1和質心Cent2的距離分別爲l1和l2,且l1<l2.那麼
        # 就保留l1並記下l1的位置(索引)
        for i in range(m):
            distlist = [distEclud(clustercents[j,:],dataSet[i,:]) for j in range(k)] #計算每個數據與隨機質心間的距離
            minDist = min(distlist)  #找到最小距離
            minIndex = distlist.index(minDist) #最小距離對應的索引值
            
            if ClustDist[i,0] != minIndex: #找到了一個新的聚類中心,因爲是for i in...循環,只要數據集中有一個新中心就變True
                clusterChanged = True
            ClustDist[i,:] = minIndex,minDist  #放置找到的新的最小距離
            
        for cent in range(k):  #假設k=2,即兩個聚類中心
            dInx = np.nonzero(ClustDist[:,0].A == cent)[0]
            ptsInClust = dataSet[dInx] #選擇數據中的數
            clustercents[cent,:] = np.mean(ptsInClust,axis=0)
    return clustercents, ClustDist

完整代碼如下:

def randcenters(dataSet,k):    #輸入數據集和k
    n = np.shape(dataSet)[1]   #查看k有多少列,實際上就是點的座標的維度,比如兩維x,y
    centroids = np.matrix(np.zeros((k,n)))  #zeros得到的是數組,一定要變成矩陣,否則centroids[:,0]並不表示第一列
    for J in range(n):
        rangeJ = float(max(dataSet[:,J])-min(dataSet[:,J])) #求出範圍,注意 A
        centroids[:,J] = min(dataSet[:,J]) + rangeJ*np.random.rand(k,1) #生成聚類中心
    return centroids

def distEclud(vecA,vecB):
    return np.sqrt(sum(np.power(vecA-vecB,2)))

def kMeans(dataSet,k): #不妨以k=2舉例
    m = np.shape(dataSet)[0]  #顯示數據集的個數,即有多少個數據需要處理
    ClustDist = np.mat(np.zeros((m,2))) #聚類最小距離的索引值和此距離。第一列放索引值,第二列放最小距離
    clustercents = randcenters(dataSet,k)  #調用生成隨機聚類
    clusterChanged = True
    while clusterChanged:     #用while進行迭代
        clusterChanged = False # 設置初始爲False
        # 計算每個數據與隨機初始得到的質心的距離,比如假設只有兩個質心,即k=2,那麼找到每個數據分別到這兩個
        # 點的距離,並保留距離小的那個。比如x1到質心Cent1和質心Cent2的距離分別爲l1和l2,且l1<l2.那麼
        # 就保留l1並記下l1的位置(索引)
        for i in range(m):
            distlist = [distEclud(clustercents[j,:],dataSet[i,:]) for j in range(k)] #計算每個數據與隨機質心間的距離
            minDist = min(distlist)  #找到最小距離
            minIndex = distlist.index(minDist) #最小距離對應的索引值
            
            if ClustDist[i,0] != minIndex: #找到了一個新的聚類中心,因爲是for i in...循環,只要數據集中有一個新中心就變True
                clusterChanged = True
            ClustDist[i,:] = minIndex,minDist  #放置找到的新的最小距離
            
        for cent in range(k):  #假設k=2,即兩個聚類中心
            dInx = np.nonzero(ClustDist[:,0].A == cent)[0]
            ptsInClust = dataSet[dInx] #選擇數據中的數
            clustercents[cent,:] = np.mean(ptsInClust,axis=0)
    return clustercents, ClustDist
        

workbook = xlrd.open_workbook('C:/users/Lenovo/Desktop/test.xlsx')
sheet = workbook.sheet_by_name('Sheet1')

dot_x = sheet.col_values(0)
dot_y = sheet.col_values(1)
dataSet = np.mat([dot_x,dot_y]).T

k = 2
clustercents,ClustDist = kMeans(dataSet,k)
print(clustercents)

結果是新的聚類中心,即μ1=(2.6,2.7),μ2=(8.15,7.5)\mu_1=(2.6,2.7),\mu_2=(8.15,7.5)
在這裏插入圖片描述
最後輸出聚類結果圖片
圖片分析部分不做進一步講解,完整代碼如下

#from numpy import *
import numpy as np
import xlrd
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans

#隨機生成聚類中心
def randcenters(dataSet,k):    #輸入數據集和k
    n = np.shape(dataSet)[1]   #查看k有多少列,實際上就是點的座標的維度,比如兩維x,y
    centroids = np.matrix(np.zeros((k,n)))  #zeros得到的是數組,一定要變成矩陣,否則centroids[:,0]並不表示第一列
    for J in range(n):
        rangeJ = float(max(dataSet[:,J])-min(dataSet[:,J])) #求出範圍,注意 A
        centroids[:,J] = min(dataSet[:,J]) + rangeJ*np.random.rand(k,1) #生成聚類中心
    return centroids

def distEclud(vecA,vecB):
    return np.sqrt(sum(np.power(vecA-vecB,2)))

def kMeans(dataSet,k): #不妨以k=2舉例
    m = np.shape(dataSet)[0]  #顯示數據集的個數,即有多少個數據需要處理
    ClustDist = np.mat(np.zeros((m,2))) #聚類最小距離的索引值和此距離。第一列放索引值,第二列放最小距離
    clustercents = randcenters(dataSet,k)  #調用生成隨機聚類
    clusterChanged = True
    while clusterChanged:     #用while進行迭代
        clusterChanged = False # 設置初始爲False
        # 計算每個數據與隨機初始得到的質心的距離,比如假設只有兩個質心,即k=2,那麼找到每個數據分別到這兩個
        # 點的距離,並保留距離小的那個。比如x1到質心Cent1和質心Cent2的距離分別爲l1和l2,且l1<l2.那麼
        # 就保留l1並記下l1的位置(索引)
        for i in range(m):
            distlist = [distEclud(clustercents[j,:],dataSet[i,:]) for j in range(k)] #計算每個數據與隨機質心間的距離
            minDist = min(distlist)  #找到最小距離
            minIndex = distlist.index(minDist) #最小距離對應的索引值
            
            if ClustDist[i,0] != minIndex: #找到了一個新的聚類中心,因爲是for i in...循環,只要數據集中有一個新中心就變True
                clusterChanged = True
            ClustDist[i,:] = minIndex,minDist  #放置找到的新的最小距離
            
        for cent in range(k):  #假設k=2,即兩個聚類中心
            dInx = np.nonzero(ClustDist[:,0].A == cent)[0]
            ptsInClust = dataSet[dInx] #選擇數據中的數
            clustercents[cent,:] = np.mean(ptsInClust,axis=0)
    return clustercents, ClustDist
        
def color_cluster(dataindx, dataSet, plt):
    datalen = len(dataindx)
    for indx in range(datalen):
        if int(dataindx[indx]) == 0:
            plt.scatter(dataSet[indx, 0], dataSet[indx, 1], c='blue', marker='o')
        elif int(dataindx[indx]) == 1:
            plt.scatter(dataSet[indx, 0], dataSet[indx, 1], c='green', marker='o')
        elif int(dataindx[indx]) == 2:
            plt.scatter(dataSet[indx, 0], dataSet[indx, 1], c='red', marker='o')
        elif int(dataindx[indx]) == 3:
            plt.scatter(dataSet[indx, 0], dataSet[indx, 1], c='cyan', marker='o')
            
def drawScatter(plt, mydata, size=20, color='blue', mrkr='o'):
    plt.scatter(mydata.T[0].tolist(), mydata.T[1].tolist(), s=size, c=color, marker=mrkr)
    
workbook = xlrd.open_workbook('C:/users/Lenovo/Desktop/test.xlsx')
sheet = workbook.sheet_by_name('Sheet1')

dot_x = sheet.col_values(0)
dot_y = sheet.col_values(1)
dataSet = np.mat([dot_x,dot_y]).T

k = 2
clustercents,ClustDist = kMeans(dataSet,k)
print(clustercents)
color_cluster(ClustDist[:, 0:1], dataSet, plt)
drawScatter(plt,clustercents,color='red',mrkr='D')

聚類中心
在這裏插入圖片描述
聚類結果
在這裏插入圖片描述

(二)調用現有庫

使用sklearn
關於sklearn庫可以參考這篇文章:https://blog.csdn.net/u014248127/article/details/78885180,
作者寫得很詳細
也可以初步掃一下這個:https://blog.csdn.net/Mr_Cat123/article/details/84594032

import numpy as np
import xlrd
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans

workbook = xlrd.open_workbook('C:/users/Lenovo/Desktop/test.xlsx')
sheet = workbook.sheet_by_name('Sheet1')

data_x = sheet.col_values(0)
data_y = sheet.col_values(1)
dataSet = np.mat([data_x,data_y]).T


dataSet_arr = np.array(dataSet)
print(dataSet_arr)
model = KMeans(n_clusters=2) #n_cluster即上面的k值,表示有多少個類

y_pred = model.fit_predict(dataSet_arr)
plt.scatter(dataSet_arr[:,0],dataSet_arr[:,1],c=y_pred)
plt.show()

這裏輸出的y_pred爲下圖
在這裏插入圖片描述
表示0,1是一類,2,3是一類。
結果如下
在這裏插入圖片描述
參考文獻
1,https://www.cnblogs.com/eczhou/p/7860424.html
2,機器學習實踐第十章
3,https://blog.csdn.net/u014248127/article/details/78885180

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