机器学习-KNN聚类算法原理及Python代码实现

回忆式~过去.
测试领域新星创作者
2023-08-28 14:25:21

一、 KNN算法概述

K最近邻(k-Nearest Neighbor,KNN)分类算法,是一个理论上比较成熟的方法,也是最简单的机器学习算法之一。需要注意的是KNN算法是监督学习中的分类算法,看起来和它的兄弟Kmeans算法有点像。KNN算法它的类别都是已知的,通过对已知分类的数据进行训练和学习,找到这些不同类的特征,在对未分类的数据进行分类。而kmeans算法属于非监督学习,我们事先是不知道数据会分为几类,通过聚类分析后将数据合成几个群体。

二、 KNN算法介绍

K-近邻算法(KNN)算法实现简单、高效。在分类、回归、模式识别等方面有着广泛的应用。该方法的思路是:在特征空间中,如果一个样本附近的k个最近(即特征空间中最邻近)样本的大多数属于某一个类别,则该样本也属于这个类别。就比如经常和我一块玩的人有10个人,他们中有6个人是好人,有1个人是比较坏的,有3个人又好又坏的,那么大家就认为我也是个好人,通过我接触某个类型的多少以此来给我定性。对应中国的古话:“近朱则赤,近墨者黑”。所以这个K的取值是很重要的,

在这里插入图片描述

上图中圆环就是K的取值范围,当K的取值是4时,K被分到黄色一栏,当K的取值是6时,K被分到蓝色一栏.

K值选择

通过上图我们知道K的取值是很重要的,那么我们该如何确定K的取值呢?在KNN中K是一个超参数,需要我们进行指定,一般情况下这个k和数据有很大关系,都是交叉验证进行选择,但是建议使用交叉验证的时候,k∈[2,20],使用交叉验证得到一个很好的k值。需注意最好K的取值为奇数,防止出现平票而无法分类的情况。
k值还可以表示我们的模型复杂度,k值越小,意味着模型复杂度变大,更容易过拟合(用极少数的样例来绝对这个预测的结果,很容易产生偏见,这就是过拟合)。k值越大,学习的估计误差越小,但是学习的近似误差就会增大,容易造成欠拟合。

距离计算

度量空间中点距离有好几种度量方式,比如常见的曼哈顿距离计算,欧式距离计算等等。通常KNN算法中采用的是欧式距离,二维空间两个点的欧式距离计算公式如下:
欧氏距离:

在这里插入图片描述


曼哈顿距离:

在这里插入图片描述

三、KNN算法优缺点

优点

  • knn算法是一种在线技术,新数据可以直接加入数据集,而不必重新训练数据
  • knn理论简单,容易实现
  • 简单好用,容易理解,精度高,理论成熟,既可以用来做分类也可以用来做回归
  • 可用于数值型数据和离散型数据
  • 训练时间复杂度为O(n);无数据输入假定
  • 对异常值不敏感

缺点

  • 对于样本容量大的数据集,计算量大
  • 样本不平衡时,预测偏差较大。如:某一类样本较少而其他类样本数据较少。
  • knn每一次分类都会重新进行全局运算,因此计算负载重,需要很多内存。
  • k的选择
  • 模型在高维空间中可能效果不佳,而且当数据规模增长时,模型的扩展性能也不好。
  • 难以确定那种距离计算好。

    四、KNN算法实现步骤

输入:

  1. 训练集数据:包括要训练的样本数和它们对应的标签
  2. 测试数据:只包含样本数据,没有对应的标签
  3. K值:K的取值范围,指定计算距离最近邻的数量

算法:

  1. 通过欧式距离计算公式:√(x - x1)² + (y - y1)²,计算测试数据与训练集中所有样本数据之间的距离
  2. 根据计算出来的距离数据,取K个最近邻的数据
  3. 统计这K个最近邻数据的标签
  4. 将测试集中的样本分类为统计数据中出现次数最多的那个类别

输出:

  1. 分类结果:将测试集中的样本被分类为对应的类别

    五、KNN算法Python实现

#!/usr/bin/env python
# _*_ coding:utf-8 _*_

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.lines as mlines
from pylab import *
import openpyxl

datafile = '/Users/desktop/leastsquare.xlsx'


def knn(train_data, testdata, data_tag, k):
    # 将数组统一化
    # 将输入数据平铺为train_data_size行1列,便于与训练数据做差
    new_testtdata = np.tile(test_data, (train_data.shape[0], 1))
    new_testtdata = new_testtdata - train_data
    new_testtdata = new_testtdata ** 2
    new_testtdata1 = new_testtdata.sum(axis=1)
    new_testtdata1 = new_testtdata1 ** 0.5  # 欧氏距离
    # new_testtdata1 = pow(new_testtdata1,0.5)
    # 将欧氏距离排序,返回对应的索引值
    sortdata = np.argsort(new_testtdata1)

    # 统计前k个类型数量
    count = {}
    for i in range(k):
        vote = data_tag[sortdata[i]]  # 第i个距离对应的标签
        count[vote] = count.get(vote, 0) + 1  #统计某个标签个数
    sortdata = sorted(count.items(), key=lambda x: x[1], reverse=True)
    return sortdata[0][0], test_data


def Read_data():
    data = pd.read_excel(datafile, index_col=u'电影名称', sheet_name='knn_data2')
    x = data[u'打斗次数'].tolist()
    y = data[u'接吻次数'].tolist()
    # z = data[u'z'].tolist()
    b = data[u'电影类型'].tolist()
    return x, y, b


x, y, b = Read_data()


def write_data(write_test_data, write_test_tag):
    """
    :param write_test_data: 将测试数据写入文件
    :param write_test_tag: 将预测后的标签写入文件
    :return:
    """
    # 打开Excel文件
    workbook = openpyxl.load_workbook(datafile)
    # 选择工作表
    worksheet = workbook['knn_data2']
    # 在指定单元格中写入数据
    worksheet['A{}'.format(int(len(x)) + 2)] = int(len(x)) + 2
    worksheet['B{}'.format(int(len(x)) + 2)] = write_test_data[0]
    worksheet['C{}'.format(int(len(x)) + 2)] = write_test_data[1]
    worksheet['D{}'.format(int(len(x)) + 2)] = write_test_tag
    # 保存Excel文件
    workbook.save(datafile)


# 调用matplotlib实现散点图
def Show():
    '''
    plt.scatter(x, y, c=b,cmap='viridis')
    plt.show()
    '''
    # mpl.rcParams['font.sans-serif'] = ['SimHei']
    tag1, data1 = knn(train_data, test_data, data_tag, k)
    write_data(data1, tag1)
    print('测试数据为:{}\n'
          'k取值范围为:{}\n'
          '输入数据的类型为:“{}”'.format(test_data, k, tag1))
    # 添加颜色列表
    colourlist = []
    for i in b:
        if i == '动作片':
            colourlist.append('black')
        if i == '科幻片':
            colourlist.append('orange')
        if i == '爱情片':
            colourlist.append('red')
    if tag1 == '动作片':
        colourlist1 = ['black', 'Testdata is Action movie']
    if tag1 == '科幻片':
        colourlist1 = ['orange', 'Testdata is Science fiction film']
    if tag1 == '爱情片':
        colourlist1 = ['red', 'Testdata is Romantic film']
    # 画出图表
    plt.title("KNN algorithm implemented in Python")
    plt.ion()
    plt.scatter(x, y, c=colourlist, s=15)
    plt.scatter(data1[0], data1[1], c=colourlist1[0], marker='*', s=100)
    didntLike = mlines.Line2D([], [], color='black', marker='.',
                              markersize=6, label='Action movie')
    smallDoses = mlines.Line2D([], [], color='orange', marker='.',
                               markersize=6, label='Science fiction film')
    largeDoses = mlines.Line2D([], [], color='red', marker='.',
                               markersize=6, label='Romantic film')
    testdata = mlines.Line2D([], [], color=colourlist1[0], marker='*',
                             markersize=12, label=colourlist1[1])
    # 添加图例
    plt.legend(handles=[didntLike, smallDoses, largeDoses, testdata])
    plt.show()


if __name__ == '__main__':

    train_data = np.array(
        [i for i in zip(Read_data()[0], Read_data()[1])]
    )
    data_tag = np.array(Read_data()[2])
    test_x = int(input("输入测试数据x:"))
    test_y = int(input("输入测试数据y:"))
    test_data = np.array([test_x, test_y])
    k = int(input("输入k取值范围:"))
    Show()

测试数据

在这里插入图片描述

运行结果

在这里插入图片描述


在这里插入图片描述


上图五角星就是我们的分类结果

...全文
142 回复 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

16

社区成员

发帖
与我相关
我的任务
社区描述
集结测试界的各位大佬,一起学习技术,一起努力!
功能测试压力测试安全性测试 个人社区 北京·海淀区
社区管理员
  • 回忆式~过去.
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧