• 机器学习——KNN算法流程详解(以iris为例)


    目    录

    前情说明

    问题陈述

    数据说明

    KNN算法流程概述

    代码实现

    运行结果

    基于可视化的改进

    可视化代码

    全部数据可视化总览

    分类投票结果

     改进后最终代码


    前情说明

    本书基于《特征工程入门与入门与实践》庄家盛 译版P53页K最近邻(KNN)算法进行讲解

    问题陈述

    Iris 鸢尾花数据集内包含 3 类分别为山鸢尾(Iris-setosa)、变色鸢尾(Iris-versicolor)和维吉尼亚鸢尾(Iris-virginica),共 150 条记录,每类各 50 个数据,每条记录都有 4 项特征:花萼长度、花萼宽度、花瓣长度、花瓣宽度。

    sepallength:萼片长度
    sepalwidth:萼片宽度
    petallength:花瓣长度
    petalwidth:花瓣宽度

    我们的任务就是:给定一组记录(包含sepallength,sepalwidth,petallength,petalwidth),使用KNN算法给出该组记录的分类 (使用0,1,2表示)

    数据说明

    本文使用数据源从机器学习库sklearn的datasets包中获取

    1. # 导入iris数据
    2. iris = datasets.load_iris()

    可支持的数据集如下:

    1. "load_digits",
    2. "load_files",
    3. "load_iris",
    4. "load_breast_cancer",
    5. "load_linnerud",
    6. "load_sample_image",
    7. "load_sample_images",
    8. "load_svmlight_file",
    9. "load_svmlight_files",
    10. "load_wine",
    11. #不知道为什么我的机器学习库只有这些数据集

    参考链接: sklearn中的datasets数据集 - 知乎 (zhihu.com)

    KNN算法流程概述

    1.数据获取。要进行KNN,我们需要样本的部分属性完整数据以及在各种属性不同值的组合情况下的对应分类结果

    2.数据清洗。获取数据后使用numpy整理缺失值,可视化查看是否有异常值(比如偏正态分布样本出现的极端值或者空值)

    3.数据切分。将数据按照一定比例,从特定位置切分成训练集和测试集,必要情况还需要切割分一部分数据作为验证集

    4.选取k个近邻点。使用某种数据结构或者库函数,获取逻辑距离最近的k个点位

    5.获取结果。对k个点位进行统计,获取票数最多的结果进行分类。但是存在票数一致的情况,可以使用某种排序方式对数据进行排序,隐式的赋予某些特定的数据具有更高的优先级(即返回首位即可)

    6.可视化(补充)。虽然使用KNN算法对结果进行展示了,但是整个过程的投票情况不够直观,于是我们接下来将对整体分类和循环内当前投票情况进行展示。

    代码实现

    1. from sklearn import datasets
    2. from collections import Counter # 为了做投票计数
    3. from sklearn.model_selection import train_test_split
    4. import random
    5. import numpy as np
    6. ###############数据定义区
    7. # 数据集划分随机数种子
    8. randomNums=random.randint(1,9999)
    9. print("随机数{}".format(randomNums))
    10. # 最短投票对象数量
    11. k=3
    12. ###############数据定义区END
    13. # 计算同类属性的欧氏距离 假设能这样计算欧式距离代表样本之间的差距
    14. def calcDistance(toBeMeasuredDataSet,DataSet):
    15. # print("打印欧氏距离")
    16. # print(toBeMeasuredDataSet,'\n',DataSet)
    17. # **2的妙用
    18. result=np.sqrt(np.sum((toBeMeasuredDataSet - DataSet)**2 ))
    19. # print("打印欧氏距离",result)
    20. return result
    21. # 原始特征数据集 原始分类数据集 选取个数 待分类对象(一条记录)
    22. def KNNSelect(X,Y,k,testObject):
    23. # 获取欧氏距离列表 计算待测数据与特征数据集的欧数据集
    24. distanceList=[calcDistance(testObject,singleData) for singleData in X ]
    25. # 排序后 切片获取逻辑距离最短的k个对记录的下标(维护前k个最值)
    26. theShortestIndex=np.argsort(distanceList)[:k]
    27. # 获取这k个结果
    28. resultList=Y[theShortestIndex]
    29. # 返回频率最高的结果 作为样本的类别
    30. return Counter(resultList).most_common(1)[0][0]
    31. def printTopLineA():
    32. print(r"/\/\/\/\/\/\/\/\/\/\/\/\/")
    33. def printTopLineB():
    34. print(r"\/\/\/\/\/\/\/\/\/\/\/\/\ ")
    35. # 导入鸾尾花数据集
    36. irisDataSet=datasets.load_iris()
    37. #获取特征数据集
    38. characteristicData=irisDataSet.data
    39. # 获取分类数据集
    40. categoricalData=irisDataSet.target
    41. # 训练用特征数据集
    42. # 测试用特征数据集
    43. # 训练用分类数据集
    44. # 测试用分类数据集
    45. trainCharDataSet,testCharDataSet,trainCateDataSet,testCateDaSet\
    46. =train_test_split(characteristicData,categoricalData,random_state=randomNums)
    47. for index,i in enumerate(testCharDataSet):
    48. print("第{}个数据\n特征数据是:{}\n数据的类别是:{}".format(index+1,i,KNNSelect(trainCharDataSet,trainCateDataSet,k,i)))
    49. if (index&1):
    50. printTopLineA()
    51. else:
    52. printTopLineB()

    运行结果

    基于可视化的改进

    我们还是从源数据入手,将源数据转换成key-value聚合的形式,

    具体点就是将同一类数据打成列表,作为以列名为key的对应的value

    运行网址:Replit: the collaborative browser based IDE - Replit

    可视化代码

    1. from collections import Counter # 为了做投票计数
    2. from sklearn import datasets
    3. from sklearn.model_selection import train_test_split
    4. import random
    5. import numpy as np
    6. import pandas as pd
    7. import seaborn as sns
    8. import matplotlib.pyplot as plt
    9. ###############说明
    10. # 1.本地sns画图环境炸了,具体原因不详,运行平台为Replit,复制即可运行
    11. # 2.参考了许多可视化案例,但大部分都没有理论支撑,就自己做了
    12. ###############数据定义区
    13. # 数据集划分随机数种子
    14. randomNums=random.randint(1,9999)
    15. print("随机数{}".format(randomNums))
    16. # 最小投票对象数量
    17. k=9
    18. ###############数据定义区END
    19. # 计算同类属性的欧氏距离 假设能这样计算欧式距离代表样本之间的差距
    20. def calcDistance(toBeMeasuredDataSet,DataSet):
    21. # print("打印欧氏距离")
    22. # print(toBeMeasuredDataSet,'\n',DataSet)
    23. # **2的妙用
    24. result=np.sqrt(np.sum((toBeMeasuredDataSet - DataSet)**2 ))
    25. # print("打印欧氏距离",result)
    26. return result
    27. #这个方法会传来收集好的k个数据以及分类结果 然后返回成key-value的形式调用进行可视化
    28. def showVisual(irisData,irisTarget):
    29. #数据处理
    30. irisDictData = {
    31. 'sepalLength': [],
    32. 'sepalWidth': [],
    33. 'petalLength': [],
    34. 'petalWidth': []
    35. }
    36. for index, i in enumerate(irisDictData):
    37. # print(index,i,irisDictData[i])
    38. #将每一列数据剥离出来
    39. irisDictData[i] = [data[index] for indexs, data in enumerate(irisData)]
    40. #将分类结果添加进来
    41. irisDictData['species']=irisTarget
    42. # 进行可视化
    43. visual(irisDictData)
    44. # 原始特征数据集 原始分类数据集 选取个数 待分类对象(一条记录)
    45. def KNNSelect(X,Y,k,testObject):
    46. # 获取欧氏距离列表 计算待测数据与特征数据集的欧数据集
    47. distanceList=[calcDistance(testObject,singleData) for singleData in X ]
    48. # 排序后 切片获取逻辑距离最短的k个对记录的下标(维护前k个最值)
    49. theShortestIndex=np.argsort(distanceList)[:k]
    50. # 获取这k个源数据和结果
    51. dataList=X[theShortestIndex]
    52. resultList=Y[theShortestIndex]
    53. print("投票结果:{}".format(resultList))
    54. ##########可视化出最近的k个点
    55. showVisual(dataList,resultList)
    56. # 返回频率最高的结果 作为样本的类别
    57. return Counter(resultList).most_common(1)[0][0]
    58. def showNcolsData():
    59. # 导入鸾尾花数据集
    60. irisDataSet = datasets.load_iris()
    61. # 分析花瓣与花萼的相关性
    62. # 宽度的相关性
    63. # 高度的相关性
    64. # data是采集数据 target是人工分好的类别数据
    65. irisData = irisDataSet["data"]
    66. # print(irisData[0][0])
    67. irisDictData = {
    68. 'sepalLength': [],
    69. 'sepalWidth': [],
    70. 'petalLength': [],
    71. 'petalWidth': []
    72. }
    73. for index, i in enumerate(irisDictData):
    74. # print(index,i,irisDictData[i])
    75. #将每一列数据剥离出来 注意这里用的下标是index 而不是indexs哈哈
    76. #感觉写的时候自己挺聪明,过两天就看不懂了qwq
    77. irisDictData[i] = [data[index] for indexs, data in enumerate(irisData)]
    78. # k2, p = stats.normaltest(irisDictData[i])
    79. # print(k2,p)
    80. # 添加预测结果数据
    81. irisDictData['species']=irisDataSet['target']
    82. return irisDictData
    83. # 装饰打印语句
    84. def printTopLineA():
    85. print(r"/\/\/\/\/\/\/\/\/\/\/\/\/")
    86. def printTopLineB():
    87. print(r"\/\/\/\/\/\/\/\/\/\/\/\/\ ")
    88. #可视化函数
    89. def visual(rawData):
    90. # 传入一个没有被DataFrame的
    91. dfData=pd.DataFrame(rawData)
    92. # x X轴展示数据
    93. # y Y轴展示数据
    94. # data 数据源
    95. # hub 颜色分类依据列
    96. # 分类总览
    97. sns.relplot(x='sepalLength',y='sepalWidth',data=dfData,hue='species')
    98. plt.show()
    99. # 导入鸾尾花数据集
    100. irisDataSet=datasets.load_iris()
    101. #获取特征数据集
    102. characteristicData=irisDataSet.data
    103. # 获取分类数据集
    104. categoricalData=irisDataSet.target
    105. # print("打印分类结果",categoricalData)
    106. # 训练用特征数据集,测试用特征数据集,训练用分类数据集,测试用分类数据集
    107. trainCharDataSet,testCharDataSet,trainCateDataSet,testCateDaSet\
    108. =train_test_split(characteristicData,categoricalData,random_state=randomNums)
    109. # 可视化需求分析
    110. # 1.对训练集数据进行可视化
    111. # 2.对每个测试对象展示一个独特的点
    112. # 3.标出待测对象最近的k个点
    113. # 每一列key的字典 对应值是该列数据
    114. irisDictData=showNcolsData()
    115. # sepalLength sepalWidth petalLength petalWidth
    116. # print(dfData)
    117. visual(irisDictData) #对整体进行可视化
    118. ###使用循环处理待测数据 并给出结果
    119. for index,i in enumerate(testCharDataSet):
    120. print("第{}个数据\n特征数据是:{}\n数据的类别是:{}"\
    121. .format(index+1,i,KNNSelect(trainCharDataSet,trainCateDataSet,k,i)))
    122. printTopLineA() if index&1 else printTopLineB()

    全部数据可视化总览

    分类投票结果

     改进后最终代码

    我们对代码进行优化,整理后最终代码如下,可在如上在线平台直接运行

    1. from collections import Counter # 为了做投票计数
    2. from sklearn import datasets
    3. from sklearn.model_selection import train_test_split
    4. import random
    5. import numpy as np
    6. import pandas as pd
    7. import seaborn as sns #流行可视化工具
    8. import matplotlib.pyplot as plt #sns的底层基于这个。。。需要用plt.show()
    9. ###############说明
    10. # 1.本地sns画图环境炸了,具体原因不详,运行平台为Replit,复制即可运行
    11. # 2.参考了许多可视化案例,但大部分都没有理论支撑,就自己做了
    12. ###############数据定义区
    13. # 数据集划分随机数种子
    14. randomNums = random.randint(1, 9999)
    15. print("随机数{}".format(randomNums))
    16. # 最小投票对象数量
    17. k = 9
    18. # 定义空字典 增加复用率
    19. irisDictEmptyData = {
    20. 'sepalLength': [],
    21. 'sepalWidth': [],
    22. 'petalLength': [],
    23. 'petalWidth': []
    24. }
    25. ###############数据定义区END
    26. # 计算同类属性的欧氏距离 假设能这样计算欧式距离代表样本之间的差距
    27. def calcDistance(toBeMeasuredDataSet, DataSet):
    28. # print("打印欧氏距离")
    29. # print(toBeMeasuredDataSet,'\n',DataSet)
    30. # **2的妙用
    31. result = np.sqrt(np.sum((toBeMeasuredDataSet - DataSet) ** 2))
    32. # print("打印欧氏距离",result)
    33. return result
    34. def dealRawDataToDict(irisDictData, irisData):
    35. for index, i in enumerate(irisDictData):
    36. # print(index,i,irisDictData[i])
    37. # 将每一列数据剥离出来 注意这里用的下标是index 而不是indexs哈哈
    38. # 感觉写的时候自己挺聪明,过两天就看不懂了qwq
    39. irisDictData[i] = [data[index] for indexs, data in enumerate(irisData)]
    40. return irisDictData
    41. # 这个方法会传来收集好的k个数据以及分类结果 然后返回成key-value的形式调用进行可视化
    42. def showVisual(irisData, irisTarget):
    43. # 数据处理
    44. irisDictData = dealRawDataToDict(irisDictEmptyData, irisData)
    45. # 将分类结果添加进来
    46. irisDictData['species'] = irisTarget
    47. # 进行可视化
    48. visual(irisDictData)
    49. # 原始特征数据集 原始分类数据集 选取个数 待分类对象(一条记录)
    50. def KNNSelect(X, Y, k, testObject):
    51. # 获取欧氏距离列表 计算待测数据与特征数据集的欧数据集
    52. distanceList = [calcDistance(testObject, singleData) for singleData in X]
    53. # 排序后 切片获取逻辑距离最短的k个对记录的下标(维护前k个最值)
    54. theShortestIndex = np.argsort(distanceList)[:k]
    55. # 获取这k个源数据和结果
    56. dataList = X[theShortestIndex]
    57. resultList = Y[theShortestIndex]
    58. print("投票结果:{}".format(resultList))
    59. ##########可视化出最近的k个点
    60. showVisual(dataList, resultList)
    61. # 返回频率最高的结果 作为样本的类别
    62. return Counter(resultList).most_common(1)[0][0]
    63. #拼装全部原始数据 然后送还字典
    64. def showNcolsData():
    65. # 导入鸾尾花数据集
    66. irisDataSet = datasets.load_iris()
    67. # 分析花瓣与花萼的相关性
    68. # 宽度的相关性
    69. # 高度的相关性
    70. # data是采集数据 target是人工分好的类别数据
    71. irisData = irisDataSet["data"]
    72. # print(irisData[0][0])
    73. irisDictData = dealRawDataToDict(irisDictEmptyData, irisData)
    74. # 添加预测结果数据
    75. irisDictData['species'] = irisDataSet['target']
    76. return irisDictData
    77. # 装饰打印语句
    78. def printTopLineA():
    79. print(r"/\/\/\/\/\/\/\/\/\/\/\/\/")
    80. def printTopLineB():
    81. print(r"\/\/\/\/\/\/\/\/\/\/\/\/\ ")
    82. # 可视化函数
    83. def visual(rawData):
    84. # 传入一个没有被DataFrame的
    85. dfData = pd.DataFrame(rawData)
    86. # x X轴展示数据
    87. # y Y轴展示数据
    88. # data 数据源
    89. # hub 颜色分类依据列
    90. # 分类总览
    91. sns.relplot(x='sepalLength', y='sepalWidth', data=dfData, hue='species')
    92. plt.show()
    93. # 导入鸾尾花数据集
    94. irisDataSet = datasets.load_iris()
    95. # 获取特征数据集
    96. characteristicData = irisDataSet.data
    97. # 获取分类数据集
    98. categoricalData = irisDataSet.target
    99. # print("打印分类结果",categoricalData)
    100. # 训练用特征数据集,测试用特征数据集,训练用分类数据集,测试用分类数据集
    101. trainCharDataSet, testCharDataSet, trainCateDataSet, testCateDaSet \
    102. = train_test_split(characteristicData, categoricalData, random_state=randomNums)
    103. # 可视化需求分析
    104. # 1.对训练集数据进行可视化
    105. # 2.对每个测试对象展示一个独特的点
    106. # 3.标出待测对象最近的k个点
    107. # 每一列key的字典 对应值是该列数据
    108. irisDictData = showNcolsData()
    109. # sepalLength sepalWidth petalLength petalWidth
    110. # print(dfData)
    111. visual(irisDictData) # 进行可视化
    112. ###使用循环处理待测数据 并给出结果
    113. for index, i in enumerate(testCharDataSet):
    114. print("第{}个数据\n特征数据是:{}\n数据的类别是:{}" \
    115. .format(index + 1, i, KNNSelect(trainCharDataSet, trainCateDataSet, k, i)))
    116. printTopLineA() if index & 1 else printTopLineB()

    部分参考链接:

    1.sklearn数据集——iris鸢尾花数据集_iris 数据_lyb06的博客-CSDN博客

    2.【机器学习实战】科学处理鸢尾花数据集_鸢尾花数据标准化处理-CSDN博客

    3.数据分析——鸢尾花数据集-CSDN博客

    4.Python collections模块之Counter()详解_python counter-CSDN博客

    5.Python基本函数:np.argsort()-CSDN博客

    6.Python中的Counter.most_common()方法-CSDN博客

    7.史上最全面K近邻算法/KNN算法详解+python实现 - 知乎 (zhihu.com)

    8.什么是KNN算法? - 知乎 (zhihu.com)

    9.sklearn中的datasets数据集 - 知乎 (zhihu.com)

  • 相关阅读:
    创建react脚手架项目——demo(react18 + react-router 6)
    git worktree与分支依赖隔离
    C#创历史成为2023年度编程语言!!!
    C语言笔记-18-Linux基础-进程
    基于SpringBoot的体育馆场地赛事预约管理系统设计与实现(源码+lw+部署文档+讲解等)
    SAS学习8、9(方差分析、anova过程、相关分析和回归分析、corr过程、reg过程、多元线性回归、stepwise)
    8Manage PM:通过项目管理信息系统做好进度管控
    蓝凌OA sysUiComponent 任意文件上传漏洞复现
    C#中string类型是引用类型
    uniapp 表格组件,冻结首行首列
  • 原文地址:https://blog.csdn.net/m0_72678953/article/details/133379030