目录
2.1k-近邻算法
2.11k-近邻算法介绍
K-近邻算法(K Nearest Neighbor)又叫KNN算法,指如果一个样本在特征空间中的k个最相似的样本中的大多数属于某一个类别,则该样本也属于这个类别。也就是对于新输入的实例,从数据集中找到于该实例最邻近的k个实例,那么这k个实例大多数属于某一个类,那么就把该实例放到该类中。
KNN算法不仅可以用于分类,还可以用于回归。通过找出一个样本的k个最近邻居,将这些邻居的属性的平均值赋给该样本,就可以得到该样本的属性。
例如:在一个只有苹果和香蕉的果篮中,加入一个水果,当要判断这个水果是苹果还是香蕉的时候,只需要判断当前水果最贴近的水果的类别,即可判断该水果也属于这个类别之中。
2.12k-近邻算法流程
1.收集数据:
在前期收集数据的过程中,可以通过任何方式进行数据地收集,可以通过一般经验,也可以翻阅书籍,或是从在网上查阅资料。
2.准备数据:
完善数据集,包括特征和标签,每个样本都至少有一个或以上的特征,以及一个对于的标签,最好是结构化的数据格式。
3.分析数据:
当有了完善的数据集后,就可以开始综合考虑确定K值,即在分类的时候考虑邻居的数量(最靠近的点的数量)。
4.使用算法:
当确定K值后,就可以开始进行算法的使用,首先要将数据集(包括数据和标签)导入到python文件中。
接着在进行knn算法的时候,需要对已经准备好的数据进行归一化,将其单位统一,并将每个数据都归到0~1之间,归一化公式:
在进行归一化的时候,不仅需要对待测数据进行归一化,也要对数据集进行归一化。
当对待测数据和数据集归一化后,就可以开始使用欧氏距离计算待测数据与数据集中每个数据的距离并且根据k值来确定取前k个与待测数据最近的数据,求这些数据所对应的最多的标签并为标签就是待测数据的标签,待测距离公式:
x,y表示待测数据的两个标签,xi,yi表示数据集中的每个元素
最后,得到待测数据的标签后,需要对数据进行分析,进行关于本次KNN算法的总结。
2.13k-近邻算法简单实现水果分类
实验目的:
在本次knn算法中,主要是实现对两种水果,包括苹果、香蕉的分类,并取了水果的两种特征:直径和高度来判断。即拿来待测水果根据k近邻算法判断其属于哪一种水果类别中。
数据准备:
在本次数据集的准备过程中,是将数据集存入到文本文件之中,以“直径,高度,对应类别的形式”放入文本文件之中,当然也可以使用excel表格等方式存放数据集。同时,在导入数据前需要先创建Python文件,并导入对应的库,可以直接在anaconda中下载对应的包,并在编译器上使用conda的环境,就可以使用已经下载好的包。
import numpy as py
import matplotlib.pyplot as plt
import operator
matplotlib包:在最后实验后,可以根据matplotlib中的pyplot模块来进行散点图地绘制,可以更加直观地展示待测数据与数据集地距离关系。
operator包:在实验的过程中,可以使用operator迭代地获取前k个元素的标签出现次数,便于获取出现频率最多的标签。
numpy包:在实验中需要多次使用基于numpy包中成熟的函数库以及数组对象Array。
图一:数据准备
导入数据:
在进行算法之前将文本文件中的数据以及标签,导入到Python文件中,用两个列表对象来接收。根据数据和标签在文本文件中的存放方式来设计读取方式:以','进行分割,并且需要去除到读取一行文件内容结尾的换行符号'\n',将数据以直径、高度对应存入到data_set列表中,将标签存入到data_lables列表中,并将其返回。
# 数据集、标签
def data():
string_file = 'D:\Py_project\knn_project\data.txt'
data_set = []#数据集
data_labels = []#标签
with open(string_file,'r',encoding="UTF-8") as f:
for line in f:
list = line.split(",")
data_set.append([int(list[0]),int(list[1])])
data_labels.append(((str(list[2])).split('\n'))[0])
# 返回数据集和标签
return data_set,data_labels
数据处理:
对于导入进来的数据,对其进行归一化,首先通过获取数据集中每个属性的最大和最小值,指定(axis = 0),根据上述的归一化公式进行处理,重新的到符合条件的待测数据和数据集,并进行返回。在下述代码中,my_test即为待测数据,data_set即为数据集。
归一化公式
# 归一化
def normalize(my_test,data_set):
# 得到每个特征的最大值和最小值
min_vals = py.min(data_set, axis=0)
max_vals = py.max(data_set, axis=0)
# 对待测数据进行归一化
test_data = (my_test - min_vals) / (max_vals - min_vals)
# 对数据集进行归一化
set_data = (data_set - min_vals) / (max_vals - min_vals)
# 将归一化后的待测数据以及数据集进行返回
return test_data,set_data
图二:归一化后的数据展示
使用算法:
得到归一化后的数据,并传入对应的k值后,首先通过扩大待测数据的维度(便于相减得到后续的欧式距离),接着获取欧式距离根据公式,得到待测数据与数据集中每个数据的距离,并进行排序,得到与待测数据最近的k个数据。
欧氏距离
接着,以键值对的形式,将这k个数据以标签和出现次数作为键值对存入字典中,并通过sorted方法对字典中的数据,即对水果的标签出现的次数(利用operator迭代获取每个标签出现的次数)进行降序排序。
最后展示待测数据与数据集的散点图,并将求得的待测数据的标签进行返回,并输出结果
# 实现knn
def knn(in_test,data_set,data_labels,k):
# 扩大待分类数据维度
data_size = data_set.shape[0]
first_distance = (py.tile(in_test,(data_size,1)) - data_set) ** 2
# 得到欧式距离
second_distance = (first_distance.sum(axis = 1)) ** 0.5
# 排序
final_distance = second_distance.argsort()
data_dict = dict()
# 找到与待测数据最近的前k个数据
for i in range(k):
# 获取离测试数据最近的k个数据(根据下标获取其标签)
data_label = data_labels[final_distance[i]]
# 将获得到的标签以及出现的对应次数以键值对的方式放入字典中
data_dict[data_label] = data_dict.get(data_label,0) + 1
# 将字典进行排序(降序),返回出现最多次数的标签名称
sort_dict = sorted(data_dict.items(),key=operator.itemgetter(1),reverse=True)
plt.scatter(data_set[:, 0], data_set[:, 1], c='blue', label='data_set') # 绘制数据集散点图
plt.scatter(in_test[0], in_test[1], c='red', label='test_data') # 绘制待测数据散点图
# 横坐标是直径,纵坐标是高度
plt.xlabel('calibre')
plt.ylabel(' height')
plt.legend()
plt.show()
return sort_dict[0][0]
分类结果:
当输入待测数据的直径和高度后,即展示散点图,和输出该水果所属的类别,如下图
# 主方法
def main():
# 获取数据集以及标签
data_set,data_labels = data()
my_test = [int(input("请输入待分类水果的直径:\n")),int(input("请输入待分类水果的高:\n"))]
# 进行归一化
k = input("请指定实现knn算法的k值:\n")
test_data,set_data = normalize(my_test,data_set)
print('输入的数据所对应的水果类别是:{}'.format(knn(test_data,set_data,data_labels,k)))
测试一:
输入待测数据的直径为:65mm,高度为:45mm,指定此次knn算法取得k值为:3
图三:测试一运行结果
图四:实验结果1
测试二:
指定待测数据的直径为36mm,高度为128mm,k值为:5
图五:测试二运行
图六:实验结果2
2.14实验结果分析与总结
实验结果分析:
在本次通过基于水果分类的背景下对k-近邻算法进行了简单的实现,在上述的实验结果展示中,可以得到该算法是一个简洁明了的算法,原理较为简单易懂,预测结果较好,在给定的两组数据都能较为准确地得到待测数据的标签,并且拟合结果是比较好的。可以应用于多分类的问题中。
在本次实验中对于不同的k值的选取,对实验的影响是较大的,选取的k值较小,这样就会产生可能的第一种情况,即在数据集中哪个数据点靠近待测点,那么待测点就属于哪个类别,这样容易出现过拟合的现象。第二种情况,即当k值取得很大的时候,与待测点较远的数据也会对待测点产生结果地影响,这样可能会出现欠拟合的现象,因此在k近邻算法中对k值地选取地策略是至关重要的。
图七:不同k值所得结果的差异
基于上述实验可以得到几点knn算法的优缺点:
优点:
k-近邻算法容易理解,简单易懂,适用于多分类和大型数据集,可以用于离散型的数据中进行分类。
缺点:
k-近邻算法,由于要存储大量的数据,因此在训练时时间复杂度会达到O(n),当数据较大时,模型计算成本较高。k值对实验的影响较大,需要在实验前选取合适的k值,当出现不恰当的k值时,实验就可能会出现过拟合或者欠拟合的现象。在进行实验时,当某个类别的数据过少就会出现数据不平衡的问题。
实验结果总结:
在本次实验中,不但通过knn算法使自身对机器学习这门课程得到了微薄的认识,也在knn算法的实现过程中,提高了对python语言的掌握程度,更重要的是,在实验中理解了第一个机器学习算法,并学会了加以利用处理简易的水果分类的问题,在实现knn时,通过一步一步从收集数据到得到实验结果,不仅提高了自身的逻辑思维能力,也对k-近邻算法从书本的理解到利用python语言地实现,然而在实验中也存在较多的不足。
在实验中,没有能够设计一个更好的数据存放方式,以文本文件的方式存放始终显得不够直观,由于对python语言的掌握程度不高,因此选择了较为简单的数据存储方式。其次,在本次实验中数据的数量明显不够多,数据的类别较少,这样容易对实验产生较大的影响。通过这次实验,让自身认识到许多的不足和需要学习的地方。
总之,在本次实验中不仅学习到knn算法的利弊,实现了简单的分类的问题,希望后续能在实际应用中,根据具体场合和需求来利用knn算法求解更多问题,得到更多的提升和锻炼。