K近邻算法是一种基本分类与回归方法。分类时,对新的实例,根据其k个最近邻的训练实例的类别,通过多数表决的方式进行预测。因此,K近邻法不具有显式的学习过程。
K近邻算法(K-nearest neighbor)
K近邻算法简单、直观:给定一个训练数据集,对新的输入实例,在训练数据集中找到与该实例最近邻的K个实例,这K个实例的多数属于某个类,就把该输入实例分为这个类。k值的选择、距离度量及分类决策规则是K近邻算法的三个基本要素。
一、k值的选择
k值的选择会对近邻法的结果产生重大影响。如果选择较小的K值,就相当于用较小的邻域中的训练实例进行预测,“学习”的近似误差会减小,只有与输入实例较近的训练实例才会对预测结果起作用,但缺点是“学习”的估计误差会增大,预测结果会对近邻的实例点非常敏感,如果近邻的实例点恰巧是噪声,预测就会出错,换句话说,k值的减小意味着整体模型变得复杂,容易过拟合。
如果选择较大的k值,就相当于用较大邻域的训练实例进行预测,其优点是减少学习到的估计误差,但缺点是学习到的近似误差会增大。这时与输入实例较远的训练实例也会对预测产生影响,K值的增大意味着整体的模型变得简单。
通常采用交叉验证法来选择最优的K值。
二、距离度量
欧式距离
特征空间中两个实例点的距离是两个实例点相似程度的反映,K近邻模型的特征空间一般是n维实数向量空间,使用的距离是欧式距离,但也可以是其他距离,如闵可夫斯基(Minkowski distance)距离。闵可夫斯基距离的表达式为:
L
p
(
x
i
,
x
j
)
=
(
∑
i
=
1
n
∣
x
i
l
−
x
j
l
∣
p
)
1
p
L_p\left( x_i,x_j \right) =\left( \sum_{i=1}^n{\left| {x_i}^l-{x_j}^l \right|^p} \right) ^{\frac{1}{p}}
Lp(xi,xj)=(i=1∑n∣∣xil−xjl∣∣p)p1
当p=2时,该式称为欧式距离;
当p=1时,该式称为曼哈顿距离;
当p=∞时,该式称为切比雪夫距离(chebyshev distance)
代码如下(示例):
三、k近邻算法的实现
实现k近邻算法时,除了考虑K值的选择以外,更要考虑如何对训练集进行快速K近邻搜索。首先想到的是使用穷举法,计算新实例点到训练集中每个实例点的距离。这种方式在训练数据集较小时可行,但是当训练数据集特别大时,此方法的缺点也很明显-计算非常耗时。为了提高K近邻算法的效率,有了kd树这种方法 产生。对于KD树的详细知识不作介绍,这里直接调用sklearn中的kd树,并实现用k近邻算法预测新实例点的类别:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.datasets import make_blobs
from sklearn.metrics import confusion_matrix#混淆矩阵
from sklearn.neighbors import KDTree
from collections import Counter##计数功能
import seaborn as sn
np.random.seed(2)
X, Y = make_blobs(n_samples=100,n_features=2,centers=4)
x_train,x_test,y_train,y_test = train_test_split(X,Y,test_size=0.2)
plt.scatter(x_train[:,0],x_train[:,1],c=y_train)
plt.scatter(x_test[:,0],x_test[:,1],marker='*',c=y_test)
plt.show()
class KNN:
def __init__(self):
pass
def predict(self,x_train,y_train,x_test):
''' 预测函数'''
kdtree=KDTree(x_train,leaf_size=2)
pred_y=[]
for i in range(len(x_test)):
index=kdtree.query([x_test[i]],k=6)[1]#kdtree.query(node,k=n)方法返回距离node最近的n个点的距离和对应点的索引,这里只用索引
target=[]
[target.append(y_train[i]) for i in index]
target=np.array(target).flatten()
max_num=Counter(target).most_common(1)[0][0]
pred_y.append(max_num)
return pred_y
model=KNN()
pred_y=model.predict(x_train,y_train,x_test)
sn.heatmap(confusion_matrix(y_test,pred_y), annot=True)
参考
统计学习方法-李航