分类算法之K-Nearest Neighbors
一:认识KNN算法
K-Nearest Neighbors又称为k最近邻算法。最初由Cover和Hart在1968年提出。属于Classification(分类)算法。Classification算法一般分为两个阶段,训练阶段和学习阶段
二:算法原理
通用步骤:
- 计算距离(常用欧式距离或马氏距离)
- 升序排列
- 取前k个
- 加权平均
k的选取:
- k太大:导致分类模糊
- k太小:手个例影响,波动较大
如何选取k:
- 经验
- 均方根误差
三:算法应用
-
简单KNN算法实现
python中的sklearn库为我们封装了KNN算法的实现方式
datasets是sklearn中的一个存放各类数据的模块,我们可以通过导入这个模块可以获取大量标准的数据进行练习。我们以鸢尾花数据为例。
数据解析:鸢尾花的共有4个属性,分别为sepal length 、sepal width 、 petal length 、 petal width, 通过属性的不同我们将鸢尾花分为了setosa、versicolor、virginica三类,分别用数字0、1、2表示。综上所述,4个属性为特征,类别为标签。
代码实现:
from sklearn.datasets import load_iris
from sklearn.neighbors import KNeighborsClassifier
# 获取数据
iris_data = load_iris()
print(iris_data)
# 将鸢尾花数据分为两组,取前100条数据为训练集,后100条数据为测试集
# 获取训练集的特征值和标签值
trans_feature = iris_data["data"][:100]
trans_label = iris_data["target"][:100]
# 获取测试集的特征值和标签值
test_feature = iris_data["data"][-100:]
test_label = iris_data["target"][-100:]
# 创建KNN模型对象,传入的参数相当于k值
KNN = KNeighborsClassifier(n_neighbors=7)
# 测试模型
KNN.fit(trans_feature,trans_label)
# 模型预测
KNN.predict(test_feature)
# 获取精度
precision = KNN.score(test_feature, test_label)
print(precision)
-
Cross Validation (交叉验证)
Cross Validation是一种评估模型性能的重要方法。主要用于在多个模型中(不同中模型和同一种类不同超参数组合)挑选出在当前问题场景下表现最优的模型
引入原因:
在训练集(train set)上训练得到的模型表现良好,但在测试集(test set)的预测结果不尽如人意,这就说明模型可能出现了过拟合(overfitting),在未知数据上的泛化能力差。
一个改进方案是,在训练集的基础上进一步划分出新的训练集和验证集(validate set),在新训练集训练模型,在验证集测试模型,不断调整初始模型(超参数等),使得训练得到的模型在验证集上的表现最好,最后放到测试集上得到这个最优模型的评估结果。
这个方案的问题在于模型的表现依赖于验证集的划分,可能使某些特殊样本被划入验证集,导致模型的表现出现异常(偏好或偏差)。而且训练集划了一部分给验证集后,训练模型能得到的数据就变少了,也会影响训练效果。因为通常来说,训练数据越多,越能反映出数据的真实分布,模型训练的效果就越好,越可能得到无偏估计。
交叉验证思想应运而生,交叉验证可以充分使用所有的训练数据用于评估模型。
-
K-fold(K折交叉验证)
k折交叉验证是最基本的cv方法,具体方法为,将训练集随机等分为k份,取其中一份为验证集评估模型,其余k-1份为训练集训练模型,重复该步骤k次,每次都取一份不同的子集为验证集,最终得到k个不同的模型(不是对一个模型迭代k次)和k个评分,综合这k个模型的表现(平均得分或其他)评估模型在当前问题中的优劣。
训练集和验证集的划分都在模块底层自动实现,我们只需要传入一个集合即可。
k值的选取很有讲究,选取适当大小的k很重要,经验值(empirical value)是k=10。
算法实现:
from sklearn.datasets import load_iris from sklearn.neighbors import KNeighborsClassifier from sklearn.model_selection import cross_val_score # 获取数据 iris_data = load_iris() # 实例化模型 KNN = KNeighborsClassifier(n_neighbors=7) # 提取特征值和标签 iris_features = iris_data["data"] iris_labels = iris_data["target"] # 交叉验证,返回模型每次的精度 score = cross_val_score(KNN,iris_features,iris_labels,cv=10) # 获取精度,精度一般取平均值 precision = score.mean() print(precision)
-
Leave one out(LOO)
LOO(留一法)每次在训练集的N个样本中选一个不同的样本作为验证集,其余样本为训练集,训练得到N-1个不同的模型。LOOCV是特殊的K-fold,当K=N时,二者相同。【不常用,了解即可】
-
-
网格搜索
网格搜索的目的主要是用来确定超参数k的值,CV是网格搜索的一种方法。
cv与网格搜索
通常情况下,有很多参数是需要手动指定的(如k-近邻算法中的K值),这种叫超参数。但是手动过程繁杂,所以需要对模型预设几种超参数组合。每组超参数都采用交叉验证来进行评估。最后选出最优参数组合建立模型。
scikit learn库中的GridSearchCV可以方便地尝试不同的超参数(hyper parameter),得到最优组合。GridSearchCV中的cv参数(默认为3-fold)利用交叉验证为某一超参数组合打出合理的评分。可以使用sklearn.model_selection.GridSearchCV(estimator, param_grid=None,cv=None)对估计器模型的指定参数值进行详尽搜索。其中estimator为模型对象,param_grid为k值的备选列表,cv为数据等分个数
GridSearchCV结果展示方法:
best_params_:返回最高精度对应的k值
best_score_:返回最高精度值
best_estimator_:返回最好的参数模型
代码实现:
from sklearn.datasets import load_iris from sklearn.neighbors import KNeighborsClassifier from sklearn.model_selection import GridSearchCV # 获取数据 iris_data = load_iris() # 获取特征值和标签 iris_features = iris_data["data"] iris_labels = iris_data["target"] # 实例化模型对象 KNN = KNeighborsClassifier() # 定义k值备选列表 params = {"n_neighbors":[i for i in range(10,30,2)]} # 实例化网格对象 gridcv = GridSearchCV(KNN,grid_param=params,cv=10) # 测试数据 gridcv.fit(iris_features,iris_labels) # 返回精度最高的参数 print(gridcv.best_params_) # 返回最高精度值 print(gridcv.best_scores_) # 返回最高精度模型
print(gridcv.best_estimator_)