機器學習——python視覺化實現KNN演算法

簡介

這裡通過python的繪圖工具Matplotlib包視覺化實現機器學習中的KNN演算法。
需要提前安裝python的Numpy和Matplotlib包。
KNN–最近鄰分類演算法,演算法邏輯比較簡單,思路如下:

  1. 設一待分類資料iData,先計算其到已標記資料集中每個資料的距離,例如尤拉距離sqrt((x1-x2)^2 (y1-y2)^2);

  2. 然後根據離iData最近的k個資料的分類,出現次數最多的類別定為iData的分類。

KNN——最近鄰演算法python程式碼

程式碼實現:

import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
def KNNClassify(labelData,predData,k):  #資料集包含分類屬性
#labelData 是已經標記分類的資料集
#predData 未分類的待預測資料集
labShape = labelData.shape
for i in range(predData.shape[0]): #以predData的每行資料進行遍歷
iData = predData[i]
iDset = np.tile(iData,(labShape[0],1))   #將iData重複,擴充套件成與labelData同形的矩陣
#這裡用尤拉距離sqrt((x1-x2)^2 (y1-y2)^2)
diff = iDset[...,:-1] - labelData[...,:-1]
diff = diff**2
distance = np.sum(diff,axis=1)
distance = distance ** 0.5  #開根號
sortedIND = np.argsort(distance)   #排序,以序號返回。
classCount = { }
for j in range(k):  #計算距離最近的前k個標記資料的類別
voteLabel = labelData[sortedIND[j],-1]
classCount[voteLabel] = classCount.get(voteLabel,0) 1
maxcls = max(classCount,key=classCount.get)   #類別最多的,返回鍵名(類別名)
predData[i][...,-1] =  maxcls
return predData

為了測試這個演算法,需要現成的已分類資料集,由於手動輸入很有限,資料量少,耗時。作為學習我們這裡用程式碼模擬生成資料來進行測試。下面是生成已分類資料集的程式碼:

生成模擬資料的函式

import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
#模擬生成分類資料
#目標是產生二維座標中的幾堆資料集,每堆為一個類
#函式邏輯:
#將x軸分段,每個段設一箇中心的,所有的中心點用cores儲存。
#設定每個資料中心點core的類別,由中心點在一定範圍內隨機產生資料,並將這些資料設為和core一樣的類別
#所以每類的資料會簡單的被X軸的每段大致分開
def makeKNNData(colnum,clsnum,nums,cores = []):
#colnum單個資料擁有特徵數量(包括資料的分類);
# clsnum表示共有多少種分類;
# nums是一個元組,表示每個類別希望產生多少資料樣本,如colnum為5,nums為[56, 69, 60, 92, 95];
#cores非必要引數,手動給出只是用於測試,cores提供每類的中心點,以中心點為依據產生該類資料。
dataSet = np.zeros((sum(nums),colnum))   #初始化資料集,用於存放隨後生成的所有資料
n=0   #記錄生成資料的下標
step = 20/clsnum      #假定X座標軸只顯示0~20的範圍,step為X軸分段後的段長
for j in range(clsnum):     #迴圈生成各個類資料
try:
core = cores[j]      #如果cores沒有給出則,則出錯,跳至except執行
except IndexError :
core = np.random.rand(1,3)      #中心點為array([[x1,x2,c]]),c用於表示類別,這裡產生的是1*3的二維陣列
core[0][0] =j*step   core[0][0]*step  #將x1限制在各段中
core[0][1] *=15       #將x2即y軸限制在0~15範圍內
core[0][2] = j    #設定類別
cores.append(core)
for i in range(nums[j]):   #按nums中指定了每類資料的數量,用迴圈生成。
point= core[0][:2]   np.random.rand(1,2)*step -step/2   #產生點point(x,y),x以中心點在(core_x - step/2, core_x   step/2)範圍隨機波動,y同理。
row = np.column_stack((point,core[0][2]))   #加上類別成為一個資料
dataSet[n] = row
n  =1
i  =1
j  =1
#print("print cores:",cores)
return dataSet

有了資料集之後,我們可以用Matplotlib將資料視覺化,以直觀顯示出來

資料視覺化函式

import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
#繪圖展示資料,每類資料點以不同的顏色顯示
def showFigure(dataSet,clsnum):
fig = plt.figure()
ax = fig.add_subplot(1,1,1)   #介面只需顯示一個檢視
ax.set_title('KNN separable data set')  #檢視名稱,這裡簡單統一定這個名稱吧
plt.xlabel('X')    #座標軸名稱
plt.ylabel('Y')
colors = ['r','g','b','y','k']   #定義顯示的顏色b為blue,k為black
for i in range(clsnum):
idx = np.where(dataSet[:,2] == i)  #查詢每類的索引號
ax.scatter(dataSet[idx,0], dataSet[idx,1], marker='o', color=colors[i%5], label=1, s=10)  #在檢視中的顯示方式
plt.legend(loc = 'upper right')   #圖例顯示位置
plt.show()
#測試一下
#需要結合模擬生成資料的函式
classnum = 5
nums = np.random.randint(50,100,classnum)   #示例 array([56, 69, 60, 92, 95]),每個數字在50~100範圍內
dataSet = makeKNNData(3,classnum,nums)
showFigure(dataSet,classnum)

生成的模擬資料展示結果如下:

這裡寫圖片描述

完整程式碼

import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
#模擬生成分類資料
#目標是產生二維座標中的幾堆資料集,每堆為一個類
#函式邏輯:
#將x軸分段,每個段設一箇中心的,所有的中心點用cores儲存。
#設定每個資料中心點core的類別,由中心點在一定範圍內隨機產生資料,並將這些資料設為和core一樣的類別
#所以每類的資料會簡單的被X軸的每段大致分開
def makeKNNData(colnum,clsnum,nums,cores = []):
#colnum單個資料擁有特徵數量(包括資料的分類);
# clsnum表示共有多少種分類;
# nums是一個元組,表示每個類別希望產生多少資料樣本;
#cores非必要引數,手動給出只是用於測試,cores提供每類的中心點,以中心點為依據產生該類資料。
dataSet = np.zeros((sum(nums),colnum))   #初始化資料集,用於存放隨後生成的所有資料
n=0   #記錄生成資料的下標
step = 20/clsnum      #假定X座標軸只顯示0~20的範圍,step為X軸分段後的段長
for j in range(clsnum):     #迴圈生成各個類資料
try:
core = cores[j]      #如果cores沒有給出則,則出錯,跳至except執行
except IndexError :
core = np.random.rand(1,3)      #中心點為array([[x1,x2,c]]),c用於表示類別,這裡產生的是1*3的二維陣列
core[0][0] =j*step   core[0][0]*step  #將x1限制在各段中
core[0][1] *=15       #將x2即y軸限制在0~15範圍內
core[0][2] = j    #設定類別
cores.append(core)
for i in range(nums[j]):   #按nums中指定了每類資料的數量,用迴圈生成。
point= core[0][:2]   np.random.rand(1,2)*step -step/2   #產生點point(x,y),x以中心點在(core_x - step/2, core_x   step/2)範圍隨機波動,y同理。
row = np.column_stack((point,core[0][2]))   #加上類別成為一個資料
dataSet[n] = row
n  =1
i  =1
j  =1
#print("print cores:",cores)
return dataSet
#繪圖展示資料,每類資料點以不同的顏色顯示
def showFigure(dataSet,clsnum):
fig = plt.figure()
ax = fig.add_subplot(1,1,1)   #介面只需顯示一個檢視
ax.set_title('KNN separable data set')  #檢視名稱,這裡簡單統一定這個名稱吧
plt.xlabel('X')    #座標軸名稱
plt.ylabel('Y')
colors = ['r','g','b','y','k']   #定義顯示的顏色b為blue,k為black
for i in range(clsnum):
idx = np.where(dataSet[:,2] == i)  #查詢每類的索引號
ax.scatter(dataSet[idx,0], dataSet[idx,1], marker='o', color=colors[i%5], label=1, s=10)  #在檢視中的顯示方式
plt.legend(loc = 'upper right')   #圖例顯示位置
plt.show()
#分類演算法:
#待分類資料iData,先計算其到已標記資料集中每個資料的距離
#然後根據離iData最近的k個資料的分類,出現次數最多的類別定為iData的分類。
def KNNClassify(labelData,predData,k):  #資料集包含分類屬性
#labelData 是已經標記分類的資料集
#predData 待預測資料集
labShape = labelData.shape
for i in range(predData.shape[0]): #以predData的每行資料進行遍歷
iData = predData[i]
iDset = np.tile(iData,(labShape[0],1))   #將iData重複,擴充套件成與labelData同形的矩陣
#這裡用尤拉距離sqrt((x1-x2)^2 (y1-y2)^2)
diff = iDset[...,:-1] - labelData[...,:-1]
diff = diff**2
distance = np.sum(diff,axis=1)
distance = distance ** 0.5  #開根號
sortedIND = np.argsort(distance)   #排序,以序號返回。
classCount = { }
for j in range(k):  #計算距離最近的前k個標記資料的類別
voteLabel = labelData[sortedIND[j],-1]
classCount[voteLabel] = classCount.get(voteLabel,0) 1
maxcls = max(classCount,key=classCount.get)   #類別最多的,返回鍵名(類別名)
predData[i][...,-1] =  maxcls
return predData
#測試
labNums = np.random.randint(50,200,classnum)
predNums = np.random.randint(10,80,classnum)
#cores = [np.array([[ 0.08321641, 12.22596938,  0.        ]]), np.array([[9.99891798, 4.24009775, 1.        ]]), np.array([[14.98097374,  9.80120399,  2.        ]])]
labelData = makeKNNData(3,classnum,labNums)
showFigure(labelData,classnum)
predData = makeKNNData(3,classnum,predNums)   #這裡為了方便,不在寫產生待分類資料的程式碼,只需用之前的函式並忽略其類別就好。
predData[...,-1]=0
showFigure(predData,classnum)
k = 10
KNNData = KNNClassify(labelData,predData,k)
showFigure(KNNData,classnum)

執行程式,結果如下:

1.labelData的資料(已知分類的資料)
這裡寫圖片描述
2.predData的資料(未標記的資料)
這裡寫圖片描述
3KNNData的資料(用KNN演算法進行分類後的資料)
這裡寫圖片描述