一、K-近邻算法定义与思想
定义
k-近邻算法是一种基本分类和回归的方法;即是给定一个训练数据集,对新的输入实例,在训练数据集中找到与该实例最邻近的K个实例,这K个实例的多数属于某个类,就把该输入实例分类到这个类中。(简单的比喻就是“少数服从多数”)。
思想
k-近邻算法的基本思想是基于已有的样本数据集,对新的未知样本进行预测。对于一个未知的数据样本,k-近邻算法会在已有的样本数据集中找到与样本距离最近的k个数据点,然后选择这k个数据点中出现次数最多的标签作为最后的预测结果。
算法步骤
1. 根据已知数据集中所有实例计算未知实例的距离
2.选择K值
3根据算法规则(少数服从多数),对未知实例进行归类。
关键
(1) 样本的所有特征都要做可比较的量化
若是样本特征中存在非数值的类型,必须采取手段将其量化为数值。例如样本特征中包含颜色,可通过将颜色转换为灰度值来实现距离计算。
(2) 样本特征要做归一化处理
样本有多个参数,每一个参数都有自己的定义域和取值范围,他们对距离计算的影响不一样,如取值较大的影响力会盖过取值较小的参数。所以样本参数必须做一些 scale 处理,最简单的方式就是所有特征的数值都采取归一化处置。
(3) 需要一个距离函数以计算两个样本之间的距离
knn算法常用所用公式:
Euclidean Distance(d)=(欧式距离)
ManhattanDistance(d)= (曼哈顿距离)
二、Knn算法具体实现案例:
基本思路:
本次实验我利用个人成绩数据集,对未知的个人成绩样本进行预测,这次总共分为三个等级:“excellent”(90-100),“good”(60-89),“fail”(任何一门低于60)。
采用Euclidean Distance(d)=(欧式距离)
数据集:
具体代码案例实现:
代码
from numpy import *
import math
# "ywodscroe"(语文平时成绩) "ywtscroe(语文期末成绩)" "sxodscroe(数学平时成绩)" "sxtsoe(数学期末成绩)" "grade(等级)"
temp = []
with open("C:/Users/HP_USER/Desktop/grqj.txt", encoding='gb18030',errors = 'ignore') as f:
for line in f.readlines():
line = line.strip('\n').split(' ') # 去掉列表中每一个元素的换行符
line.pop(0) # 去掉每行数据的"id"数据
temp.append(line)
# 最后用二维数组来存储数据集中的数据
dtype=object
testData = [] # 定义一个testData列表来接收用户输入的数据
ywodscroe = float(input('请输入:语文平时成绩'))
ywtscroe = float(input('请输入:语文期末成绩'))
sxodscroe = float(input('请输入:数学平时成绩'))
sxtscroe = float(input('请输入:数学期末成绩'))
testData.append(ywodscroe)
testData.append(ywtscroe)
testData.append(sxodscroe)
testData.append(sxtscroe)
distance = []
for item in cj:
# 计算数据集中每一个人数据和与用户输入的数据之间的距离(欧式距离)
result = math.sqrt((testData[0] - float(item[0]))**2 + (testData[1] - float(item[1]))**2
+ (testData[2] - float(item[2]))**2 + (testData[3] - float(item[3]))**2)
distance.append({
'data': result,
'species': item[4]
}) # 用一个字典来存储每一个人与用户输入的数据之间的距离和每个人的种类,
# 并将字典结果存储到distance列表中
for i in range(1, len(distance)): # 用冒泡排序算法根据每个人数据与用户输入的数据之间的距离对distance中的数据进行升序排序
for j in range(0, len(distance) - i):
if distance[j]['data'] > distance[j + 1]['data']:
temp = distance[j]
distance[j] = distance[j + 1]
distance[j + 1] = temp
k = 9 # 定义k-近邻算法中的k值为9
species = ["excellent", "good", "fail"] # 个人成绩分为三个等级
count = [0, 0, 0] # 用count列表存储距离最小的前k个数据中每个等级的人数
for i in range(0, k): # 统计前k个数据中每个等级的人数并存储到count列表中
if str(distance[i]['species']).replace('"', '') == 'excellent':
count[0] += 1
elif str(distance[i]['species']).replace('"', '') == 'good':
count[1] += 1
else:
count[2] += 1
max = 0
for i in range(1, 3): # 找出前k个数据中数量最多的等级,即为最终的分类结果
if count[i] > max:
max = i
print('预测您的等级为:'+species[max])
结果:
问题1:在实现的过程中,我也遇到了问题,显示“gbk”编码器无法解码字节,其字节序列为非法多字序列;
解决方案: encoding='gb18030',errors = 'ignore'(利用ignore忽视这些特殊字符)
问题2: 请求的数组在一维之后形状不均匀![](https://i-blog.csdnimg.cn/blog_migrate/01e174afb6a7a0d26010d1f1fc76f60e.png)
解决方案: 将cj = array(temp)改为cj = array(temp[0])
三、总结:
1、k的取值
knn实验中有一个关键点:k k的取值很大程度决定了实例的准确性,其实k值是KNN算法的一个超参数,k的含义即参考K取值较小时,模型复杂度(容量)高,训练误差会减小,泛化能力减弱;K取值较大时,模型复杂度低,训练误差会增大,泛化能力有一定的提高。如何选择k值,我们可以利用交叉验证不断尝试最优值,从选取一个较小的K值开始,不断增加K的值,然后计算验证集合的方差,最终找到一个比较合适的K值。
2、knn的局限性
适用数据范围是数值型和标称型,因此多数情况下,knn算法比较适用于样本容量比较大的类域的自动分类,而那些样本容量较小的类域采用这种算法就比较容易产生误分,且在样本不平衡的时候,对稀有类别的预测准确率十分低。同时在特征量十分多的时候,knn算法的计算量就非常多了。
参考文献:
K近邻(KNN)算法总结_ⅰl1、、knn.hnm.-CSDN博客
机器学习算法----KNN K邻近 (K值的选择) (学习笔记)_knn的k值如何选择_深度不学习!!的博客-CSDN博客
错误解决:ValueError: could not convert string to float-CSDN博客
Python中读取txt文本出现“ 'gbk' codec can't decode的解决方法_python gbk codec cant decode-CSDN博客