K近邻算法(K-Nearest Neighbor,KNN)是最简单的机器学习算法之一,易于理解和实现。它主要用于分类和回归任务。KNN的输入是实例的特征向量,通过计算新数据与已有数据特征值之间的距离,选取K(K≥1)个最近的邻居进行分类或回归判断。如果K=1,新数据会被直接分配给最近的邻居。
在分类任务中,输入的是实例的类别。对于新的实例,根据其K个最近邻的训练实例类别,采用多数表决的方式进行预测。
在回归任务中,输入的是实例的数值。对于新的实例,取其K个最近邻的训练实例数值的平均值作为预测值。
KNN算法没有显式的训练过程,而是直接进行预测。实际上,它利用训练数据集对特征空间进行划分,并将这种划分作为模型的一部分。
KNN算法包含三个关键要素:K值的选择、距离度量以及分类决策规则。K值越小,模型越复杂,但可能过拟合;K值越大,模型越简单,但可能会忽略局部细节。常用的距离度量方法是欧氏距离。分类决策规则通常包括权重分配,其中均匀权重(uniform)和距离权重(distance)是最常见的两种方法。在实际应用中,通常通过交叉验证来确定最优的K值。
KNN算法在处理大量训练数据时,线性扫描方法效率较低。因此,引入kd树来加速搜索过程。kd树是一种二叉树结构,通过递归分割空间来构建。kd树的构建步骤包括创建根节点、不断切分域直至所有节点的子域中没有样本为止。
KNeighborsClassifier类提供了多种参数来定制KNN算法的行为。以下是主要参数及其说明:
以下是一些示例代码,演示如何使用KNeighborsClassifier进行分类和评估。
```python from sklearn.datasets import loaddigits from sklearn.modelselection import traintestsplit import numpy as np import matplotlib.pyplot as plt
def loaddigitsdata(): digits = loaddigits() # 分层采样 return traintestsplit(digits.data, digits.target, testsize=0.25, random_state=0, stratify=digits.target)
def testKNerghborsClassifier(xtrain, xtest, ytrain, ytest): cls = KNeighborsClassifier() cls.fit(xtrain, ytrain) print("KNerghbors training score set is: {:.3f}".format(cls.score(xtrain, ytrain))) print("KNerghbors test score set is: {:.3f}".format(cls.score(xtest, y_test)))
def testKNeighborsClassifierkw(xtrain, xtest, ytrain, ytest): ks = np.linspace(1, ytrain.size, num=100, endpoint=False, dtype='int') weights = ['uniform', 'distance'] fig, ax = plt.subplots() for weight in weights: trainingscores = [] testingscores = [] for k in ks: cls = KNeighborsClassifier(weights=weight, nneighbors=k) cls.fit(xtrain, ytrain) trainingscores.append(cls.score(xtrain, ytrain)) testingscores.append(cls.score(xtest, ytest)) ax.plot(ks, trainingscores, label=f"KNeighbors training score: weight={weight}") ax.plot(ks, testingscores, label=f"KNeighbors test score: weight={weight}") ax.legend(loc='best') ax.setxlabel("K value") ax.setylabel("score value") ax.setylim(0, 1.05) ax.set_title("KNeighbors") plt.show()
def testKNeighborsClassifierkp(xtrain, xtest, ytrain, ytest): ks = np.linspace(1, ytrain.size, num=100, endpoint=False, dtype='int') ps = [1, 2, 8] fig, ax = plt.subplots() for p in ps: trainingscores = [] testingscores = [] for k in ks: cls = KNeighborsClassifier(p=p, nneighbors=k) cls.fit(xtrain, ytrain) trainingscores.append(cls.score(xtrain, ytrain)) testingscores.append(cls.score(xtest, ytest)) ax.plot(ks, trainingscores, label=f"KNeighbors training score: p={p}") ax.plot(ks, testingscores, label=f"KNeighbors test score: p={p}") ax.legend(loc='best') ax.setxlabel("K value") ax.setylabel("score value") ax.setylim(0, 1.05) ax.set_title("KNeighbors") plt.show()
xtrain, xtest, ytrain, ytest = loaddigitsdata() testKNerghborsClassifier(xtrain, xtest, ytrain, ytest) testKNeighborsClassifierkw(xtrain, xtest, ytrain, ytest) testKNeighborsClassifierkp(xtrain, xtest, ytrain, y_test) ```
通过上述实验可以看出,权重参数(uniform 和 distance)对预测效果有显著影响。均匀权重在K值较大时,预测效果较为稳定,而距离权重则在K值较小时表现更好。参数p值的变化对预测效果的影响较小,这表明曼哈顿距离和欧氏距离对分类器的预测效果影响不大。