目录
1.概述
KNN的原理非常简单明了,根据离样本最近的
k
k
k个点的标签来决定样本的类别或值。既可以用来分类,也可以进行回归。
分类:多数表决。在数据集中,找出与样本特征最近的
k
k
k个数据点,这些数据点中占比最多的类别即为要预测的样本的类别。
回归:取平均值。在数据集中,找出与样本特征最近的
k
k
k个数据点,取它们的平均值作为样本的预测值。
2.算法流程
(1)计算距离
计算样本与训练集中每个点的距离。一般使用欧式距离,向量
x
,
y
\mathbf{x,y}
x,y的欧式距离为:
D
(
x
,
y
)
=
∑
i
=
1
n
(
x
i
−
y
i
)
2
D(\mathbf{x,y})=\sqrt{\sum_{i=1}^{n}(\mathbf{x}_{i}-\mathbf{y}_{i})^{2}}
D(x,y)=i=1∑n(xi−yi)2
其中,
n
n
n为每个样本的维度。
(2)选择最近邻点
选择距离样本点最近的 k k k个点, k k k值的选择应该多次尝试,因为当 k k k较小时,容易发生过拟合;当 k k k较大时,模型简单,容易加大预测误差。
(3)预测
如果是分类,多数表决;如果是回归,输出为最近 k k k个类别的平均值。
3.KNN优化之KD树
如果每次预测都需要计算每个样本的距离,则无疑计算量是巨大的。为了减少计算,这里给出KD树在KNN中的应用。
(1)KD树之建树
建树依据为维度方差最大化:
数据有
n
n
n个维度,依次计算各个维度的方差。选择方差最大的维度
n
i
n_{i}
ni,在所有样本的此维度中寻找中位数;假设中位数为10,将其他样本中维度
n
i
n_{i}
ni的值小于10的划入左子树,大于10的划入右子树。递归建树直到最后一个维度。
(2)KD树之搜索
样本
x
\mathbf{x}
x的预测过程:
根据维度划分,首先找到样本
x
\mathbf{x}
x对应的叶子节点,以样本
x
\mathbf{x}
x和叶子结点的距离为半径做超球体,最近邻的点一定在这个超球体内部。返回叶子节点的父节点,检查父节点的另一个节点的超矩形和这个超球体是否相交,相交的话在这个矩形内寻找是否有更近的节点,有的话跟新最近邻;不相交的话继续返回上一层的父节点,重复以上步骤直到根节点。
4.sklearn实现KNN
(1)数据预处理
导入数据集,划分训练集、测试集,标准化
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
iris = load_iris()
x,y=iris.data,iris.target
x_train,x_test,y_train,y_test=train_test_split(x,y)
std = StandardScaler()
x_train=std.fit_transform(x_train)
x_test = std.fit_transform(x_test)
print(x_train.shape,x_test.shape)
输出:
(112, 4) (38, 4)
(2)预测和评价
KNN模型的K值设为3:
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score
model = KNeighborsClassifier(n_neighbors=3)
model.fit(x_train,y_train)
y_pred = model.predict(x_test)
print(accuracy_score(y_pred,y_test))
输出:
0.8421052631578947
(3)网格搜索
使用网格搜索、交叉验证选择合适的K值
from sklearn.model_selection import GridSearchCV
parameters={'n_neighbors':[1,3,5,10,20,50]}
model2 = KNeighborsClassifier()
cvModel=GridSearchCV(model2,parameters,cv=5)
cvModel.fit(x_train,y_train)
print(cvModel.best_score_)
print(cvModel.best_params_)
输出:
0.9727272727272727
{'n_neighbors': 10}