Python实现KNN分类算法:原理、优化与代码详解

Luna
Luna
发布时间:2026-10-16 | 4人浏览过
原创

本文详细介绍KNN(K近邻)分类算法的核心原理,包括距离度量与投票机制。深入探讨暴力法、K-D Tree及Ball-Tree的性能差异与适用场景,解决维度灾难问题。通过Python与scikit-learn完整代码示例,演示数据预处理、模型训练、网格绘制及结果评估,帮助读者掌握KNN在复杂分类边界下的应用技巧。

简介: 在人生旅程中,我们的选择塑造了最终的形态,生活的丰富性源于个人的努力与积累。当下的每一次投入,都在定义未来的自己;当无法改变外部环境时,调整自我便是最有力的行动。

KNN分类算法的介绍

KNN分类算法(K-Nearest-Neighbors Classification),又称K近邻算法,以其概念简洁且分类效果卓越而著称。

其核心逻辑在于:为确定测试样本的类别,需遍历所有训练样本,找出与该测试样本“距离”最近的前K个样本,并统计这K个样本中占比最高的类别,从而判定测试样本归属。简言之,即由最相似的K个样本通过投票决定最终分类。

文中所指的距离,通常采用多维空间中的欧氏距离。这里的维度对应特征维度,即样本包含多少个特征属性,便处于多少维空间中。

KNN示意图如下所示。(图片来源:百度百科)

上图中需确定测试样本(绿色点)应归类为蓝色还是红色。

观察可知,当K=3时,投票结果为1:2,样本被分类为红色;而当K=5时,投票结果为3:2,样本则被分类为蓝色。

KNN算法简单高效,但未优化的暴力搜索法易遇性能瓶颈。若样本数量为N,特征维度为D,则该算法的时间复杂度随O(DN)增长。

因此,KNN的实现通常会将训练数据构建为K-D Tree(K维树)。构建过程迅速,甚至无需计算D维欧氏距离,搜索速度可提升至O(D*log(N))。

然而,当D维度过高时,会引发所谓的“维度灾难”,导致效率下降至与暴力法相当的水平。

鉴于此,通常当D>20时,建议采用效率更高的Ball-Tree,其时间复杂度同样为O(D*log(N))。

长期实践表明,KNN算法虽简单,却能处理大规模数据分类,尤其适用于样本分类边界不规则的情况。更重要的是,该算法是许多高级机器学习算法的基础。

当然,KNN算法也存在固有缺陷。例如,若训练数据中某一类占绝大多数,投票机制可能失效。此时需考虑为每个投票者设计权重,以优化分类效果。

测试数据

测试数据格式与前文使用的身高体重数据一致,但数据量有所增加。

1.5 40 thin
1.5 50 fat
1.5 60 fat
1.6 40 thin
1.6 50 thin
1.6 60 fat
1.6 70 fat
1.7 50 thin
1.7 60 thin
1.7 70 fat
1.7 80 fat
1.8 60 thin
1.8 70 thin
1.8 80 fat
1.8 90 fat
1.9 80 thin
1.9 90 fat

Python代码实现

scikit-learn提供了优秀的KNN算法支持。

import numpy as np
from sklearn import neighbors
from sklearn.metrics import precision_recall_curve
from sklearn.metrics import classification_report
from sklearn.cross_validation import train_test_split
import matplotlib.pyplot as plt
 
''' 数据读入 '''
data = []
labels = []
with open("data\\1.txt") as ifile:
 for line in ifile:
  tokens = line.strip().split(' ')
  data.append([float(tk) for tk in tokens[:-1]])
  labels.append(tokens[-1])
x = np.array(data)
labels = np.array(labels)
y = np.zeros(labels.shape)
 
''' 标签转换为0/1 '''
y[labels=='fat']=1
 
''' 拆分训练数据与测试数据 '''
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size = 0.2)
 
''' 创建网格以方便绘制 '''
h = .01
x_min, x_max = x[:, 0].min() - 0.1, x[:, 0].max() + 0.1
y_min, y_max = x[:, 1].min() - 1, x[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, h),
   np.arange(y_min, y_max, h))
 
''' 训练KNN分类器 '''
clf = neighbors.KNeighborsClassifier(algorithm='kd_tree')
clf.fit(x_train, y_train)
 
'''测试结果的打印'''
answer = clf.predict(x)
print(x)
print(answer)
print(y)
print(np.mean( answer == y))
 
'''准确率与召回率'''
precision, recall, thresholds = precision_recall_curve(y_train, clf.predict(x_train))
answer = clf.predict_proba(x)[:,1]
print(classification_report(y, answer, target_names = ['thin', 'fat']))
 
''' 将整个测试空间的分类结果用不同颜色区分开'''
answer = clf.predict_proba(np.c_[xx.ravel(), yy.ravel()])[:,1]
z = answer.reshape(xx.shape)
plt.contourf(xx, yy, z, cmap=plt.cm.Paired, alpha=0.8)
 
''' 绘制训练样本 '''
plt.scatter(x_train[:, 0], x_train[:, 1], c=y_train, cmap=plt.cm.Paired)
plt.xlabel(u'身高')
plt.ylabel(u'体重')
plt.show()

结果分析

输出结果: [ 0. 0. 1. 0. 0. 1. 1. 0. 0. 1. 1. 0. 0. 1. 1. 0. 1.] [ 0. 1. 1. 0. 0. 1. 1. 0. 0. 1. 1. 0. 0. 1. 1. 0. 1.] 准确率=0.94, score=0.94 precision recall f1-score support thin 0.89 1.00 0.94 8 fat 1.00 0.89 0.94 9 avg / total 0.95 0.94 0.94 17

KNN分类器在众多分类算法中属于最简单的之一,需要注意的地方不多。有这几点要说明:

1、KNeighborsClassifier可设置3种算法:‘brute',‘kd_tree',‘ball_tree'。若不确定选用哪种,设置‘auto'让KNeighborsClassifier根据输入自动决定。

2、注意统计准确率时,分类器的score返回的是计算正确的比例,而非R2。R2通常应用于回归问题。

3、本例先根据样本中身高体重的最大最小值,生成了一个密集网格(步长h=0.01),然后将网格中的每一个点都当成测试样本去测试,最后使用contourf函数,使用不同的颜色标注出了胖、瘦两类。

容易看到,本例的分类边界,属于相对复杂,但却又与距离呈现明显规则的锯齿形。

这种边界线性函数是难以处理的。而KNN算法处理此类边界问题具有天生的优势。我们在后续的系列中会看到,这个数据集达到准确率=0.94算是很优秀的结果了。

到此这篇关于使用Python处理KNN分类算法的实现代码的文章就介绍到这了,更多相关Python KNN分类算法内容请搜索本站以前的文章或继续浏览下面的相关文章希望大家以后多多支持本站!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表