本章內容:
1. K-均值聚類算法。
2. 對聚類得到的簇進行後處理。
3. 二分K-均值聚類算法。
4. 對地理位置進行聚類。
========================================================================
K-聚類算法是一種無監督學習算法。首先明白什麼是無監督學習:輸入數據有標籤,則爲有監督學習,沒標籤則爲無監督學習。可以參考這個知乎的鏈接:什麼是無監督學習?
聚類就是一種無監督的學習,它將相似的對象歸到同一個簇中,有點像全自動分類。聚類方法幾乎可以應用於所有對象。簇內的對象越相似,聚類的效果越好。本章要學習一種稱爲 K-means 聚類的算法。之所以稱爲 K-均值 是因爲它可以發現 k 個不同的簇,且每個簇的中心採用簇中所含值的均值計算而成。
聚類與分類的最大不同在於:分類的目標事先已知,而聚類則不一樣。因爲其產生的結果與分類相同,而只是類別沒有預先定義,聚類有時也被稱爲無監督學習( unsupervised classification )。
===========================================================================================
10.1 K-均值聚類算法
優點:容易實現。
缺點:可能收斂到局部最小值,在大規模數據集上收斂較慢。
適用數據類型:數值型數據。
k-均值僞代碼:
創建 k 個點作爲起始質心(經常是隨機選擇)
當任意一個點的簇分類結果發生改變時
對數據集中的每一個數據點
對每個質心
計算質心與數據點之間的距離
將數據點分配到距其最近的簇
對每一個簇,計算簇中所有點的均值並將均值作爲質心
# -*- coding:utf-8 -*- # kMeans.py from numpy import * # 將文本文件導入到一個列表中 def loadDataSet(fileName): dataMat = [] fr = open(fileName) for line in fr.readlines(): curLine = line.strip().split('\t') # 以 tab 分割浮點數 fltLine = map(float, curLine) dataMat.append(fltLine) # append() 方法用於在列表末尾添加新的對象,這裏是 dataMat return dataMat def distEclud(vecA, vecB): # 歐拉距離 return sqrt(sum(power(vecA - vecB, 2))) # 給定數據集構建一個包含 K 個隨機質心的集合 def randCent(dataSet, k): n = shape(dataSet)[1] centroids = mat(zeros((k, n))) # 調用 mat() 函數可以將數組轉化爲矩陣 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
# -*- coding:utf-8 -*-
# run_kMeans.py
import kMeans
from numpy import *
datMat = mat(kMeans.loadDataSet('testSet.txt')) # 從文本文件中構建矩陣
print min(datMat[:,0])
print min(datMat[:,1])
print max(datMat[:,1])
print max(datMat[:,0])
print kMeans.randCent(datMat, 2)# 給定數據集構建一個包含 2 個隨機質心的集合
print kMeans.distEclud(datMat[0], datMat[1])
然後運行結果:
運行了兩次,看得出來隨機數結果是不同的。
現在準備實現完整的 k-均值 算法。該算法創建 k 個質心,然後將每個點分配到最近的質心,再重新計算質心。這個過程重複多次,直到數據點的簇分配結果不再改變爲止。
在 kMeans.py 裏面輸入下面的代碼。
# 接受四個輸入參數,只有數據集和簇的數目是必選參數,用來計算距離和創建初始質心的函數都是可選的
def kMeans(dataSet, k, distMeas = distEclud, createCent = randCent):
m = shape(dataSet)[0]
clusterAssment = mat(zeros((m,2)))
centroids = createCent(dataSet, k)
clusterChanged = True
while clusterChanged:
clusterChanged = False
for i in range(m):
minDist = inf; minIndex = -1
for j in range(k): # 尋找最近的質心
distJI = distMeas(centroids[j,:], dataSet[i,:])
if distJI < minDist:
minDist = distJI; minIndex = j
if clusterAssment[i,0] != minIndex: clusterChanged = True # True 表示可以繼續迭代
clusterAssment[i,:] = minIndex,minDist ** 2
print centroids
for cent in range(k):
ptsInClust = dataSet[nonzero(clusterAssment[:,0].A == cent)[0]]
centroids[cent,:] = mean(ptsInClust, axis = 0)
return centroids, clusterAssment # 更新質心的位置
遍歷所有質心並且更新的具體步驟是:首先通過數組過濾來獲得給定簇的所有點;然後計算所有點的均值,選項 axis = 0 表示沿舉證的列方向進行均值計算;最後,程序返回所有的類質心與點分配結果。
運行裏面添加:
print'\n***************************************\n'
reload(kMeans)
datMat = mat(kMeans.loadDataSet('testSet.txt'))
print 'myCentroids, clustAssing = kMeans.kMeans(datMat, 4)'
myCentroids, clustAssing = kMeans.kMeans(datMat, 4)
print myCentroids, clustAssing
不知道爲什麼出來的是一長串結果,這裏就不貼了。