Python使用Numpy實現(xiàn)Kmeans算法的步驟詳解
Kmeans聚類算法介紹:
1.聚類概念:
將物理或抽象對象的集合分成由類似的對象組成的多個類的過程被稱為聚類。由聚類所生成的簇是一組數(shù)據(jù)對象的集合,這些對象與同一個簇中的對象彼此相似,與其他簇中的對象相異。
2.Kmeans算法:
定義:
kmeans算法又名k均值算法,K-means算法中的k表示的是聚類為k個簇,means代表取每一個聚類中數(shù)據(jù)值的均值作為該簇的中心,或者稱為質心,即用每一個的類的質心對該簇進行描述。
大概步驟:
- 設置初始類別中心和類別數(shù)
- 根據(jù)類別中心對全部數(shù)據(jù)進行類別劃分:每個點分到離自己距離最小的那個類
- 重新計算當前類別劃分下每個類的中心:例如可以取每個類別里所有的點的平均值作為新的中心。如何求多個點的平均值? 分別計算X坐標的平均值,y坐標的平均值,從而得到新的點。注意:類的中心可以不是真實的點,虛擬的點也不影響。
- 在新的類別中心下繼續(xù)進行類別劃分;
- 如果連續(xù)兩次的類別劃分結果不變則停止算法; 否則循環(huán)2~5。例如當類的中心不再變化時,跳出循環(huán)。
Kmeans距離測定方式:
歐式距離:
曼哈頓距離:
余弦相似度:
A與B表示向量(x1,y1),(x2,y2)
分子為A與B的點乘,分母為二者各自的L2相乘,即將所有維度值的平方相加后開方。
3.如何確定最佳的k值(類別數(shù)):
本文選取手肘法
手肘法:
對于每一個k值,計算它的誤差平方和(SSE):
其中N是點的個數(shù),Xi 是第i 個點,ci 是Xi 對應的中心。
- 隨著聚類數(shù)k的增大,樣本劃分會更加精細,每個簇的聚合程度會逐漸提高,那么誤差平方和SSE自然會逐漸變小。
- 當k小于真實聚類數(shù)時,由于k的增大會大幅增加每個簇的聚合程度,故SSE的下降幅度會很大,而當k到達真實聚類數(shù)時,再增加k所得到的聚合程度回報會迅速變小,所以SSE的下降幅度會驟減,然后隨著k值的繼續(xù)增大而趨于平緩,也就是說SSE和k的關系圖是一個手肘的形狀,而這個肘部對應的k值就是數(shù)據(jù)的真實聚類數(shù)
python實現(xiàn)Kmeans算法:
1.代碼如下:
import numpy as np import matplotlib.pyplot as plt import math k = eval(input("請輸入想要劃分的類別個數(shù)")) #規(guī)定類別數(shù) n = eval(input("請輸入要循環(huán)的次數(shù)"))#規(guī)定循環(huán)次數(shù) sw = eval(input("請輸入想要查詢的元素在數(shù)據(jù)中的位置")) def readdata():#獲取data數(shù)據(jù)中坐標值 data = np.loadtxt("E:\\Python\\Lab4\\Lab4.dat")#讀取dat數(shù)據(jù) x_data = data[:,0]#橫坐標 y_data = data[:,1]#縱坐標 return data,x_data,y_data def init(k):#初始化生成k個隨機類別中心 data,x_data,y_data = readdata() class_center = [] for i in range(k): #在數(shù)據(jù)的最大值與最小值間給出隨機值 x = np.random.randint(np.min(x_data),np.max(x_data)) y = np.random.randint(np.min(y_data),np.max(y_data)) class_center.append(np.array([x,y]))#以數(shù)組方式添加,方便后面計算距離 return class_center def dist(a,b):#計算兩個坐標間的歐氏距離 dist = math.sqrt(math.pow((a[0] - b[0]),2) + math.pow((a[1] - b[1]),2)) return dist def dist_rank(center,data):#得到與類中心最小距離的類別位置索引 tem = [] for m in range(k): d = dist(data, center[m]) tem.append(d) loc = tem.index(min(tem)) return loc def means(arr):#計算類的平均值當作類的新中心 sum_x,sum_y =0,0 for n in arr: sum_x += n[0] sum_y += n[1] mean_x = sum_x / len(arr) mean_y = sum_y / len(arr) return [mean_x,mean_y] def divide(center,data):#將每一個二維坐標分到與之歐式距離最近的類里 cla_arr = [[]] for i in range(k-1):#創(chuàng)建與k值相同維度的空數(shù)組存取坐標 cla_arr.append([]) for j in range(len(data)): loc = dist_rank(center,data[j]) cla_arr[loc].append(list(data[j])) return cla_arr def new_center(cla):#計算每類平均值更新類中心 new_cen = [] for g in range(k): new = means(cla[g]) new_cen.append(new) return new_cen def index_element(arr,data,sw):#索引第sw個元素對應的類別 index = [] for i in range(len(data)):#遍歷每一個數(shù)據(jù) for j in range(k):#遍歷每一個類別 tem = arr[j] for d in range(len(tem)):#遍歷類別內的每一個數(shù)據(jù) if data[i][0] == tem[d][0] and data[i][1] == tem[d][1]:#如果橫縱坐標數(shù)值都相等 index.append((j + 1))#歸為j+1類 else: continue return index[sw] def Kmeans(n,sw):#獲取n次更新后類別中心以及第sw個元素對應的類別 data, x_data, y_data = readdata()#讀取數(shù)據(jù) center = init(k) # 獲取初始類別中心 while n > 0: cla_arr = divide(center,data)# 將數(shù)據(jù)分到隨機選取的類中心的里 center = new_center(cla_arr)#更新類別中心 n -= 1 sse1 = 0 for j in range(k): for i in range(len(cla_arr[j])): # 計算每個類里的誤差平方 # 計算每個類里每個元素與元素中心的誤差平方 dist1 = math.pow(dist(cla_arr[j][i], center[j]), 2) sse1 += dist1 sse1 = sse1 / len(data) index = index_element(cla_arr,data,sw) return center,index,sse1,cla_arr center_l, index,sse1, cla_arr = Kmeans(n,sw) print("類別中心為:",center_l) print("所查元素屬于類別:",index) print('k值為{0}時的誤差平方和為{1}'.format(k,sse1))#format格式化占位輸出誤差平方和 def visualization(cla):#聚類可視化展現(xiàn) cla_x = [[]] cla_y = [[]] for m in range(k-1):#創(chuàng)建與k值相同維度的空數(shù)組存取x坐標和y坐標 cla_x.append([]) cla_y.append([]) for i in range(k):#遍歷k次讀取k個類別 for j in cla[i]:#遍歷每一類存取橫縱坐標 cla_x[i].append(j[0]) cla_y[i].append(j[1]) plt.rcParams['axes.unicode_minus'] = False plt.rcParams['font.sans-serif']=['SimHei']#解決中文不能顯示的問題 plt.figure() plt.xlabel("x") plt.ylabel("y") plt.title("聚類圖") plt.scatter(cla_x[0],cla_y[0],c = 'r',marker = 'h') plt.scatter(cla_x[1], cla_y[1], c='y', marker='.') plt.scatter(cla_x[2], cla_y[2], c='g', marker='o') plt.scatter(cla_x[3], cla_y[3], c='b', marker=',') plt.scatter(cla_x[4], cla_y[4], c='k', marker='p') plt.show() visualization(cla_arr) def hand():#畫出手肘圖 #sse列表是循環(huán)次數(shù)為3,改變k從2到8一個一個人工測得存入 sse = [17.840272113687078,12.116153021227769,8.563862232332205,4.092534331364449,3.573312882789776,3.42794767600246,3.2880646083752185] x = np.linspace(2,8,7)#創(chuàng)建等間距大小為7的數(shù)組 plt.xlabel("k值")#橫坐標名稱 plt.ylabel("誤差平方和")#縱坐標名稱 plt.title("手肘圖")#曲線名 plt.plot(x,sse)#畫出曲線 plt.show() hand()
2.代碼結果展示:
聚類可視化圖:
手肘圖:
運行結果:
文章參考:
手肘法:K-means聚類最優(yōu)k值的選取_qq_15738501的博客-CSDN博客_kmeans聚類k的選取
matplotpb.pyplot.scatter散點圖的畫法:
PYthon——plt.scatter各參數(shù)詳解_yuanCruise-CSDN博客_plt.scatter
到此這篇關于Python使用Numpy實現(xiàn)Kmeans算法的文章就介紹到這了,更多相關Python Kmeans算法內容請搜索本站以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持本站!
版權聲明:本站文章來源標注為YINGSOO的內容版權均為本站所有,歡迎引用、轉載,請保持原文完整并注明來源及原文鏈接。禁止復制或仿造本網站,禁止在非www.sddonglingsh.com所屬的服務器上建立鏡像,否則將依法追究法律責任。本站部分內容來源于網友推薦、互聯(lián)網收集整理而來,僅供學習參考,不代表本站立場,如有內容涉嫌侵權,請聯(lián)系alex-e#qq.com處理。