一 Kmeans原理
kmeans是屬於無監督學習的數據聚類算法,根據點與點之間的距離推測每個點屬於哪個中心,常用計算距離的方式有:餘弦距離、歐式距離、曼哈頓距離等,本文以歐式距離為例。圖1假設每個點的維度是n,即每個點有n個特徵維度,計算這些點數據到數據中心A、B、C的距離,從而將每個數據歸類到A或B或C。
歐式距離公式:
假設1點的數據為:
A中心數據為:
歐式公式計算為:
kmeans實現邏輯:
需要輸入待聚類的數據和欲聚類簇數k
1.隨機生成k個初始點作為質心
2.將數據集中的數據按照距離質心的遠近分到各個簇中
3.對每個簇的數據求平均值,作為新的質心,重複上一步,直到所有的簇不再改變
k是聚類個數,可以根據我們的經驗給數值,也可以通過程序初步預測k設置為多少對聚類最準確。本章通過變化k的個數,計算k取不同值時,最後的誤差多少,誤差越小,則k最準確。
二 數據準備
對數據進行聚類,要對測試數據進行清洗。一般代碼都是對數值型數據進行計算,所以如果測試數據是漢字或其他類型的信息,我們要對其進行量化。本案例通過鏈家數據進行測試,通過學習,可以學習python機器學習的一般步驟和整個過程。圖4是初始數據,其中面積特徵、格局特徵、裝修特徵都需要量化成數值型,大家可以根據實際情況進行量化。比如精裝對應80,簡裝對應30,毛坯對應10等,本文對這些數值進行如下量化,同時將面積的單位平米去掉,最終訓練數據見圖5.
簡裝:0 精裝:1 毛坯:3
東:0 西:1 南:2 北:3
三 程序
1、對初始k進行預測
# 歐氏距離計算
def distEclud(x,y):
return np.sqrt(np.sum((x-y)**2)) # 計算歐氏距離
# 為給定數據集構建一個包含K個隨機質心的集合
def randCent(dataSet,k):
m,n = dataSet.shape
centroids = np.zeros((k,n))
for i in range(k):
index = int(np.random.uniform(0,m))
centroids[i,:] = dataSet[index,:]
return centroids
def cost(dataMat, k, distMeas=distEclud, createCent=randCent,iterNum=300):
# 獲取樣本數和特徵數
m, n = np.shape(dataMat)
# 初始化一個矩陣來存儲每個點的簇分配結果
# clusterAssment包含兩個列:一列記錄簇索引值,第二列存儲誤差(誤差是指當前點到簇質心的距離,後面會使用該誤差來評價聚類的效果)
clusterAssment = np.mat(np.zeros((m, 2)))
# 創建質心,隨機K個質心
centroids = createCent(dataMat, k)
clusterChanged = True
while iterNum > 0:
clusterChanged = False
# 遍歷所有數據找到距離每個點最近的質心,
# 可以通過對每個點遍歷所有質心並計算點到每個質心的距離來完成
for i in range(m):
minDist = np.inf
minIndex = -1
for j in range(k):
# 計算數據點到質心的距離
distJI = distMeas(centroids[j, :], dataMat[i, :])
# 如果距離比minDist(最小距離)還小,更新minDist(最小距離)和最小質心的index(索引)
if distJI < minDist:
minDist = distJI
minIndex = j
# 更新簇分配結果為最小質心的index(索引),minDist(最小距離)的平方
clusterAssment[i, :] = minIndex, minDist ** 2
iterNum -= 1;
# print(centroids)
# 遍歷所有質心並更新它們的取值
for cent in range(k):
# 通過數據過濾來獲得給定簇的所有點
ptsInClust = dataMat[np.nonzero(clusterAssment[:, 0].A == cent)[0]]
# 計算所有點的均值,axis=0表示沿矩陣的列方向進行均值計算
centroids[cent, :] = np.mean(ptsInClust, axis=0)
# 返回給定迭代次數後誤差的值
return np.mat(clusterAssment[:,1].sum(0))[0,0]
調用上述方法預測k,見圖6,所以k可以取值:2、3、5等,可以結合實際需要進行選取。本文數據可能比較不典型,正常情況下,曲線應該是單一方向的上升或下降趨勢,我們取轉折點作為k的值。
dataSet = loadDataSet("test.txt")
allcost=[]
x=[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18]
k=1
while k <19:
a=cost(dataSet, 2, distMeas=distEclud, createCent=randCent,iterNum=300)
allcost.append(a)
k = k+1
2 kmean算法程序
3、繪製數據點
本文數據不是二維數據,而是5維數據,我們需要安裝plotly來實現多維數據的繪製,從繪製的數據點我們可以形象的看出數據都聚集在2大塊,所以聚類K應該取2比較合適。
x:面積,y:朝向,z:總價,實現三維圖形,格局特徵我們通過點大小描繪,裝修特徵我們通過點顏色標誌,通過如此,5維數據都可以在圖上展示出來了。
import pandas as pd
import plotly
import plotly.graph_objs as go
dataPath = 'C:/Users/xzx/Desktop/linkHomeData.xlsx'
data = pd.read_excel(dataPath,sheet_name='Sheet2')
#Set marker properties
markersize = data['geju']/3
markercolor = data['zhuangxiu']
#Make Plotly figure
fig1 = go.Scatter3d(x=data['mianji'],
y=data['chaoxiang'],
z=data['price'],
marker=dict(size=markersize,
color=markercolor,
opacity=0.9,
reversescale=True,
colorscale='Blues'),
line=dict (width=0.02),
mode='markers')
#Make Plot.ly Layout
mylayout = go.Layout(scene=dict(xaxis=dict( title="面積"),
yaxis=dict( title="朝向"),
zaxis=dict(title="總價")),)
#Plot and save html
plotly.offline.plot({"data": [fig1],
"layout": mylayout},
auto_open=True,
filename=("5D Plot.html"))
四 總結
本文講述了kmeans算法的原理,聚類中心K個數的選取,kmeans算法的一般步驟,以及如何繪製多維圖形。