機器學習-*-K均值聚類及程式碼實現
阿新 • • 發佈:2018-11-27
KMeans聚類
在聚類演算法中,最出名的應該就是k均值聚類(KMeans)了,幾乎所有的資料探勘/機器學習書籍都會介紹它,有些初學者還會將其與KNN等混淆。k均值是一種聚類演算法,屬於無監督學習的一種,而KNN是有監督學習/分類學習的一種。
聚類:顧名思義,就是講某些相似的事物聚在一起,形成一個類。這裡就涉及到幾個概念
1.如何表示一個事物?通常我們會準備好一個數據集,裡面是我們的資料,每一行代表的都是一個數據,每一列是一個數據的一種特徵。比如經典的分類資料集 iris(鳶尾花資料),每一行代表的是每一朵花,每一朵花都有花萼長度,花萼寬度,花瓣長度,花瓣寬度 4個特徵,即有4列特徵。
2.如何度量事物間的距離?我們拿到每一個數據的特徵值之後,需要根據實際情況來進行兩種資料之間的計算,常用的方法是歐氏距離、馬氏距離、餘弦距離等。
3.按照什麼樣的過程進行聚類?這裡就涉及到具體的演算法了,目前聚類大致有幾個比較流行的方法:基於劃分、基於層次、基於密度、基於網路。這裡的K均值就屬於基於劃分的方法,後續會繼續寫其餘幾種方法的代表演算法。
4.如何能判斷聚類過程結束呢?當每一種類別中的資料趨於穩定,即為完成聚類
KMeans過程
上圖是擷取別人blog中的圖片(參考文獻1),這裡講的其實很清楚了。
上程式碼:
#!/usr/bin/python # -*- coding:utf-8 -*- """ Author LiHao Time 2018/11/26 9:21 """ import os import sys import numpy as np import scipy as sp from sklearn.datasets import load_iris # 歐式距離函式 from ml_learn.algorithm.distance import eculide import matplotlib.pyplot as plt def load_data(): """ 匯入iris標準資料集 :return: """ iris = load_iris() data = iris.data target = iris.target target_names = iris.target_names return data,target,target_names class Group(object): """ 定義類簇 """ def __init__(self): self._name = "" self._no = None self._members = [] self._center = None @property def no(self): return self._no @property def name(self): return self._name @name.setter def name(self,no): self._no = no self._name = "G"+str(self._no) @property def members(self): return self._members @members.setter def members(self,member): if member is None: raise TypeError("member is None,please set value") self._members.append(member) def clear_members(self): self._members = [] @property def center(self): return self._center @center.setter def center(self,c): self._center = c class KMeans(object): def __init__(self,k = 2): if (k <= 1) or (k is None): raise ValueError("k's num must not none and must > 1.") self._k = k # 類簇 self._groups = self._make_groups(k) self._pre_mean_value = 0 self._current_mean_value = 1 def _make_groups(self,k): """ 生成類簇 :param k: :return: """ groups = [] for i in range(k): g = Group() g.name = i+1 groups.append(g) return groups def _random_x_index(self,xlen): indexes = np.random.randint(0,xlen,self._k).tolist() return indexes def _compute_mean_value(self): sum = 0 for i in range(len(self._groups)): average = self._compute_members_mean(self._groups[i].members) self._groups[i].center = average sum += average return sum/(len(self._groups)) def _compute_members_mean(self,members): np_members = np.array(members) average = np.average(np_members,axis=0) return average def _find_most_nearby_group(self,x): np_groups = np.array([group.center for group in self._groups]) distances = eculide(x,np_groups) most_similarity_index = np.argmin(distances).squeeze() self._groups[most_similarity_index].members = x return most_similarity_index def _clear_groups_members(self): for group in self._groups: group.clear_members() def fit(self,X): rows,cols = X.shape # 1.首先選取k個點為初始聚類中心點 init_indexes = self._random_x_index(rows) for i,index in enumerate(init_indexes): self._groups[i].center = X[index] self._groups[i].members = X[index] # 2.計算每個資料與聚類中心的距離,加入到最近那一個類 while(True): for i in range(rows): #發現距離最近的group 並將資料加入至類簇中 self._find_most_nearby_group(X[i]) # 3.重新計算每個類簇的平均值 # 計算各個類別的聚類中心並返回所有類簇的均值 self._current_mean_value = self._compute_mean_value() epos = np.sum(self._current_mean_value-self._pre_mean_value,axis=0).squeeze() if epos <= 0.00001: break # 清除歷史成員 並將計算得到的均值誤差儲存 self._clear_groups_members() self._pre_mean_value = self._current_mean_value # 4.重複2-3的運算,直到每個類簇額均值不再發生變化 def plot_example(self): figure = plt.figure() ax = figure.add_subplot(111) ax.set_title("KMeans Iris Example") colors = ['b','r','y','k','g','c','m'] plt.xlabel("first dim") plt.ylabel("third dim") legends = [] for i in range(len(self._groups)): group = self._groups[i] members = group.members x = [member[0] for member in members] y = [member[2] for member in members] ax.scatter(x,y,c=colors[i],marker='o') legends.append(group.name) plt.legend(legends,loc="best") plt.show() data,target,target_names = load_data() kmeans = KMeans(k=3) kmeans.fit(data) kmeans.plot_example()
經過執行,可以得到類似下圖的結果:選取的是iris資料集,展示的是第一維和第三維的二位平面圖。iris真實資料是分為3類,每一類50個數據。
每次執行的結果可能不一樣,因為我們選取的初始中心點是隨機的,這樣就會造成結果的不穩定性。因此,很多K均值的改進方法就會從初始點選取進行優化;還有的是優化了均值計算,變成了中位數計算(K_median演算法)