1. 程式人生 > >機器學習-K均值聚類(python3程式碼實現)

機器學習-K均值聚類(python3程式碼實現)

K均值聚類

哈爾濱工程大學-537

演算法原理:

K均值是發現給定資料集的k個簇的演算法。簇個數k是使用者給定的,每一個簇通過其質心(centroid),即簇中所有點的中心來描述。

K均值演算法的工作流程是:首先隨機確定k個初始點作為質心。然後將資料集中的每個點分配到一個簇,具體來講,為每個點找距其最近的質心,並將其分配給該之心所對應的簇。這一步完成後,每個簇的質心更新為該簇所有點的平均值。

程式碼實現 :

一、基礎實現

1)首先匯入所需要的各個庫
%matplotlib inline是為了使接下來的繪圖能夠顯示在Jupyter notebook的瀏覽器上。

import
numpy as np
import math import matplotlib.pyplot as plt %matplotlib inline

2)定義載入樣本點資料的函式load_dataset,輸入引數為檔名;
將檔案按行讀取,每一行為一個列表,依次追加到空列表data_mat中,最後以矩陣的形式返回所得。

def load_dataset(file_name):
    data_mat = []
    with open(file_name) as fr:
        lines = fr.readlines()
    for line in lines:
        cur_line = line.strip().split("\t"
) flt_line = list(map(lambda x:float(x), cur_line)) data_mat.append(flt_line) return np.array(data_mat)

3)呼叫load_dataset函式,引數為將要開啟的檔案的路徑和檔名,得到樣本點的特徵矩陣矩陣data_set。

data_set = load_dataset(r"D:\python_data\MachineLearningInaction\machinelearninginaction\Ch10\testSet.txt")
print(data_set)

將其打印出來,得到一個80行,2列的矩陣,其中前9行如下圖:

這裡寫圖片描述

4)利用python的繪相簿繪製樣本點的散點圖。其中橫座標為”factor1”,縱座標為”factor2”。

point_x = data_set[:,0]
point_y = data_set[:,1]        
fig, ax = plt.subplots(figsize=(10,5))
ax.scatter(point_x, point_y, s=30, c="r", marker="o", label="sample point")
ax.legend()
ax.set_xlabel("factor1")
ax.set_ylabel("factor2")

繪製出的散點圖如下圖所示:

這裡寫圖片描述

5)接下來定義一個計算兩個向量之間歐氏距離的函式dist_eclud,已知向量X=(x1,x2...xn)Y=(y1,y2...yn)之間的歐氏距離為
(x1y1)2+(x2y2)2+...+(xnyn)2

def dist_eclud(vecA, vecB):
    vec_square = []
    for element in vecA - vecB:
        element = element ** 2
        vec_square.append(element)
    return sum(vec_square) ** 0.5

6)構建k個隨機質心。輸入引數為資料集data_set和想要構建的質心個數k。隨機質心必須要在整個資料集的邊界之內。首先可以找到資料集每一維的最小和最大值。然後得到每一維的取值範圍。用0到1之間的隨機數和取值範圍相乘,再用最小值加上該乘積,就可以得到在每一維取值範圍內的隨機數。

# 構建k個隨機質心
def rand_cent(data_set, k):
    n = data_set.shape[1]    
    centroids = np.zeros((k, n))
    for j in range(n):
        min_j = float(min(data_set[:,j]))
        range_j = float(max(data_set[:,j])) - min_j
        centroids[:,j] = (min_j + range_j * np.random.rand(k, 1))[:,0]
    return centroids

7)演算法的主函式,輸入引數為資料集和簇的個數。
首先初始化樣本點的簇分配矩陣,有80行2列,第一列為該樣本點的簇分配索引,第二列為該樣本點到該簇質心的歐氏距離。
當任意一個點的簇分配發生變化時,迭代執行以下操作:遍歷每個樣本點,計算樣本點i到各個質心的距離,找到最小距離,將該質心所在簇編號分配給該樣本點。遍歷完所有樣本點後,重新計算每個簇的質心。直到所有樣本點的簇分配都不再發生變化時迭代停止。
最後返回質心和樣本點的簇分配矩陣

def Kmeans(data_set, k):    
    m = data_set.shape[0]   
    cluster_assment = np.zeros((m, 2))  
    centroids = rand_cent(data_set, k)  
    cluster_changed = True        
    while cluster_changed:       
        cluster_changed = False   
        for i in range(m):        
            min_dist = np.inf; min_index = -1   
            for j in range(k):     
                dist_ji = dist_eclud(centroids[j,:], data_set[i,:])
                if dist_ji < min_dist:              
                    min_dist = dist_ji; min_index = j   
            if cluster_assment[i,0] != min_index:    
                cluster_changed = True      
            cluster_assment[i,:] = min_index, min_dist**2   
        for cent in range(k):   
            pts_inclust = data_set[np.nonzero(list(map(lambda x:x==cent, cluster_assment[:,0])))]
            centroids[cent,:] = np.mean(pts_inclust, axis=0)
    return centroids, cluster_assment            

8)呼叫函式Kmean,輸入資料集為data_set,簇數量為4個,得到收斂後的質心和簇分配矩陣(簇分配矩陣略)。

my_centroids, my_cluster_assment = Kmeans(data_set, 4)
print(my_centroids)
# print(my_cluster_assment)

得到的4個質心為:

這裡寫圖片描述

9)為了更加清晰直觀,用繪相簿繪製散點圖,其中,四個質心用黑色▲標出。

point_x = data_set[:,0]
point_y = data_set[:,1]  
cent_x = my_centroids[:,0]
cent_y = my_centroids[:,1]
fig, ax = plt.subplots(figsize=(10,5))
ax.scatter(point_x, point_y, s=30, c="r", marker="o", label="sample point")
ax.scatter(cent_x, cent_y, s=100, c="black", marker="v", label="centroids")
ax.legend()
ax.set_xlabel("factor1")
ax.set_ylabel("factor2")

得到的散點圖如下圖所示:

這裡寫圖片描述

二、二分K-均值聚類

上述演算法的聚類簇的數目k是使用者自定義的,那麼使用者如何才能知道k的選擇是否正確?如何才能知道生成的簇比較好呢?在包含簇分配結果的矩陣中儲存著每個點的誤差,即該點到簇質心的距離平方值。

一種用於度量聚類效果的指標使SSE(Sum of Squared Error,誤差平方和),SSE值越小表示資料點越接近它們的質心,聚類效果也就越好。

於是就可以採用二分K-聚類的方法,具體程式碼實現如下:

1)定義一個bi_Kmeans函式,兩個輸入引數分別為資料集和聚類簇數量。

該函式首先建立一個矩陣cluster_assment來儲存資料集中每個點的簇分配結果及平方誤差,然後計算整個資料集的質心,並使用一個列表cent_list來保留所有的質心。得到上述質心之後,可以遍歷資料集中所有點來計算每個點到質心的誤差值。這些誤差值將會在後面用到。

接下來程式進入while迴圈,該迴圈會不停對簇進行劃分,直到得到想要的簇數目為止。可以通過考察簇列表中的值來獲得當前簇的數目。然後遍歷所有簇來決定最佳的簇進行劃分。

為此需要比較劃分前後的SSE。一開始將最小SSE設定為無窮大,然後遍歷簇列表cent_list中的每一個簇。對每個簇,將該簇中的所有點堪稱一個小的資料集pts_incurr_cluster。將pts_incurr_cluster輸入到函式Kmeans()中進行處理(k=2)。K-均值演算法會生成兩個質心(簇),同時給出每個簇的誤差值。這些誤差與剩餘資料集的誤差之和作為本次劃分的誤差。如果該劃分的SSE值最小,則儲存本次劃分。

一旦決定了要劃分的簇,接下來就可以實際執行劃分操作。劃分操作很容易,只需要將劃分的簇中所有點的簇分配結果進行修改即可。當使用Kmeans()函式並且制定簇數目為2時,會得到兩個編號分別為0和1的結果簇。需要將這些簇編號修改為被劃分簇以及新加簇的編號,該過程可以通過兩個陣列過濾器來完成。

最後,新的簇分配結果被更新,新的質心會被新增到cent_list中。

當while迴圈結束時,同Kmeans()函式一樣,函式返回之心列表與簇分配結果。

# 二分K均值聚類的主函式,輸入引數為資料集和要分的簇的個數
def bi_Kmeans(data_set, k):   
    m = data_set.shape[0]   # 得到data_set的行數,即資料集的個數
    cluster_assment = np.zeros((m,2)) # 初始化樣本點的簇分配矩陣,第一列為簇分配索引,第二列為歐氏距離平方
    centroid0 = np.mean(data_set, axis=0)  # 按列計算均值,即找到初始質心
    cent_list = [centroid0]
    for j in range(m):   # 對於每個樣本點
        cluster_assment[j,1] = dist_eclud(centroid0, data_set[j,:])**2 # 計算該樣本點的誤差平方
    while (len(cent_list) < k):   # 當已有的簇個數小於k時,迭代執行以下程式碼
        lowestSSE = np.inf     # 初始化誤差平方和SSE的最小值

        # 找到對哪個簇進行劃分可以最大程度降低SSE值
        for i in range(len(cent_list)):   # 遍歷每個已有的簇
            # 得到屬於該簇的所有樣本點
            pts_incurr_cluster = \
            data_set[np.nonzero(list(map(lambda x:x==i, cluster_assment[:,0])))]
            # 將該簇的所有樣本點通過函式Kmean進行劃分(k=2),得到劃分後的質心和簇分配矩陣
            centroid_mat, split_clust_ass = Kmeans(pts_incurr_cluster, 2)    
            sse_split = np.sum(split_clust_ass[:,1])  # 得到劃分後的誤差平方和
            # 得到其他樣本點的誤差平方和
            sse_not_split = \
            np.sum(cluster_assment[np.nonzero(list(map(lambda x:x!=i, cluster_assment[:,0]))),1])
            if (sse_split + sse_not_split) < lowestSSE:  # 如果總的誤差平方和小於lowestSSE
                best_cent_to_split = i                   # 則儲存本次劃分
                best_new_cents = centroid_mat
                best_clust_ass = split_clust_ass
                lowestSSE = sse_split + sse_not_split
        # 對最大程度降低SSE值的簇進行劃分

        # 將劃分後得到的編號為0的結果簇的編號修改為原最大簇編號+1,即len(cent_list)
        best_clust_ass[np.nonzero(list(map(lambda x:x==1, best_clust_ass[:,0]))), 0] = len(cent_list)  
         # 將劃分後得到的編號為1的結果簇的編號修改為被劃分的簇的編號
        best_clust_ass[np.nonzero(list(map(lambda x:x==0, best_clust_ass[:,0]))), 0] = best_cent_to_split 
        cent_list[best_cent_to_split] = best_new_cents[0,:] # 更新被劃分的簇的質心
        cent_list.append(best_new_cents[1,:])  # 新增一個新的簇的質心
        cluster_assment[np.nonzero(list(map(lambda x:x==best_cent_to_split, cluster_assment[:,0]))),:] = \
            best_clust_ass  # 將簇分配矩陣中屬於被劃分的簇的樣本點的簇分配進行更新
    return np.array(cent_list), cluster_assment

2)接下來呼叫bi_Kmeans()函式,得到三個質心和簇分配結果(簇分配結果略),在呼叫bi_Kmeans()函式前,先執行load_dataset()函式載入資料。

data_set2 = load_dataset(r"D:\python_data\MachineLearningInaction\machinelearninginaction\Ch10\testSet2.txt")
cent_list, cluster_assment = bi_Kmeans(data_set2, 3)
print(cent_list)

這裡寫圖片描述

3)最後,用繪相簿繪製散點圖,橫座標為”factor1”,縱座標為”factor2”,其中三個質心用黑色X標出。

point_x = data_set2[:,0]
point_y = data_set2[:,1] 
cent_x = cent_list[:,0]
cent_y = cent_list[:,1]
fig, ax = plt.subplots(figsize=(10,5))
ax.scatter(point_x, point_y, s=30, c="r", marker="o", label="sample point")
ax.scatter(cent_x, cent_y, s=100, c="black", marker="x", label="centroids")
ax.legend()
ax.set_xlabel("factor1")
ax.set_ylabel("factor2")

所繪製的散點圖如下:

這裡寫圖片描述

相關推薦

機器學習-K均值(python3程式碼實現)

K均值聚類 哈爾濱工程大學-537 演算法原理: K均值是發現給定資料集的kk個簇的演算法。簇個數kk是使用者給定的,每一個簇通過其質心(centroid),即簇中所有點的中心來描述。 K均值演算法的工作流程是:首先隨機確定kk個初始點作為質心。然後

機器學習-*-K均值程式碼實現

KMeans聚類 在聚類演算法中,最出名的應該就是k均值聚類(KMeans)了,幾乎所有的資料探勘/機器學習書籍都會介紹它,有些初學者還會將其與KNN等混淆。k均值是一種聚類演算法,屬於無監督學習的一種,而KNN是有監督學習/分類學習的一種。 聚類:顧名思義,就是講某些相似的事物聚在

機器學習——K-均值K-means)演算法

本文轉載自:https://www.cnblogs.com/ybjourney/p/4714870.html 一 K-均值聚類(K-means)概述 聚類 “類”指的是具有相似性的集合。聚類是指將資料集劃分為若干類,使得類內之間的資料最為相似,各類之間的資料相

無監督學習——K-均值算法對未標註數據分組

機器學習算法 可能 變化 分類 結果 sts lis mat 得到 無監督學習 和監督學習不同的是,在無監督學習中數據並沒有標簽(分類)。無監督學習需要通過算法找到這些數據內在的規律,將他們分類。(如下圖中的數據,並沒有標簽,大概可以看出數據集可以分為三類,

機器學習 K-means 演算法 C++

筆記: 尚未解決的問題 :     1. 只支援二維,而不支援三維或更高,需要模板元     2. 尚未實現如何刪除極端點, 即預處理     3. 尚未視覺化 編譯環境 Ubuntu gcc 5.4 編譯選項  g++ -std=c++14 #include &l

機器學習之層次程式碼示例

一、層次聚類 層次聚類是無監督學習方法,可對給定的N個待聚類的樣本進行層次的分類,直到某種條件(類的個數、類間的距離超過某個閾值)滿足為止。 1、層次聚類的劃分 對於層次聚類,可具體分為: a. 凝聚的(agglomerative)層次聚類: 採用

機器學習之劃分程式碼示例

一、聚類 聚類是一種無監督學習,根據樣本的內在相似性/距離,將大量未知標記的樣本集劃分為多個類別,使得同一個類別內的樣本相似度較大(距離較小),而不同類別間的樣本相似度較小(距離較大)。 劃分聚類包含K-Means、Bisecting K-Means(二分K

機器學習實戰(Machine Learning in Action)學習筆記————06.k-均值演算法(kMeans)學習筆記

機器學習實戰(Machine Learning in Action)學習筆記————06.k-均值聚類演算法(kMeans)學習筆記關鍵字:k-均值、kMeans、聚類、非監督學習作者:米倉山下時間:2018-11-3機器學習實戰(Machine Learning in Action,@author: Pet

機器學習實戰———k均值 演算法

問題:關於第九章list()新增的問題 fltLine = list(map(float,curLine)) fltLine = map(float,curLine) 二者的區別在於 加list()輸出為數 [1.658985, 4.285136] [-3.453

機器學習實戰》二分-kMeans演算法(二分K均值

首先二分-K均值是為了解決k-均值的使用者自定義輸入簇值k所延伸出來的自己判斷k數目,其基本思路是: 為了得到k個簇,將所有點的集合分裂成兩個簇,從這些簇中選取一個繼續分裂,如此下去,直到產生k個簇。 虛擬碼: 初始化簇表,使之包含由所有的點組成的簇。 repeat   &n

機器學習實戰---讀書筆記: 第10章 利用K均值演算法對未標註資料分組---1

#!/usr/bin/env python # encoding: utf-8 import os from matplotlib import pyplot as plt from numpy import * ''' 讀書筆記之--<<機器學習實戰>>--第10章_

Python機器學習演算法實踐——k均值k-means)

一開始的目的是學習十大挖掘演算法(機器學習演算法),並用編碼實現一遍,但越往後學習,越往後實現編碼,越發現自己的編碼水平低下,學習能力低。這一個k-means演算法用Python實現竟用了三天時間,可見編碼水平之低,而且在編碼的過程中看了別人的編碼,才發現自己對

機器學習實戰》筆記之十——利用K均值演算法對未標註資料分組

第十章 利用K均值聚類演算法對未標註資料分組 10.1 K-均值聚類演算法 K-均值是發現給定資料集的k個簇的演算法,每個簇通過其質心來描述。其優點為容易實現,但可能收斂到區域性最小值,在大規模資料集上收斂較慢。 隨機確定k個初始點為質心,為每個點找距其最近的質心,並將

機器學習(二)——K均值演算法(K-means)

概述: 1.聚類 “類”指的是具有相似性的集合。聚類是指將資料集劃分為若干類,使得類內之間的資料最為相識,各類之間的資料相似度差別儘可能大。聚類分析就是以相似性為基礎,對資料集進行聚類分析,屬於無監督學習。 2.無監督學習和監督學習 k-均值聚類(k-means)與k-近鄰(knn)

斯坦福大學機器學習筆記——k-均值演算法、損失函式、初始化、數目的選擇)

上面的部落格的演算法都是有監督學習的演算法,即對於每個資料我們都有該資料對應的標籤,資料集的形式如下: 而今天我們學習的演算法是一種無監督學習的演算法——聚類,該演算法中的每個資料沒有標籤,資料集的形式如下: K-均值聚類 k-均值聚類是一種最常見

機器學習實戰之k-means_程式碼註釋

#-*- coding: UTF-8 -*- from numpy import * def loadDataSet(fileName):#函式的輸入為檔名稱,函式的主要作用是將檔案中的每行內容轉換成浮點型, # 每行

python機器學習案例系列教程——k均值k中心點

上一篇我們學習了層次聚類。層次聚類只是迭代的把最相近的兩個聚類匹配起來。並沒有給出能給出多少的分組。今天我們來研究一個K均值聚類。就是給定分組數目的基礎上再來聚類。即將所有的樣本資料集分成K個組,每個組內儘可能相似,每個組間又儘可能不相似。 k均值聚類和k

機器學習練習(七)—— K-均值與主成分分析

這篇文章是一系列 Andrew Ng 在 Coursera 上的機器學習課程的練習的一部分。這篇文章的原始程式碼,練習文字,資料檔案可從這裡獲得。 現在我們到了本系列最後兩篇文章了!在本部分,我們將會討論

機器學習實戰》學習筆記———利用K-均值演算法對未標註資料分組

引言 K-均值演算法試圖將一系列樣本分割成K個不同的類簇(其中K是模型的輸入引數),其形式化的目標函式稱為類簇內的方差和(within cluster sum of squared errors,WCSS)。K-均值聚類的目的是最小化所有類簇中的