近邻算法——K-NearestNeighbor
如果一个待分类样本在特征空间中的k个最相似(即特征空间中K近邻)的样本中的大多数属于某一个类别,则该样本也属于这个类别,即近朱者赤,近墨者黑,这是一种监督学习。
例如:
在黑实线的圆圈内(只选3个邻居),有两个红三角一个蓝方块,那么系统认为?就是红三角
在黑虚线的圆圈内(只选5个邻居),有两个红三角三个蓝方块,那么系统认为?就是蓝方块
-
所以定的邻居数(n_neighbors)会影响最终的判断
注意:n_neighbors过大会使训练模型欠拟合(过于粗糙,不论是当前训练集还是之后测试集表现都不好),过小会使训练模型过拟合(可能在训练集很准确,但是在新的测试集表现很差) -
此外,距离度量的方式也有较大的影响,距离一般使用欧式距离或者曼哈顿距离
可以看出,欧氏距离是闵可夫斯基距离在 p=2时的特例,而曼哈顿距离是 p=1时的特例。
下面举上2个案例
鸢尾花实验
# 近邻算法
import numpy as np
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import cross_val_score
from sklearn.datasets import load_iris
import matplotlib
import matplotlib.pyplot as plt
if __name__ == '__main__':
#系统自带有鸢尾花数据
datas = load_iris()
#获取训练集(真正要训练的数据)和目标结果集(分类的结果)
tarin, target = datas.data, datas.target
# 为了知道n_neighbors取多少合适,我们要在一定范围内取值去测试
#这里我训练1~33使,训练结果的正确率
x = np.arange(1, 33)
y = []
for num in x:
#设置n_neighbors数
knn = KNeighborsClassifier(n_neighbors=num)
# 模型评估(交叉验证)
# cv=10代表9份训练1份测试
# scoring='accuracy'表示9次训练中每次的准确率
arrmodel = cross_val_score(knn, tarin, target, cv=10, scoring='accuracy')
# 9次训练结果准确率的平均值
avgmodel = arrmodel.mean()
#1~33次每次都放到y中
y.append(avgmodel)
print(y)
# 设置中文
matplotlib.rcParams['font.sans-serif'] = ['SimHei']
# 设置折线图
plt.plot(x, y, 'pink')
#加数字
for x1, y1 in zip(x, y):
plt.text(x1, y1, str(x1), ha='center', va='bottom', fontsize=12, rotation=0)
plt.show()
x轴就是n_neighbors数,y就是准确率,从图中看到13、18、20正确率比较高,那么下次我们就让n_neighbors等于这些数,然后做后面测试集的预测分类就会比较准确
手写数字识别
上面是我准备的数据,.前面的数字表示我们的数字(也就是真正的分类结果),后面的表示这个数字有多少个训练数据,一共0~ 9,每个数字3000~4000的量
import matplotlib.pyplot as plt
import cv2
from sklearn.model_selection import cross_val_score
from sklearn.neighbors import KNeighborsClassifier
if __name__ == '__main__':
# 训练集数组和训练目标数组(分类结果)
tarin, target = [], []
#
new=[]
# 利用循环读入0-9的每个3000张图片
#num表示分类结果
for num in range(10):
#flag表示每个分类中取都多少个数据进行训练
for flag in range(300):
target.append(num)
#opencv去读取图片,会变成二维数组
digit = cv2.imread("C:/Users/wuyanxiang/study/python/chenming/mnist_data/" + str(num) + "." + str(flag) + ".jpg")
#将数组内RGB只拿第一个R值,否则RGB每个值都要计算,工作量太大
res = digit[:, : , 0].reshape(784)
#二值化,避免不同灰度值的影响
for rn in range(len(res)):
res[rn]=0 if res[rn]<128 else 255
#放进训练数组里
tarin.append(res)
#看工作进度
print("--------"+str(num))
#==================================
#训练完后6效果最好
# x = range(1, 55)
# y = []
# for k in x:
# knn = KNeighborsClassifier(n_neighbors=k)
# 准确率
# val = cross_val_score(knn, tarin, target, cv=20, scoring="accuracy").mean()
# print("========"+k)
# y.append(val)
# plt.plot(x, y)
# plt.show()
# ==================================
#weights='distance' 给每个邻居到点一个权重,距离越近权重越大,这样更合理
#p=2 使用的是欧氏距离
#n_jobs=-1 开启全核
knn = KNeighborsClassifier(n_neighbors=6,weights='distance',p=2,n_jobs=-1)
#正确率
res = cross_val_score(knn, tarin, target, cv=20, scoring="accuracy").mean()
#真正训练模型
knn.fit(tarin,target)
#对图片进行识别
#test测试数据 test_target真正分类结果
test,test_target=[],[]
for rn in range(10):
for co in range(300,310):
test_target.append(rn)
digit = cv2.imread("C:/Users/wuyanxiang/study/python/chenming/mnist_data/" + str(rn) + "." + str(co) + ".jpg")
res = digit[:, :, 0].reshape(784)
test.append(res)
#预测结果
pre=knn.predict(test)
print("-------预测结果")
print(pre)
print("-------真实结果")
print(test_target)
--------0
--------1
--------2
--------3
--------4
--------5
--------6
--------7
--------8
--------9
-------预测结果
[0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 3 3 3 3 3 5 3
3 3 3 4 4 1 4 4 4 4 4 9 4 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 7 7 7 7
1 7 7 7 7 7 8 3 3 6 8 5 8 8 8 8 7 7 9 9 9 9 9 9 9 9]
-------真实结果
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9]