一,k均值算法
(一)自己寫程序
舉例,在excel中有四個點的座標如下,表示樣本集 (分別對應下圖中的最左邊標籤對應的數,)
現在將這四個點畫出來
import numpy as np
import xlrd
import matplotlib.pyplot as plt
workbook = xlrd.open_workbook('C:/users/Lenovo/Desktop/test.xlsx')
sheet = workbook.sheet_by_name('Sheet1')
dot_x = sheet.col_values(0)
dot_y = sheet.col_values(1)
plt.scatter(dot_x,dot_y)
plt.show()
隨機選擇兩個樣本作爲初始均值向量,(機器學習西瓜書中隨機選樣本集中的數,而此處是隨機生成範圍內的數,未必是樣本集中存在的):
在上面得到了點的橫縱座標之後(即dot_x,dot_y),現在組合成數據集(注意dot_x,dot_y)都是行矢量,所以組成矩陣數據集後要轉置
dot_x = sheet.col_values(0)
dot_y = sheet.col_values(1)
dataSet = np.mat([dot_x,dot_y]).T
現在開始隨機生成聚類中心
def randcenters(dataSet,k): #輸入數據集和k
n = np.shape(dataSet)[1] #查看k有多少列,實際上就是點的座標的維度,比如兩維x,y
centroids = np.matrix(np.zeros((k,n))) #zeros得到的是數組,一定要變成矩陣,否則centroids[:,0]並不表示第一列
for J in range(n):
rangeJ = float(max(dataSet[:,J])-min(dataSet[:,J])) #求出範圍,注意 A
centroids[:,J] = min(dataSet[:,J]) + rangeJ*np.random.rand(k,1) #生成聚類中心
return centroids
上面中注意“A”部分:rangeJ=float…, 此處float一定不能少,因爲max(dataSet[:,J])還是矩陣,是矩陣。
經過float之後變成浮點數。
測試一下
test = randcenters(dataSet,2)
所以這裏得到的兩個質心就是初始均值向量,即
現在計算上面的數據集到質心的距離(歐氏距離)
def distEclud(vecA,vecB): #輸入的是數組,不能用list形式
return np.sqrt(sum(np.power(vecA-vecB,2)))
開始着手聚類算法:
def kMeans(dataSet,k): #不妨以k=2舉例
m = np.shape(dataSet)[0] #顯示數據集的個數,即有多少個數據需要處理
ClustDist = np.mat(np.zeros((m,2))) #聚類最小距離的索引值和此距離。第一列放索引值,第二列放最小距離
clustercents = randcenters(dataSet,k) #調用生成隨機聚類
clusterChanged = True
while clusterChanged: #用while進行迭代
clusterChanged = False # 設置初始爲False
# 計算每個數據與隨機初始得到的質心的距離,比如假設只有兩個質心,即k=2,那麼找到每個數據分別到這兩個
# 點的距離,並保留距離小的那個。比如x1到質心Cent1和質心Cent2的距離分別爲l1和l2,且l1<l2.那麼
# 就保留l1並記下l1的位置(索引)
for i in range(m):
distlist = [distEclud(clustercents[j,:],dataSet[i,:]) for j in range(k)] #計算每個數據與隨機質心間的距離
minDist = min(distlist) #找到最小距離
minIndex = distlist.index(minDist) #最小距離對應的索引值
if ClustDist[i,0] != minIndex: #找到了一個新的聚類中心,因爲是for i in...循環,只要數據集中有一個新中心就變True
clusterChanged = True
ClustDist[i,:] = minIndex,minDist #放置找到的新的最小距離
for cent in range(k): #假設k=2,即兩個聚類中心
dInx = np.nonzero(ClustDist[:,0].A == cent)[0]
ptsInClust = dataSet[dInx] #選擇數據中的數
clustercents[cent,:] = np.mean(ptsInClust,axis=0)
return clustercents, ClustDist
完整代碼如下:
def randcenters(dataSet,k): #輸入數據集和k
n = np.shape(dataSet)[1] #查看k有多少列,實際上就是點的座標的維度,比如兩維x,y
centroids = np.matrix(np.zeros((k,n))) #zeros得到的是數組,一定要變成矩陣,否則centroids[:,0]並不表示第一列
for J in range(n):
rangeJ = float(max(dataSet[:,J])-min(dataSet[:,J])) #求出範圍,注意 A
centroids[:,J] = min(dataSet[:,J]) + rangeJ*np.random.rand(k,1) #生成聚類中心
return centroids
def distEclud(vecA,vecB):
return np.sqrt(sum(np.power(vecA-vecB,2)))
def kMeans(dataSet,k): #不妨以k=2舉例
m = np.shape(dataSet)[0] #顯示數據集的個數,即有多少個數據需要處理
ClustDist = np.mat(np.zeros((m,2))) #聚類最小距離的索引值和此距離。第一列放索引值,第二列放最小距離
clustercents = randcenters(dataSet,k) #調用生成隨機聚類
clusterChanged = True
while clusterChanged: #用while進行迭代
clusterChanged = False # 設置初始爲False
# 計算每個數據與隨機初始得到的質心的距離,比如假設只有兩個質心,即k=2,那麼找到每個數據分別到這兩個
# 點的距離,並保留距離小的那個。比如x1到質心Cent1和質心Cent2的距離分別爲l1和l2,且l1<l2.那麼
# 就保留l1並記下l1的位置(索引)
for i in range(m):
distlist = [distEclud(clustercents[j,:],dataSet[i,:]) for j in range(k)] #計算每個數據與隨機質心間的距離
minDist = min(distlist) #找到最小距離
minIndex = distlist.index(minDist) #最小距離對應的索引值
if ClustDist[i,0] != minIndex: #找到了一個新的聚類中心,因爲是for i in...循環,只要數據集中有一個新中心就變True
clusterChanged = True
ClustDist[i,:] = minIndex,minDist #放置找到的新的最小距離
for cent in range(k): #假設k=2,即兩個聚類中心
dInx = np.nonzero(ClustDist[:,0].A == cent)[0]
ptsInClust = dataSet[dInx] #選擇數據中的數
clustercents[cent,:] = np.mean(ptsInClust,axis=0)
return clustercents, ClustDist
workbook = xlrd.open_workbook('C:/users/Lenovo/Desktop/test.xlsx')
sheet = workbook.sheet_by_name('Sheet1')
dot_x = sheet.col_values(0)
dot_y = sheet.col_values(1)
dataSet = np.mat([dot_x,dot_y]).T
k = 2
clustercents,ClustDist = kMeans(dataSet,k)
print(clustercents)
結果是新的聚類中心,即
最後輸出聚類結果圖片
圖片分析部分不做進一步講解,完整代碼如下
#from numpy import *
import numpy as np
import xlrd
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
#隨機生成聚類中心
def randcenters(dataSet,k): #輸入數據集和k
n = np.shape(dataSet)[1] #查看k有多少列,實際上就是點的座標的維度,比如兩維x,y
centroids = np.matrix(np.zeros((k,n))) #zeros得到的是數組,一定要變成矩陣,否則centroids[:,0]並不表示第一列
for J in range(n):
rangeJ = float(max(dataSet[:,J])-min(dataSet[:,J])) #求出範圍,注意 A
centroids[:,J] = min(dataSet[:,J]) + rangeJ*np.random.rand(k,1) #生成聚類中心
return centroids
def distEclud(vecA,vecB):
return np.sqrt(sum(np.power(vecA-vecB,2)))
def kMeans(dataSet,k): #不妨以k=2舉例
m = np.shape(dataSet)[0] #顯示數據集的個數,即有多少個數據需要處理
ClustDist = np.mat(np.zeros((m,2))) #聚類最小距離的索引值和此距離。第一列放索引值,第二列放最小距離
clustercents = randcenters(dataSet,k) #調用生成隨機聚類
clusterChanged = True
while clusterChanged: #用while進行迭代
clusterChanged = False # 設置初始爲False
# 計算每個數據與隨機初始得到的質心的距離,比如假設只有兩個質心,即k=2,那麼找到每個數據分別到這兩個
# 點的距離,並保留距離小的那個。比如x1到質心Cent1和質心Cent2的距離分別爲l1和l2,且l1<l2.那麼
# 就保留l1並記下l1的位置(索引)
for i in range(m):
distlist = [distEclud(clustercents[j,:],dataSet[i,:]) for j in range(k)] #計算每個數據與隨機質心間的距離
minDist = min(distlist) #找到最小距離
minIndex = distlist.index(minDist) #最小距離對應的索引值
if ClustDist[i,0] != minIndex: #找到了一個新的聚類中心,因爲是for i in...循環,只要數據集中有一個新中心就變True
clusterChanged = True
ClustDist[i,:] = minIndex,minDist #放置找到的新的最小距離
for cent in range(k): #假設k=2,即兩個聚類中心
dInx = np.nonzero(ClustDist[:,0].A == cent)[0]
ptsInClust = dataSet[dInx] #選擇數據中的數
clustercents[cent,:] = np.mean(ptsInClust,axis=0)
return clustercents, ClustDist
def color_cluster(dataindx, dataSet, plt):
datalen = len(dataindx)
for indx in range(datalen):
if int(dataindx[indx]) == 0:
plt.scatter(dataSet[indx, 0], dataSet[indx, 1], c='blue', marker='o')
elif int(dataindx[indx]) == 1:
plt.scatter(dataSet[indx, 0], dataSet[indx, 1], c='green', marker='o')
elif int(dataindx[indx]) == 2:
plt.scatter(dataSet[indx, 0], dataSet[indx, 1], c='red', marker='o')
elif int(dataindx[indx]) == 3:
plt.scatter(dataSet[indx, 0], dataSet[indx, 1], c='cyan', marker='o')
def drawScatter(plt, mydata, size=20, color='blue', mrkr='o'):
plt.scatter(mydata.T[0].tolist(), mydata.T[1].tolist(), s=size, c=color, marker=mrkr)
workbook = xlrd.open_workbook('C:/users/Lenovo/Desktop/test.xlsx')
sheet = workbook.sheet_by_name('Sheet1')
dot_x = sheet.col_values(0)
dot_y = sheet.col_values(1)
dataSet = np.mat([dot_x,dot_y]).T
k = 2
clustercents,ClustDist = kMeans(dataSet,k)
print(clustercents)
color_cluster(ClustDist[:, 0:1], dataSet, plt)
drawScatter(plt,clustercents,color='red',mrkr='D')
聚類中心
聚類結果
(二)調用現有庫
使用sklearn
關於sklearn庫可以參考這篇文章:https://blog.csdn.net/u014248127/article/details/78885180,
作者寫得很詳細
也可以初步掃一下這個:https://blog.csdn.net/Mr_Cat123/article/details/84594032
import numpy as np
import xlrd
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
workbook = xlrd.open_workbook('C:/users/Lenovo/Desktop/test.xlsx')
sheet = workbook.sheet_by_name('Sheet1')
data_x = sheet.col_values(0)
data_y = sheet.col_values(1)
dataSet = np.mat([data_x,data_y]).T
dataSet_arr = np.array(dataSet)
print(dataSet_arr)
model = KMeans(n_clusters=2) #n_cluster即上面的k值,表示有多少個類
y_pred = model.fit_predict(dataSet_arr)
plt.scatter(dataSet_arr[:,0],dataSet_arr[:,1],c=y_pred)
plt.show()
這裏輸出的y_pred爲下圖
表示0,1是一類,2,3是一類。
結果如下
參考文獻
1,https://www.cnblogs.com/eczhou/p/7860424.html
2,機器學習實踐第十章
3,https://blog.csdn.net/u014248127/article/details/78885180