欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

KNN分类算法的Python实现

程序员文章站 2022-03-22 15:00:46
文章目录前言一、KNN的基本思路二、代码实现1.读取excel文件2.对一个数据规范化3.对数据集规范化4.计算样本间距离5.KNN算法完整代码分类结果总结前言K最近邻(k-Nearest Neighbor,KNN)分类算法,是一个理论上比较成熟的方法,也是最简单的机器学习算法之一。该方法的思路是:在特征空间中,如果一个样本附近的k个最近(即特征空间中最邻近)样本的大多数属于某一个类别,则该样本也属于这个类别。。一、KNN的基本思路所谓K近邻算法,即是给定一个训练数据集,对新的输入实例,在训....


前言

K最近邻(k-Nearest Neighbor,KNN)分类算法,是一个理论上比较成熟的方法,也是最简单的机器学习算法之一。该方法的思路是:在特征空间中,如果一个样本附近的k个最近(即特征空间中最邻近)样本的大多数属于某一个类别,则该样本也属于这个类别。。


一、KNN的基本思路

所谓K近邻算法,即是给定一个训练数据集,对新的输入实例,在训练数据集中找到与该实例最邻近的K个实例, 这K个实例的多数属于某个类,就把该输入实例分类到这个类中。并不是很复杂,十分易于理解。主要的算法思路也就分为3步。

  1. 从测试集中选择一个样本,分别计算该样本和训练集中各样本的距离(本文选择欧氏距离)。
  2. 对选取的测试集样本与各训练集样本的距离记录排序,找到距离最小的k个距离。以距离平方的倒数为权重,对这k个样本的标签进行加权投票,得到该测试集样本的标签。
  3. 循环对测试集样本进行上述两步操作。

二、代码实现

程序部分主要有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]]

可视化结果如下:
KNN分类算法的Python实现
如果改变K的取值,混淆矩阵会明显改变,如下所示:

①k=3:KNN分类算法的Python实现
②k=5:
KNN分类算法的Python实现 ③k=6:

KNN分类算法的Python实现
④k=8:
KNN分类算法的Python实现
⑤k=9:
KNN分类算法的Python实现

总结

本文利用KNN算法所得分类结果并不是很佳,无法很准确地分辨“0”类和“2”类,如果选择其他的度量方式来获取样本间距离,或是采用其他对数据的标准化方法可能可以有所改善。但KNN算法本身是一个比较简单粗暴的方法,还是能起到初步的分类效果的。

本文地址:https://blog.csdn.net/ixobgenw/article/details/109821291