k-Means是一種無監督的聚類算法,實現起來比較簡單,聚類效果也不錯,因此被廣泛應用。
原理
物以類聚,人以羣分。
無監督 聚類。
簡單地說,就是把相似的物體聚到一個簇。同一簇內相似度儘可能大,不同簇間相似度儘可能低。採用距離度量相似程度。
算法
1、初始化k箇中心點,有了k個簇
2、對所有樣本,計算每個樣本與k箇中心點的距離,將各樣本劃分到距離最近的中心點所在的簇
3、重新計算各簇的中心:爲各簇所有點的均值
4、不斷迭代2、3,直到各簇不再發生變化或者達到迭代次數
優缺點
優點:
是解決聚類問題的一種經典算法,簡單、快速;
對處理大數據集,該算法高效率;
當結果是密集的,它的效果較好。
缺點:
k值選取不好把握;
對初值敏感(初始聚類中心的選擇:改進1:k-means++,改進2:二分k-means);
對噪聲和異常點敏感(改進:離羣點檢測,去掉離羣點後再聚類,減少它們對聚類效果的影響);
只能收斂到局部最小,不適合於發現非凸形狀的簇還有,不能處理大小、密度差別很大的簇(改進:基於密度的聚類:擅於解決不規則形狀的聚類問題,能克服基於距離的算法只能發現“類圓形”的聚類的缺點。如,DBSCAN算法)
實現
import numpy as np
#文件解析,將值封裝到矩陣(實質是list裏每個元素list)裏
#dataset文件每行數字以製表符分
def loadDataset(filename):
data = []
f = open(filename)
for line in f:
line = line.strip().split('\t')
floatline = map(float, line)
data.append(floatline)
return data
#歐式距離公式
def distance(vecA, vecB):
return np.sqrt(np.sum(np.square(vecA - vecB)))
#構建質心
#隨機選擇k個樣本點做質心
def randCenter(dataMat, k):
row, col = dataMat.shape
centers = []
centersIndex = np.random.randint(0, row, size=k)
for i in centersIndex:
centers.append(dataMat[i])
centers = np.mat(centers)
return centers
#輸入:樣本點集合(矩陣形式,m個樣本),聚類簇數k
# 算法:
# 隨機選擇k個樣本作爲初始質心:{u1,u2,..uk},即均值向量集合
# 1、對每一個點:
# 計算它與每一個簇的質心的距離;
# 找出最小距離;
# 劃分到最小距離所在簇
# (所有點都被劃分了一遍)
# 2、對每一個簇:
# 重新計算質心(均值向量)
# 如果質心改變了,則更新質心;否則,不用更新
# 直到當前的所有簇的質心均未改變,算法結束【換個思路:即是如果一有改變就繼續循環1、2】
# 返回:質心、簇劃分
def kmeans(dataMat, k):
m = dataMat.shape[0] #也就是row,m個樣本點
centers= randCenter(dataMat, k)
#簇劃分 初始時爲:{0:u1, 1:u2,..., k:uk}
clusters = {}
for cent in range(k):
clusters[cent]= centers[cent]
clusterChanged = True
while clusterChanged:
clusterChanged= False
for i in range(m):
minDist= distance(dataMat[i], centers[0])
minIndex= 0
for j in range(k):
distIJ= distance(dataMat[i], centers[j])
if distIJ< minDist:
minDist= distIJ
minIndex= j
#將樣本點劃分到最近簇
clusters[minIndex]= np.row_stack((clusters[minIndex], dataMat[i])) #minIndex鍵下的值——矩陣增一行
#一輪劃分完後(即所有樣本劃分一遍後),計算質心
for cent in range(k):
newCenter= np.mat([clusters[cent][:,0].mean(), clusters[cent][:,1].mean()])
if newCenter[cent, 0]!= centers[cent, 0] or newCenter[cent, 1]!= centers[cent, 1]:
clusterChanged= True
#更新質心
centers[cent]= newCenter
return centers, clusters