KNN分类算法的Python实现
前言
K最近邻(k-Nearest Neighbor,KNN)分类算法,是一个理论上比较成熟的方法,也是最简单的机器学习算法之一。该方法的思路是:在特征空间中,如果一个样本附近的k个最近(即特征空间中最邻近)样本的大多数属于某一个类别,则该样本也属于这个类别。。
一、KNN的基本思路
所谓K近邻算法,即是给定一个训练数据集,对新的输入实例,在训练数据集中找到与该实例最邻近的K个实例, 这K个实例的多数属于某个类,就把该输入实例分类到这个类中。并不是很复杂,十分易于理解。主要的算法思路也就分为3步。
- 从测试集中选择一个样本,分别计算该样本和训练集中各样本的距离(本文选择欧氏距离)。
- 对选取的测试集样本与各训练集样本的距离记录排序,找到距离最小的k个距离。以距离平方的倒数为权重,对这k个样本的标签进行加权投票,得到该测试集样本的标签。
- 循环对测试集样本进行上述两步操作。
二、代码实现
程序部分主要有5个部分:
read_xslx(xslx_path) #读取excel文件
standardization(v,mu,sigma) #对一个数据规范化
standardize(data) #对数据集规范化
calDistance(testingrow, trainingrow) #计算样本间距离
KNN(trainingData, testingData, k) #KNN算法部分
1.读取excel文件
#读取excel文件,400个为训练集,200个为测试集
####################################################################################################################
def read_xslx(xslx_path):
dataSet = [] # 先声明一个空list
data = xlrd.open_workbook(xslx_path) # 读取文件
table = data.sheet_by_index(0) # 按索引获取工作表,0就是工作表1
for i in range(table.nrows): # table.nrows表示总行数
line = table.row_values(i) # 读取每行数据,保存在line里面,line是list
dataSet.append(line) # 将line加入到trainingdata中,trainingdata是二维list
dataSet = np.array(dataSet) # 将trainingdata从二维list变成数组
return dataSet
####################################################################################################################
2.对一个数据规范化
#规范化处理函数
#####################################################################################
def standardization(v,mu,sigma):
v = (v - mu)/sigma
return v
#####################################################################################
3.对数据集规范化
#规范化数据
####################################################################################################################
def standardize(data):
numTotal = data.shape[0] # 记录测试数据集总条数
attr1 = data[:, 0].astype(float) #标准化过程
attr2 = data[:, 1].astype(float)
attr3 = data[:, 2].astype(float)
attr4 = data[:, 3].astype(float)
attr5 = data[:, 4].astype(float)
attr6 = data[:, 5].astype(float)
Data = data
mu1 = np.mean(attr1)
sigma1 = np.std(attr1)
for i in range(0,numTotal):
Data[:, 0][i] = standardization(attr1[i],mu1,sigma1)
mu2 = np.mean(attr2)
sigma2 = np.std(attr2)
for i in range(0,numTotal):
Data[:, 1][i] = standardization(attr2[i],mu2,sigma2)
mu3 = np.mean(attr3)
sigma3 = np.std(attr3)
for i in range(0,numTotal):
Data[:, 2][i] = standardization(attr3[i],mu3,sigma3)
mu4 = np.mean(attr4)
sigma4 = np.std(attr4)
for i in range(0,numTotal):
Data[:, 3][i] = standardization(attr4[i],mu4,sigma4)
mu5 = np.mean(attr5)
sigma5 = np.std(attr5)
for i in range(0,numTotal):
Data[:, 4][i] = standardization(attr5[i],mu5,sigma5)
mu6 = np.mean(attr6)
sigma6 = np.std(attr6)
for i in range(0,numTotal):
Data[:, 5][i] = standardization(attr6[i],mu6,sigma6)
return Data
####################################################################################################################
4.计算样本间距离
#计算距离
####################################################################################################################
def calDistance(testingrow, trainingrow):
dist = ((float(testingrow[0]) - float(trainingrow[0])) ** 2 + (float(testingrow[1]) - float(trainingrow[1])) ** 2 \
+ (float(testingrow[2]) - float(trainingrow[2])) ** 2 + (float(testingrow[3]) - float(trainingrow[3])) ** 2\
+ (float(testingrow[4]) - float(trainingrow[4])) ** 2 + (float(testingrow[5]) - float(trainingrow[5])) ** 2) ** 0.5
return dist
####################################################################################################################
5.KNN算法
#K邻近算法
####################################################################################################################
def KNN(trainingData, testingData, k):
numTest = testingData.shape[0] # 记录测试数据集总条数
numTrain = trainingData.shape[0] # 记录训练数据集总条数
labelTest = [] # 记录各测试样本的标签分类结果
for i in range(0, numTest):
distance = [] # 记录某测试样本和各训练样本的距离
labelTrain = [] # 记录某测试样本下各训练样本的标签
labeljudge = [0.0, 0.0, 0.0]
for j in range(0, numTrain):
distance.append(calDistance(testingData[i], trainingData[j])) # 记录某测试样本和各训练样本的距离
labelTrain.append(trainingData[j][-1]) # 记录各训练样本的标签
distance2 = distance[:]
distance2.sort()
for p in range(0, k):
a = distance2[p]
b = distance.index(a)
temp = labelTrain[b] # 记录各测试样本的标签分类结果
if temp == '0.0':
labeljudge[0] += 1/(distance2[p])**2
elif temp == '1.0':
labeljudge[1] += 1/(distance2[p])**2
elif temp == '2.0':
labeljudge[2] += 1/(distance2[p])**2
labelType = labeljudge.index(max(labeljudge))
if labelType == 0:
labelTest.append('0.0')
elif labelType == 1:
labelTest.append('1.0')
elif labelType == 2:
labelTest.append('2.0')
cm = confusion_matrix(testingData[:,-1], labelTest, labels=["0.0", "1.0", "2.0"])
plt.rc('figure', figsize=(5, 5))
plt.matshow(cm, cmap=plt.cm.cool) # 背景颜色
plt.colorbar() # 颜色标签
# 内部添加图例标签
for x in range(len(cm)):
for y in range(len(cm)):
plt.annotate(cm[x, y], xy=(y, x), horizontalalignment='center', verticalalignment='center')
plt.ylabel('True Label')
plt.xlabel('Predicted Label')
plt.title('KNN')
plt.savefig(r'confusion_matrix')
return cm
####################################################################################################################
完整代码
# -*- coding: utf-8 -*- 支持文件中出现中文字符
#########################################################################
"""
Created on Thur Nov 19 16:32:00 2020
@author: ixobgnew
代码功能描述:(1)读取xlsx文件
(2)分离数据集
(3)数据规范化处理
(4)计算数据欧氏距离
(5)K邻近算法
(6)生成混淆矩阵
"""
#####################################################################
import xlrd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.metrics import confusion_matrix
#读取excel文件,400个为训练集,200个为测试集
####################################################################################################################
def read_xslx(xslx_path):
dataSet = [] # 先声明一个空list
data = xlrd.open_workbook(xslx_path) # 读取文件
table = data.sheet_by_index(0) # 按索引获取工作表,0就是工作表1
for i in range(table.nrows): # table.nrows表示总行数
line = table.row_values(i) # 读取每行数据,保存在line里面,line是list
dataSet.append(line) # 将line加入到trainingdata中,trainingdata是二维list
dataSet = np.array(dataSet) # 将trainingdata从二维list变成数组
return dataSet
####################################################################################################################
#规范化处理函数
#####################################################################################
def standardization(v,mu,sigma):
v = (v - mu)/sigma
return v
#####################################################################################
#规范化数据
####################################################################################################################
def standardize(data):
numTotal = data.shape[0] # 记录测试数据集总条数
attr1 = data[:, 0].astype(float) #标准化过程
attr2 = data[:, 1].astype(float)
attr3 = data[:, 2].astype(float)
attr4 = data[:, 3].astype(float)
attr5 = data[:, 4].astype(float)
attr6 = data[:, 5].astype(float)
Data = data
mu1 = np.mean(attr1)
sigma1 = np.std(attr1)
for i in range(0,numTotal):
Data[:, 0][i] = standardization(attr1[i],mu1,sigma1)
mu2 = np.mean(attr2)
sigma2 = np.std(attr2)
for i in range(0,numTotal):
Data[:, 1][i] = standardization(attr2[i],mu2,sigma2)
mu3 = np.mean(attr3)
sigma3 = np.std(attr3)
for i in range(0,numTotal):
Data[:, 2][i] = standardization(attr3[i],mu3,sigma3)
mu4 = np.mean(attr4)
sigma4 = np.std(attr4)
for i in range(0,numTotal):
Data[:, 3][i] = standardization(attr4[i],mu4,sigma4)
mu5 = np.mean(attr5)
sigma5 = np.std(attr5)
for i in range(0,numTotal):
Data[:, 4][i] = standardization(attr5[i],mu5,sigma5)
mu6 = np.mean(attr6)
sigma6 = np.std(attr6)
for i in range(0,numTotal):
Data[:, 5][i] = standardization(attr6[i],mu6,sigma6)
return Data
####################################################################################################################
#计算距离
####################################################################################################################
def calDistance(testingrow, trainingrow):
dist = ((float(testingrow[0]) - float(trainingrow[0])) ** 2 + (float(testingrow[1]) - float(trainingrow[1])) ** 2 \
+ (float(testingrow[2]) - float(trainingrow[2])) ** 2 + (float(testingrow[3]) - float(trainingrow[3])) ** 2\
+ (float(testingrow[4]) - float(trainingrow[4])) ** 2 + (float(testingrow[5]) - float(trainingrow[5])) ** 2) ** 0.5
return dist
####################################################################################################################
#K邻近算法
####################################################################################################################
def KNN(trainingData, testingData, k):
numTest = testingData.shape[0] # 记录测试数据集总条数
numTrain = trainingData.shape[0] # 记录训练数据集总条数
labelTest = [] # 记录各测试样本的标签分类结果
for i in range(0, numTest):
distance = [] # 记录某测试样本和各训练样本的距离
labelTrain = [] # 记录某测试样本下各训练样本的标签
labeljudge = [0.0, 0.0, 0.0]
for j in range(0, numTrain):
distance.append(calDistance(testingData[i], trainingData[j])) # 记录某测试样本和各训练样本的距离
labelTrain.append(trainingData[j][-1]) # 记录各训练样本的标签
distance2 = distance[:]
distance2.sort()
for p in range(0, k):
a = distance2[p]
b = distance.index(a)
temp = labelTrain[b] # 记录各测试样本的标签分类结果
if temp == '0.0':
labeljudge[0] += 1/(distance2[p])**2
elif temp == '1.0':
labeljudge[1] += 1/(distance2[p])**2
elif temp == '2.0':
labeljudge[2] += 1/(distance2[p])**2
labelType = labeljudge.index(max(labeljudge))
if labelType == 0:
labelTest.append('0.0')
elif labelType == 1:
labelTest.append('1.0')
elif labelType == 2:
labelTest.append('2.0')
cm = confusion_matrix(testingData[:,-1], labelTest, labels=["0.0", "1.0", "2.0"])
plt.rc('figure', figsize=(5, 5))
plt.matshow(cm, cmap=plt.cm.cool) # 背景颜色
plt.colorbar() # 颜色标签
# 内部添加图例标签
for x in range(len(cm)):
for y in range(len(cm)):
plt.annotate(cm[x, y], xy=(y, x), horizontalalignment='center', verticalalignment='center')
plt.ylabel('True Label')
plt.xlabel('Predicted Label')
plt.title('KNN')
plt.savefig(r'confusion_matrix')
return cm
####################################################################################################################
Data113 = read_xslx(r'e:/Table/机器学习/1118/attribute_113.xlsx')
Data114 = read_xslx(r'e:/Table/机器学习/1118/attribute_114.xlsx')
data = np.vstack((Data113[1:,1:],Data114[1:,1:]))
Data = standardize(data)
trainingData = Data[0:397]
testingData = Data[398:600]
ConfusionMatrix = KNN(trainingData, testingData, 4)
print(ConfusionMatrix)
分类结果
需要注意,KNN算法中K的选择对算法的分类效果有着明显影响。
选择K=4时,生成的混淆矩阵:
[[46 0 17]
[ 1 30 2]
[22 1 81]]
可视化结果如下:
如果改变K的取值,混淆矩阵会明显改变,如下所示:
①k=3:
②k=5:
③k=6:
④k=8:
⑤k=9:
总结
本文利用KNN算法所得分类结果并不是很佳,无法很准确地分辨“0”类和“2”类,如果选择其他的度量方式来获取样本间距离,或是采用其他对数据的标准化方法可能可以有所改善。但KNN算法本身是一个比较简单粗暴的方法,还是能起到初步的分类效果的。
本文地址:https://blog.csdn.net/ixobgenw/article/details/109821291