一、题目要求
KNN(K Near Neighbor):k个最近的邻居,即每个样本都可以同他最接近的k个邻居来代表。
KNN算法是一种分类算法,该算法思想是一个样本与数据集中的k个样本最相似,如果k个样本的大多数属于某一个类别,则该样本也属于这个类别。
二、算法分析
在选择两个实例相似性时,一般是用的欧式距离:
对于k值的选择,如果选择较小的K值,就相当于用较小的邻域中的训练实例进行预测,学习的近似误差会减小,只有与输入实例较近的训练实例才会对预测结果起作用,单缺点是学习的估计误差会增大,预测结果会对近邻的实例点分成敏感。如果邻近的实例点恰巧是噪声,预测就会出错。换句话说,K值减小就意味着整体模型变复杂,分的不清楚,就容易发生过拟合。
如果选择较大K值,就相当于用较大邻域中的训练实例进行预测,其优点是可以减少学习的估计误差,但近似误差会增大,也就是对输入实例预测不准确,K值得增大就意味着整体模型变的简单。
三、代码分析
导入项目所需的包,以及定义训练集、测试集和所需的k值
import math
import random
import matplotlib.pyplot as plt
data_train=[]
data_test=[]
k_near_by=5
limit=math.ceil(k_near_by/2)
制作数据的函数,在训练集中数据被分为5类,每类个10组数据,再在测试集中添加30组测试数据,所有数据都由随机生成。
def make_data():
"""
制作数据
"""
for p in range(1,5):
x=random.random()*20
y=random.random()*20
for i in range(10):
x_shift=random.random()*5
y_shift=random.random()*5
data_train.append([x+x_shift,y+y_shift,p])
for p in range(30):
x=random.random()*20
y=random.random()*20
data_test.append([x,y,0])
这里我们还可以通过skitlearn的包导入鸢尾花的数据进行数据的制作
def make_data_from_iris():
"""
从数据集中导入鸢尾花数据
"""
iris_dataset = load_iris()
iris_data_train=iris_dataset['data'][::5]
iris_tag_train=iris_dataset['target'][::5]
iris_data_tag_train=[]
for i in range(30):
iris_data_tag_train=[iris_data_train[i][0],iris_data_train[i][1],iris_tag_train[i]]
data_train.append(iris_data_tag_train)
iris_data_test=iris_dataset['data'][1::15]
iris_tag_test=iris_dataset['target'][1::15]
iris_data_tag_test=[]
for i in range(10):
iris_data_tag_test=[iris_data_test[i][0],iris_data_test[i][1],0]
data_test.append(iris_data_tag_test)
data_test_origin.append(iris_data_tag_test)
计算距离函数,返回欧式距离的平方
def dis(a,b):
"""
a,b传入列表 格式为:[x,y,*]
计算距离
"""
return ((a[0]-b[0])**2+(a[1]-b[1])**2)
当传入一个数据时,获取它的第一个元素,用于获取在标签时获取距离
def takefirst(elem):
return elem[0]
分类函数,将传入的数据分类并附上标签,先将训练集的数据转换为一个字典,并将每个数据分类的个数更新为字典对应键的值
def make_tag(t):
"""
t:传入列表 格式为[x,y,0]
分类标签,标签为0表示不分类
"""
min_dix=[]
for i in data_train:
min_dix.append([dis(i,t),i[2]])
min_dix.sort(key=takefirst)
tag_dact={}
for i in range(k_near_by):
if min_dix[i][1] not in tag_dact:
tag_dact.update({min_dix[i][1]:1})
else:
tag_dact[min_dix[i][1]]+=1
for kv in tag_dact.items():
if kv[1] > limit:
return kv[0]
return 0
调用函数并进行分类,调用matplotlib将散点图画出
make_data()
for i in range(len(data_test)):
data_test[i][2]=make_tag(data_test[i])
"""
可视化部分
"""
point_dict={
0 : 'H',#错误
1 : '.',
2 : ',',
3 : 'o',
4 : 'v',
5 : '^',
6 : '<',
}
color_dict={
0 : 'y', # 错误
1 : 'b',
2 : 'c',
3 : 'g',
4 : 'k',
5 : 'm',
6 : 'r',
}
plt.figure(1,dpi=80)
ax1=plt.subplot(221)
ax2=plt.subplot(222)
ax3=plt.subplot(223)
for i in data_train :
plt.sca(ax1)
plt.scatter(i[0],i[1],c=color_dict[i[2]],marker=point_dict[i[2]])
for i in data_train :
plt.sca(ax3)
plt.scatter(i[0],i[1],c=color_dict[i[2]],marker=point_dict[i[2]])
for i in data_test :
plt.sca(ax2)
plt.scatter(i[0],i[1],c=color_dict[i[2]],marker=point_dict[i[2]])
for i in data_test :
plt.sca(ax3)
plt.scatter(i[0],i[1],c=color_dict[i[2]],marker=point_dict[i[2]])
plt.show()
exit(0)
四、运行结果
五、总结分析
Knn算法是机器学习中用于分类的基本算法,不是只考虑最近的点,而是通过该点周围的一定数量的邻居点,并通过邻居点的类别来判断改点的类别。Knn算法k值的选择十分重要,k值较小,说明整体模型变复杂,预测结构会对邻近的干扰产生较大的误差,容易发生过拟合;而k值较大时,说明整体模型变简单,使得对输入实例预测不准确,容易产生欠拟合。