上次簡單介紹了kNN演算法,簡單來說,通過計算目標值與樣本資料的距離,選取k個最近的值,用出現概率大的分類值代表目標值的分類,演算法實現比較簡單,屬於監督學習方法。 這篇文章打算簡單介紹k-means聚類演算法,與之前不同,是一種非監督的學習方法。 機器學習中兩類大問題,分類和聚類。 分類是根據一些給定的已知類別標號的樣本,訓練某種學習機器,使它能夠對未知類別的樣本進行分類。這屬於supervised learning(監督學習)。而聚類指事先並不知道任何樣本的類別標號,希望通過某種演算法來把一組未知類別的樣本劃分成若干類別,這在機器學習中被稱作 unsupervised learning (無監督學習)。
k-means 聚類演算法
通常,根據樣本間的某種距離或者相似性來將樣本分為不同類別,成為聚類。 比如給定資料集,部分資料(二維, 共80個)如下:
1.658985 4.285136
-3.453687 3.424321
4.838138 -1.151539
-5.379713 -3.362104
0.972564 2.924086
複製程式碼
其視覺化如下:
從分佈狀態,可以大概知道可以聚為4個cluster。最後目的是將4個不同的cluster標上不同的顏色。 利用k-means演算法如下實現:- 隨機選取k個點作為初始質心。
- 對於樣本中每一個點,分別求與k點的距離。距離最小者就屬於該類。
- 此時對得到的k各類,重新計算新的質心。
- 當3步得到的質心與之前的質心誤差很小時,分類結束。 其中用到的公式都特別簡單,後面程式碼有詳細敘述。
python 程式碼實現
# 資料初始化
import numpy as np
import random
import re
import matplotlib.pyplot as plt
def loadDataSet():
dataSet = np.loadtxt("dataSet.csv")
return dataSet
複製程式碼
def initCentroids(dataSet, k):
# 從資料集中隨機選取k個資料返回
dataSet = list(dataSet)
return random.sample(dataSet, k)
複製程式碼
對應第2步,計算距離並分類,根據到不同質心的最短距離分類,用字典儲存。
def minDistance(dataSet, centroidList):
# 對每個屬於dataSet的item, 計算item與centroidList中k個質心的距離,找出距離最小的,並將item加入相應的簇類中
clusterDict = dict() #dict儲存簇類結果
k = len(centroidList)
for item in dataSet:
vec1 = item
flag = -1
minDis = float("inf") # 初始化為最大值
for i in range(k):
vec2 = centroidList[i]
distance = calcuDistance(vec1, vec2) # error
if distance < minDis:
minDis = distance
flag = i # 迴圈結束時, flag儲存與當前item最近的蔟標記
if flag not in clusterDict.keys():
clusterDict.setdefault(flag, [])
clusterDict[flag].append(item) #加入相應的類別中
return clusterDict #不同的類別
複製程式碼
def getCentroids(clusterDict):
#重新計算k個質心
centroidList = []
for key in clusterDict.keys():
centroid = np.mean(clusterDict[key], axis=0)
centroidList.append(centroid)
return centroidList #得到新的質心
複製程式碼
計算計算各蔟集合間的均方誤差,來衡量聚類的效果
def getVar(centroidList, clusterDict):
# 計算各蔟集合間的均方誤差
# 將蔟類中各個向量與質心的距離累加求和
sum = 0.0
for key in clusterDict.keys():
vec1 = centroidList[key]
distance = 0.0
for item in clusterDict[key]:
vec2 = item
distance += calcuDistance(vec1, vec2)
sum += distance
return sum
複製程式碼
#測試聚類效果,並視覺化
def test_k_means():
dataSet = loadDataSet()
centroidList = initCentroids(dataSet, 4)
clusterDict = minDistance(dataSet, centroidList)
# # getCentroids(clusterDict)
# showCluster(centroidList, clusterDict)
newVar = getVar(centroidList, clusterDict)
oldVar = 1 # 當兩次聚類的誤差小於某個值是,說明質心基本確定。
times = 2
while abs(newVar - oldVar) >= 0.00001:
centroidList = getCentroids(clusterDict)
clusterDict = minDistance(dataSet, centroidList)
oldVar = newVar
newVar = getVar(centroidList, clusterDict)
times += 1
showCluster(centroidList, clusterDict)
if __name__ == '__main__':
# show_fig()
test_k_means()
複製程式碼
如上如,當兩次計算質心之間的誤差在0.00001之內時,可以認為聚類完成。 執行函式:
從結果可以看出,對著不斷的迭代,聚類的效果越來越好,直至小於誤差,完成聚類。
完成程式碼和資料請參考github:
github:k-means
總結
- 無監督學習
- k-means演算法
- 最小化平方差刻畫蔟內向量的緊密程度。
參考資料:(內有公式介紹)
聚類之均值聚類(k-means)演算法的python實現
機器學習演算法與Python實踐之(五)k均值聚類(k-means)