1、引言
- k近邻法(k-nearest neighbor,kNN)是一种基本分类与回归方法,其基本做汝法是:给定测试实例,基于某种距离度量找出训练集中与其最靠近的k个实例点,然后基于这k个最近邻的信息来进行预测。
- 通常,在分类任务中可使用"投票法",即选择这k个实例中出现最多的标记类别作为预测结果;在回归任务中可使用"平均法",即将这k个实例的实值输出标记的平均值作为预测结果;还可基于距离远近进行加权平均或加权投票,距离越近的实例权重越大。
- k近邻法不具有显式的学习过程,事实上,它是懒惰学习(lazy.learning)的著名代表,此类学习技术在训练阶段仅仅是把样本保存起来,训练时间开销为零,待收到测试样本后再进行处理。
2、k邻三要素
距离度量、k值的选择、分类决策规则
距离度量
特征空间中的两个实例点的距离是两个实例点相似程度的反映。K近邻法的特征空间一般是n维实数向量空间Rn。使用的距离是欧氏距离,但也可以是其他距离,如更一般的Lp距离或Minkowski距离
k值的选择
k值的选择会对k近邻法的结果产生重大影响。在应用中,k值一般取双一个比较小的数值,通常采用交叉验证法来选取最优的k值
交叉验证
3、算法代码实现
- kNN算法没有什么训练,数据的清洗例如one-hot,标准或者归一。。算法难点在于
- 怎么找到距离最近的几个点
- 找到后,怎么根据这几个点来判断预测点的归属
- 如果你的待分类点和历史的每个点都算一遍距离,再找出距离最近的N各点,那么计算开销大。于是kd树产生了,这个是第一个难点。
- 你找到了N个最近的点,用什么办法来确定待分类点的类别,例如投票、加权投票,如何验证,这个是第二个难点。
- 另外几个在sklearn.neighbors包中但不是做分类回归预测的类也值得关注。
- kneighbors_graph类返回用KNN时和每个样本最近的K个训练集样才本的位置。
- radius_neighbors_graph返回用限定半径最近邻法时和每个样本在正限定半径内的训练集样本的位置。
- NearestNeighbors是个大杂烩,它即可以返回用KNN时和每个样本最近的K个训练集样本的位置,也可以返回用限定半径最近邻法时和每个样本最近的训练集样本的位置,常常用在聚类模型中。
调用方式
# 分类
sklearn.neighbors.KNeighborsClassifier(n_neighbors=5, weights='uniform', algorithm='auto', leaf_size=330, p=2, metric='minkowski', metric_params=None, n_jjobs=1, **kwargs)
# 回归
sklearn.neighbors.KNeighborsRegressor(n_neighbors=55, weights='uniform', algorithm='auto', leaf_size=369, p=2, metric='minkowski', metric_params=None, n_joobs=1, **kwargs)
参数解释
- n_neighbors:KNN中的k值,默认为5
- weights:标识每个样本的近邻样本的权重,可选择"uniform","distance"或自定义权重。
- 默认"uniform":所有最近邻样本权重都一样。
- "distance":权重和距离成反比例;如果样本的分布是比较成簇的,即各类样本都在相对分开的簇中时,我们用默认的"uniform"就可以了,如果样本的分布比较乱,规律不好寻找,选择"distance"是一个比较好的选择
- 如果都不好用,就自定义权重
- algorithm:限定半径最近邻法使用的算法,可选'auto', ball_tree''kd_tree','brute'。
- 'brute'对应第一种线性扫描
- 'kd_tree'对应第二种kd树实现
- 'ball_tree'对应第三种的球树实现
- 'auto'则会在上面三种算法中做权衡,选择一个拟合最好的最优算法
- leaf_size:这个值控制了使用kd树或者球树时,停止建子树的叶子节点数量的阈值
- 这个值越小,则生成的kc树或者球树就越大,层数越深,建树时间起城长
- 反之,则生成的kd树或者球树会小,层数较浅,建树时间较短。默认是30。
- 依赖于样本的数量,随着样本数量的增加,这个值必须要增加,否则不光建树预测的时间长,还容易过拟合。可以通过交叉验证来选择一个适中的值。
- metric,p:距离度量(前面介绍过),默认闵可夫斯基距离"minkowski"(p=1为曼哈顿距离,p=2为欧式距离)
- metric_params:距离度量其他附属参数,这个不管了
- njobs:并行处理任务数,主要用于多核CPU时的并行处理,加快建立KNN树和预测搜索的速度。njobs=-1,即所有的CPU核都参与计算。
4、KNN分类算法
from sklearn import datasets
from sklearn.neighbors import KNeighborsClassifier # 分类
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import cross_val_score # 交叉验证
from sklearn.model_selection import GridSearchCV #grid网格,search搜索,网格搜索最佳超参数
from sklearn.neighbors import KNeighborsRegressor # 回归
# 回归评估指标
from sklearn.metrics import explained_variance_score, mmean_absolute_error, mean_squared_error, median_absolute_error, r2_score
iris = datasets.load_iris() # 加载鸢尾花数据集
# print(iris.DESCR) # 输出数据集的信息,查看属性,数据集数量和种类
X=iris.data # 分离数据集的属性和标签,标签就是表明种类
Y=iris.target
print(X.shape) # 输出样本数量,属性数量
X_train,X_test,Y_train,Y_test = train_test_split(X,Y,test_size=1/3) # 2/3,100个训练,1/3,50个测试验证,每次结果不一样随机分类
#标准化
standardscaler=StandardScaler()
standardscaler.fit(X_train)
X_train=standardscaler.transform(X_train)
X_test=standardscaler.transform(X_test)
# KNN模型参数选择
#构造一些属性
params ={'n_neighbors':[i for i in range(1,15)], 'weights':['uniform','distance'], 'p':[1,2]}
#进行网格搜索
knn = KNeighborsClassifier()
grid = GridSearchCV(knn, params, scoring='accuracy', cv=6)
grid.fit(X_train, Y_train)
#预测准确率
print("在交叉验证当中最好的结果:",grid.best_score
print("选择最好的模型是:",grid.best_estimator_)
print("在测试集上准确率:",grid.score(X_test,Y_test))
# 结果
'''
(150, 4)
在测试集上准确率: 0.9
在交叉验证当中最好的结果: 0.97
选择最好的模型是:KNeighborsClassifier(algorithm='auto',leaf_size=30, metric='minkowski'
metric_params=None, n_jobs=1, n_neighbors=5, p=1, weights='distance')
'''
# print("每个超参数每次交叉验证的结果:",gcv.cv_ressults)
#knn算法流程
knn = grid.best_estimator_# 最好的模型赋给knn
knn.fit(X_train,Y_train) # fit用于训练
Y_pred=knn.predict(X_test) # predict用于预测