KNN算法简介
KNN(K-Nearest Neighbor) 最邻近分类算法时数据挖掘分类(classification)技术中最简单的算法之一,KNN算法用到的思想是,在相同范围内预测目标属于哪一类,看的就是范围内已知类别的数量大小,最多的则作为预测值。
KNN最邻近分类算法实现原理
为了判断位置样本的类别,以所有一直类别的样本作为参照,计算位置样本与所有一直样本的距离,从中选取与位置样本距离最近的K个已知样本,根据少数服从多数的投票法则,将位置样本与K个最临近样本中所属类别占比较多的归为一类。
以上就是KNN算法在分类任务中的基本原理,实际上K这个字母的含义就是要选取的最近邻近样本示例的个数。
K的取值决定了分类的结果。当K取值过小时,噪声成分对整体结果影响较大。
当K取值过大时,就意味着,及时离样本距离交院的点也对样本产生一定的影响,会造成预测结果的准确性降低。我们可以想象两个极端,当K取值为1时,模型整体会非常复杂,一旦最近的点是个噪声点,就意味着分类错误。当K取真个样本数时,那么分类的结果是一种先验概率,并不具有参考性。因此,k要选择恰当的取值。
KNN算法的关键
样本的所有特征都要做可比较的量化
若是样本特征中存在非数量的类型,必须采取手段将量化为数值。例如样本特征中包含颜色,可通过将颜色转换为灰度值来实现距离计算。
样本特征要做归一化处理
样本有多个参数,每个参数都有自己的定义域和取值范围,他们对距离计算的影响不一样,如取值较大的影响力会盖过取值较小的参数。所以样本参数必须做一些scale处理,最简单的方式就是所有特征的数量都采取归一化处置。
需要一个距离函数计算两个样本之间的距离
通常使用的距离函数有欧氏距离
、余弦距离
、汉明距离
、曼哈顿距离
等,一啊不能选欧式距离
作为距离度量,但是这是只适用于连续变量。在文本分类这种非连续变量清凉下,汉明距离
可以用来作为度量。通常情况下,如果运用溢写特殊的算法来计算氟利昂的话,K近邻分类精度可显著提高,如运用大边缘最近邻法或者近邻成分分析法。
K值的确定
K值选的太大易引起拟合,太小容易过拟合,需交叉验证确定K值。
KNN算法的优点
- 简单,容易理解,易于实现,无需估计参数。
- 适合对西游时间进行分类
- 特别适合与多分类问题(mulit-modal,对象具有多个类别标签)。
KNN算法的缺点
KNN算法在分类时有个主要的不足是,当样本不平衡时,如一个类的样本容量很大,而其他类样本容量很小时,有可能导致当输入一个新样本时,该样本的K个邻居中大容量类的样本站多数。该算法只计算最近的邻居样本,某一类的样本数量很大,那么或者这类样本并不接近目标样本,或者这列样本很靠近目标样本。无论怎样,数量并不能影响运行结果。可以采用权值的方法来改进。
花瓣参数判断花瓣种类的案例演示
图文解释
以随机取的10条数据为例
文件准备
链接:算法所用到的文件
提取码:lyq6
前期数据清洗准备
# 导入jar包
import numpy as np
import pandas as pd
# 读取csv文件 去除头部 默认 0 ,第一行,如果不去除头部,可以使用None
data = pd.read_csv("iris.csv",header=0)
# 对读取数据进行检验
# head 默认5行
data.head(10)
# 取最后20行
data.tail(20)
# 抽样方法
data.sample(10)
# 将文本类型转换成 数字类型
data["Species"] = data["Species"].map({"virginica":0,"setosa":1,"versicolor":2})
data.sample(10)
# 删除Id列 inplace设置为true,修改当前对象的值
data.drop("Id",axis=1,inplace=True)
# 判断是否有重复 False没有重复值 True有重复值
data.duplicated()
# 返回true以后表示有重复值
data.duplicated().any()
# 去除重复值
# 相当于矩阵去除线性相关
data.drop_duplicates(inplace=True)
data
data["Species"].value_counts()
KNN分类算法的编写
class KNN:
"""实现 KNN 临近算法 (分类)"""
def __init__(self,k):
"""
初始化方法
k : int
获取邻居的个数
self : 相当于java中的this,名字可以随便起
"""
self.k = k
def fit(self,X,y):
"""
训练数据
Parameter
X:类数组类型,形状为:【样本数量,特征数量】(表示矩阵)
训练样本特征(属性) 5.1,,3.5,1.4,0.2
y:类数组类型,形状为:【标签数量】(表示向量)
每个样本的目标值(标签) 1
"""
# 将X,y转化成np array
self.X = np.asarray(X)
self.y = np.asarray(y)
def predict(self,V):
"""根据样本传过来的属性,预测特征
X:类数组类型,形状为:【样本数量,特征数量】
result:数据类型
预测结果
"""
V = np.asarray(V)
result = []
# 对测试数据集进行遍历,取出每条数据与训练数据集合进行计算
for v in V:
#获取每一个测试集到每一个训练集的距离
dis = np.sqrt(np.sum((v - self.X)**2,axis=1))
#将距离dis进行排序(下标进行排序)
index = dis.argsort()
# 取出前k个距离最近的邻居
index = index[:self.k]
#根据index过去y中对应的特征值
count = np.bincount(self.y[index],weights= 1 /dis[index])
result.append(count.argmax())
#返回预测数据集合
return np.asarray(result)
训练数据集和预测数据集的准备
# 将data表数据按最后一列分类成三分数据
t0 = data[data["Species"]==0]
t1 = data[data["Species"]==1]
t2 = data[data["Species"]==2]
# 将数据按随机值打乱
t0 = t0.sample(len(t0),random_state=0)
t1 = t1.sample(len(t1),random_state=0)
t2 = t2.sample(len(t2),random_state=0)
# 取每类数据的前40条数据作为训练数据
train_X = pd.concat([t0.iloc[:40,:-1],t1.iloc[:40,:-1],t2.iloc[:40,:-1]],axis=0)
# 取每类数据的前40条数据的结果集作为训练结果集
train_y = pd.concat([t0.iloc[:40,-1],t1.iloc[:40,-1],t2.iloc[:40,-1]],axis=0)
# 取第40条以后的数据作为预测所需数据
test_X = pd.concat([t0.iloc[40:,:-1],t1.iloc[40:,:-1],t2.iloc[40:,:-1]],axis=0)
# 取第40条以后的数据的结果最为标准,与预测结果进行对比
test_y = pd.concat([t0.iloc[40:,-1],t1.iloc[40:,-1],t2.iloc[40:,-1]],axis=0)
创建KNN对象,预测算法的准确性
# 创建 KNN 对象
knn = KNN(k=3)
#训练数据
knn.fit(train_X,train_y)
#预测结果
result = knn.predict(test_X)
# 计算预测结果的正确个数
np.sum(result==test_y)
# 计算预测结果准确率
np.sum(result==test_y)/len(test_y)
可视化预测结果
# 导入可视化包
import matplotlib as mpl
import matplotlib.pyplot as plt
# matplotlib 不支持中文,需要配置一下,设置一个中文字体
mpl.rcParams["font.family"] = "SimHei"
# 能够显示 中文 ,正常显示 "-"
mpl.rcParams["axes.unicode_minus"] = False
绘制点状分布图
#设置画布大小
plt.figure(figsize=(10,10))
# SepalLengthCm,SepalWidthCm,PetalLengthCm,PetalWidthCm
# 绘制 点图,需要提供 x坐标 (花蕊的长度) y坐标 (花瓣的长度)
plt.scatter(x=t0["SepalLengthCm"][:40],y=t0["PetalLengthCm"][:40],color="r",label="virginica")
plt.scatter(x=t1["SepalLengthCm"][:40],y=t1["PetalLengthCm"][:40],color="g",label="setosa")
plt.scatter(x=t2["SepalLengthCm"][:40],y=t2["PetalLengthCm"][:40],color="b",label="versicolor")
# 测试数据集 test_y(待测试数据集 真实数据集) result(用KNN算法计算出来的数据集)
right = test_X[test_y == result]
wrong = test_X[test_y != result]
plt.scatter(x=right["SepalLengthCm"],y=right["PetalLengthCm"],color="c",label="right",marker="x")
plt.scatter(x=wrong["SepalLengthCm"],y=wrong["PetalLengthCm"],color="m",label="wrong",marker=">")
#plt.xlabel="花萼"
#plt.ylabel="花瓣"
#plt.title="KNN分类算法显示"
# 如果不显示重新启动jupyter
plt.xlabel('花萼')
plt.ylabel('花瓣')
plt.title('KNN分类算法显示')
plt.legend()
plt.show()
结果为: