機器學習算法複習---聚類算法之KMeans

         瞭解基礎的機器學習知識即瞭解基礎的機器學習的一些名詞但沒有實現過機器學習算法的人觀看且對python不瞭解的也可以看,每一處具有註釋。本文使用的python3編譯環境,與python2編譯環境有一些差別,不過不影響大體。本文的理論部分以西瓜書和統計學習方法爲參考,代碼實現以機器學習實戰爲參考。

         好!開始上代碼!主要介紹聚類算法中的KMeans算法,其他的陸續更新

         一、手寫KMeans

        理論部分

              1、聚類算法:聚類試圖將數據集中的樣本劃分爲若干個通常是不相交的子集,每個子集稱爲一個"簇" (cluster). 通過這樣的劃分,每個簇可能對應於一些潛在的概念(類別) ,如"淺色瓜" "深色瓜","有籽瓜" "無籽瓜",甚至"本地瓜""外地瓜"等;需說明的是,這些概念對聚類算法而言事先是未知的,聚類過程僅能自動形成簇結構,簇所對應的概念語義需由使用者來把握和命名. 

              

               人話版本:當思考聚類算法的時候,我第一次想到的是人以羣分,物以類聚。舉個例子面對一個班級的學生我們可以根據數學考試的分數90-100分爲一等,80-90分爲二等。。面對我們不知道怎麼分類的事物我們怎麼實現物以類聚,(哈哈本專業來幫忙了),在植物學中我們怎麼分類各種植物呢?動物學中我們怎麼分類各種動物呢?全國的草地如何進行分類呢?拿全國的草地如何進行分類來說,我們要蒐集各個草地所在地的降水量、溫度、適度、主要的建羣種等屬性然後將其量化。爲敘述簡單僅取一個屬性降水量來分析。輸入不同地區的降水量,計算不同地區之間的差距,比如分爲兩類,從中隨機選擇兩地,其他的地區以這倆地方爲標準計算與這兩地的距離,並選擇最小的進行投靠,這樣就能將其分類。那麼問題來了?如何計算他們之間的差距?

           2、距離的計算------距離算法的靈魂

              介紹距離計算之前先介紹屬性

                     連續屬性:在定義域上有無窮多個可能的取值

                     離散屬性:在定義域上是有限個取值

                    有序屬性:能直接在屬性值上計算距離 "1" 與 "2" 比較接近、與 "3" 比較遠,這樣屬性稱爲"有序屬性" (ordinal attribute),數據具有一定的等級順序; 而定義域爲{飛機,火車,輪船}這樣的離散屬性則不能直接在屬性值上計算距離,稱爲"無序屬性" (non-ordinal
attribute) .  。

               

閔可夫斯基距離

 

 

閔可夫斯基距離可用於有序屬性

p=2 時,閔可夫斯基距離即歐氏距離 (Euclidean distance) --即兩點之間距離公式

p=l 時,閔可夫斯基距離即曼哈頓距離 (Manhattan distance)

街區距離" (city block distance)

 

 

VDM(Value Difference Metric)

與本文無關省略

思想

公式

 

例子

 

others

 

       代碼部分

            k-means clustering
                  Pros: Easy to implement
                  Cons: Can converge at local minima; slow on very large datasets
                  Works with: Numeric values

         僞代碼

創建k個點作爲起始質心(經常是隨機選擇)
當任意一個點的簇分配結果發生改變時 
    對養據集中的每個數據點 
        對每個質心
            計算質心與數據點之間的距離 
        將數據點分配到距其最近的簇 
    對每一個簇,計算簇中所有點的均值並將均值作爲質心

           python3

              

# -*- coding: utf-8 -*-
"""
k-means clustering
    Pros: Easy to implement 
    Cons: Can converge at local minima; slow on very large datasets 
    Works with: Numeric values
 
@author: 
"""

from numpy import *
import numpy as np
#加載數據
def loadDataSet(fileName):
    datMat =[] 
    fr = open(fileName)
    for line in fr.readlines():
        curLine = line.strip().split('\t')
        ##這裏與原文不一樣。
        datMat.append(curLine)
        dataMat = np.array(datMat)
        ##astype 將numpy數組類型轉換爲float形式
        dataMat = dataMat.astype(float)
        
    return dataMat

#計算歐式距離
def distEclud(vecA, vecB):
     return sqrt(sum(power(vecA - vecB, 2)))
 

##獲得初始蔟質心
##centroids:中心點
def randCent(dataSet, k):
    ##獲得列數
    n = shape(dataSet)[1]
    ##創建k行n列的0矩陣
    centroids = mat(zeros((k,n)))
    for j in range(n):                     
        minJ = min(dataSet[:,j]) 
        rangeJ = float(max(dataSet[:,j]) - minJ)
        centroids[:,j] = minJ + rangeJ * random.rand(k,1)
    return centroids


def kMeans(dataSet, k, distMeas=distEclud, createCent=randCent):
    ##獲得行數
    m = shape(dataSet)[0]
    """
    clusterAssment:蔟分配結果矩陣
        第一列:記錄蔟索引值
        第二列:誤差---當前點到簇質心的距離
    """
    clusterAssment = mat(zeros((m,2))) 
    #獲得初始質心
    centroids = createCent(dataSet, k)
    clusterChanged = True
    while clusterChanged:
        clusterChanged = False
        
        for i in range(m):
            #minDist初始值設置爲無窮大  inf:無窮大
            minDist = inf; minIndex = -1
            ##選出第i個元素距離那一個蔟最小
            for j in range(k):
                ##計算每一個元素與質心J的歐氏距離                                
                distJI = distMeas(centroids[j,:],dataSet[i,:])  
                if distJI < minDist:                          
                    minDist = distJI; minIndex = j
            
            ##只要當前第i個元素所屬於的蔟與之前不想等就繼續循環
            if clusterAssment[i,0] != minIndex: clusterChanged = True
            
            ##將當前的第i個元素距離第j個蔟最小記錄下來
            clusterAssment[i,:] = minIndex,minDist**2
            
        for cent in range(k):         
            ##clusterAssment[:,0]第一列元素 list
            ##屬於第cent個質心的所有元素賦值給ptsInClust                                
            ptsInClust = dataSet[nonzero(clusterAssment[:,0]==cent)[0]]
            ##axis = 0表示矩陣的列方向按均值計算
            ##計算每一蔟的均值
            centroids[cent,:] = mean(ptsInClust, axis=0)      
            
    return centroids, clusterAssment

          調用SKlearn中的算法

          

# -*- coding: utf-8 -*-
"""
Created on Mon Nov 25 10:36:56 2019

@author: 
"""

import numpy as np
import matplotlib.pyplot as mp
import sklearn.cluster as sc

# 讀取數據,繪製圖像
#x = np.loadtxt('testSet.txt', unpack=False, dtype='f8', delimiter=',')
datMat =[] 
fr = open('testSet.txt')
for line in fr.readlines():
    curLine = line.strip().split('\t')
    fltLine = curLine
    datMat.append(fltLine)
    dataMat = np.array(datMat)

dataMat = dataMat.astype(float)

print(dataMat.shape)
#print(dataMat)
# 基於Kmeans完成聚類
model = sc.KMeans(n_clusters=4)
model.fit(dataMat)  # 完成聚類
pred_y = model.predict(dataMat)  # 預測點在哪個聚類中
print(pred_y)  # 輸出每個樣本的聚類標籤
#獲取聚類中心
centers = model.cluster_centers_
print("聚類中心",centers)

# 繪製分類邊界線
l, r = dataMat[:, 0].min() - 1, dataMat[:, 0].max() + 1
b, t = dataMat[:, 1].min() - 1, dataMat[:, 1].max() + 1
n = 500
grid_x, grid_y = np.meshgrid(np.linspace(l, r, n), np.linspace(b, t, n))
bg_x = np.column_stack((grid_x.ravel(), grid_y.ravel()))
bg_y = model.predict(bg_x)
grid_z = bg_y.reshape(grid_x.shape)



# 畫圖顯示樣本數據
mp.figure('Kmeans', facecolor='lightgray')
mp.title('Kmeans', fontsize=16)

mp.xlabel('X', fontsize=14)
mp.ylabel('Y', fontsize=14)

mp.tick_params(labelsize=10)
mp.pcolormesh(grid_x, grid_y, grid_z, cmap='gray')
mp.scatter(dataMat[:, 0], dataMat[:, 1], s=80, c=pred_y, cmap='brg', label='Samples')
mp.scatter(centers[:, 0], centers[:, 1], s=300, color='red', marker='+', label='cluster center')

mp.legend()

mp.show()

 

 

 

 

 

 

 

 

 

 

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