機器學習-kmeans
KMeans(K均值)是典型的基於距離的排他划分方法:給定一個n個對象的數據集,它可以構建數據的k個划分,每個划分就是一個聚類,並且k<=n,同時還滿足兩個要求:
1.每個組至少包含一個對象
2.每個對象必須屬於且僅屬於一個組
優點:
擅長處理球狀分布的數據,當結果聚類是密集的,而且類和類之間的區別比較明顯時,K均值的效果比較好
對於處理大數據及,這個算法是相對可伸縮的和高效的,它的復雜度是O(nkt),n是對象的個數,k是簇的數目,t是迭代的次數。
缺點:
算法的初始中心點選擇與算法的運行效率密切相關,而隨機選取中心點有可能導致迭代次數很大或者限於某個局部最優狀態;通常k<<n,且t<<n,所以算法經常以局部最優收斂
K均值的最大問題是要求用戶必須事先給出k的個數,k的選擇一般都基於經驗值和多次實驗的結果,對於不同的數據集,k的取值沒有可借鑒性。
對異常偏離的數據敏感--離群點;K均值對噪聲和孤立點數據是敏感的,少量的這類數據就能對平均值造成極大的影響。
步驟:
1.首先創建一個初始化分,隨機的選擇k個對象,每個對象初始的代表一個聚類中心。對於其他對象,根據其與各個聚類中心的距離,將它們賦給最近的聚類。
遞歸重定位,嘗試通過對象在划分間移動來改進划分。重定位即:當有新的對象加入聚類或者已有對象離開聚類的時候,重新計算聚類的平均值,然后對對象進行重新分配。這個過程不斷重復,直到聚類中的數據不再變化為止。
sklearn代碼如下
from numpy import * from sklearn.cluster import KMeans import matplotlib.pyplot as plt def file2matrix(filePath, lineSplit): dataSet = [] fr = open(filePath, 'r') content = fr.read() for line in content.splitlines(): dataSet.append([line.split('\t')[0], line.split('\t')[1]]) fr.close() return dataSet def drawScatter(plt, dataMat, size, color, mrkr): X = dataMat[:,0] Y = dataMat[:,-1] plt.scatter(X.tolist(), Y.tolist(), c=color, marker=mrkr, s=size) plt.xlabel("x") plt.ylabel("y") plt.title("Kmeans") plt.legend() k = 4 dataSet = file2matrix("/Users/FengZhen/Desktop/accumulate/機器學習/推薦系統/kmeans聚類測試集.txt", "\t") dataMat = mat(dataSet) print(dataMat) # 執行kmeans算法 kmeans = KMeans(init='k-means++', n_clusters=k) kmeans.fit(dataMat) print(kmeans.cluster_centers_) #繪制計算結果 drawScatter(plt, dataMat, size=20, color='b', mrkr='.') drawScatter(plt, kmeans.cluster_centers_, size=20, color='red', mrkr='D') plt.show()
python自實現
import matplotlib.pyplot as plt
from numpy import *
import numpy as np
# 數據文件轉矩陣
def file2matrix(filePath):
dataSet = []
fr = open(filePath, 'r')
content = fr.read()
for line in content.splitlines():
dataSet.append([line.split('\t')[0], line.split('\t')[1]])
fr.close()
return dataSet
# 根據聚類中心繪制散點圖,以及繪制聚類中心
def color_cluster(dataindx, dataSet, plt, k=4):
# print(dataindx)
plt.scatter(dataSet[:, 0].tolist(), dataSet[:, 1].tolist(), c='blue', marker='o')
# index = 0
# datalen = len(dataindx)
# for indx in range(datalen):
# if int(dataindx[index]) == 0:
# plt.scatter(dataSet[index, 0].tolist(),dataSet[index, 1].tolist(), c='blue', marker='o')
# elif int(dataindx[index]) == 1:
# plt.scatter(dataSet[index, 0].tolist(), dataSet[index, 1].tolist(), c='green', marker='o')
# elif int(dataindx[index]) == 2:
# plt.scatter(dataSet[index, 0].tolist(), dataSet[index, 1].tolist(), c='red', marker='o')
# elif int(dataindx[index]) == 3:
# plt.scatter(dataSet[index, 0].tolist(), dataSet[index, 1].tolist(), c='cyan', marker='o')
# index += 1
# 繪制散點圖
def drawScatter(plt, mydata, size=20, color='blue', mrkr='o'):
# print(mydata.T[0][0].tolist())
# print(mydata.T[1][0].tolist())
plt.scatter(mydata.T[0][0].tolist(), mydata.T[1][0].tolist(), s=size, c=color, marker=mrkr)
# 歐氏距離公式
def distEclud(vecA, vecB):
return linalg.norm(vecA.astype(float) - vecB.astype(float))
# 隨機生成聚類中心
def randCenters(dataSet, k):
n = shape(dataSet)[1] # 列數
clustercents = mat(zeros((k, n))) # 初始化聚類中心矩陣:k*n
for col in range(n):
mincol = min(dataSet[:, col]).astype(float); maxcol = max(dataSet[:, col]).astype(float)
# random.rand(k,1)):產生一個0-1之間的隨機數向量:k,1表示產生k行1列的隨機數
clustercents[:, col] = mat(mincol + float(maxcol - mincol) * random.rand(k, 1))
return clustercents
def kMeans(dataSet, k):
m = dataSet.shape[0]
ClustDist = mat(zeros((m, 2)))
clustercents = randCenters(dataSet, k) # 隨機生成聚類中心
flag = True # 迭代標記
counter = [] # 初始化計數器
while flag:
flag = False # 默認設置退出標志
# 算法停止條件:ClustDist[i, 0] == minIndex
for i in range(m):
# 遍歷k個聚類中心,獲取最短距離
distlist = [distEclud(clustercents[j, :], dataSet[i, :]) for j in range(k)]
minDist = min(distlist) # 獲取最小距離
minIndex = distlist.index(minDist) # 獲取最小距離所屬的簇
if ClustDist[i, 0] != minIndex: # 找到了一個新聚類中心
flag = True # 重置標志位為True,繼續迭代
# 更新聚類中心
ClustDist[i, :] = minIndex, minDist
for cent in range(k):
# 從ClustDist的第一列中篩選出等於cent值的行下標
ptsInClust = dataSet[nonzero(ClustDist[:, 0].A == cent)[0]]
# 計算ptsInClust各列的均值
clustercents[cent, :] = mean(ptsInClust.astype(float), axis=0)
return clustercents, ClustDist
dataMat = file2matrix("/Users/FengZhen/Desktop/accumulate/機器學習/推薦系統/kmeans聚類測試集.txt") # 從文件構建的數據集
dataSet = mat(dataMat) # 轉換為矩陣形式
k = 4 # 外部指定的聚類中心
clustercents,ClustDist = kMeans(dataSet, k)
# print("clustercents:\n", clustercents)
# color_cluster(ClustDist[:, 0:1], dataSet, plt)
# drawScatter(plt, clustercents, size=20, color='red', mrkr='D')
# plt.show()