day01 KNN算法(K-近邻算法)


前言

K-近邻算法(K-Nearest Neighbors, KNN)是机器学习入门最经典的算法之一。

本文从零开始,系统性地介绍KNN算法的核心原理、关键参数(K值)的选择策略、两种核心距离度量公式(欧式距离与曼哈顿距离),并使用Python的Scikit-Learn库完成两个完整的实战项目:AI智能寝室分配系统鸢尾花分类

通过本文,你将不仅理解KNN的理论基础,更能掌握其在实际数据科学项目中的应用流程,为后续学习更复杂的机器学习模型打下坚实基础。

一、什么是KNN算法?

1.定义

全称是K-Nearest neighbors ,通过寻找k个距离最近的数据,来确定当前数据值的大小或者类别。是机器学习中最为简单和经典的一个算法。

目标检测:回归+分类

2. KNN算法的使用步骤

结合文章中的实战代码,KNN算法的完整使用流程可以分为以下5个步骤:

步骤1:导入所需库

首先需要导入KNN分类器以及数据处理相关的库:

import numpy as np
import pandas as pd
from sklearn.neighbors import KNeighborsClassifier

步骤2:加载并准备数据

将数据分为**特征变量(X)标签(y)**两部分。特征变量是用于判断的依据,标签是已知的分类结果:

# 以AI智能寝室分配系统为例
data = np.loadtxt('datingTestSet2.txt')
X = data[:, :-1]   # 特征:学生的各项性格指标
y = data[:, -1]    # 标签:学生的性格类别(1/2/3)

步骤3:创建KNN模型并训练

创建KNN分类器对象,设置邻居数量K值,然后使用 fit() 方法进行训练:

knn = KNeighborsClassifier(n_neighbors=3)  # 设置K=3
knn.fit(X, y)  # 模型学习特征与标签之间的对应关系

步骤4:使用模型进行预测

训练完成后,使用 predict() 方法对新样本进行分类预测:

# 单次预测
print(knn.predict([[42666, 13.276368, 0.543880]]))

# 批量预测
predict_data = [[5569, 4.875435, 0.728658], [65230, 9.972470, 0.881877]]
print(knn.predict(predict_data))

步骤5:评估模型性能

使用 score() 方法计算模型在测试集上的准确率,评估模型的泛化能力:

score = knn.score(data_test, test_y)  # 计算准确率
print(score)

以上5个步骤是KNN算法在sklearn中的标准使用流程,后面的「实战案例」部分将基于此流程展开两个完整的项目实践。

3. 如何选择K值?

K值的选择是KNN算法中最重要的参数调优环节,它直接影响模型的预测性能。

K值对模型的影响

  • K值过小(如K=1):模型只参考最近的一个邻居,容易受到噪声和异常值的干扰,导致过拟合——训练集上表现很好,但测试集上泛化能力差。
  • K值过大(如K=50):模型会参考大量远距离的样本,导致决策边界过于平滑,可能忽略数据的局部模式,造成欠拟合——模型过于简单,无法捕捉数据的真实分布。
  • K值适中:模型在偏差和方差之间取得平衡,既能利用局部信息,又对噪声有一定容忍度。

经验法则:通常K取训练样本数的平方根附近的值,且一般选择奇数(避免二分类时出现平票情况)。

二、KNN算法—距离公式

1.欧式距离(Euclidean Distance)

欧式距离是最常用的距离度量方法,用于计算多维空间中两点之间的直线距离。

对于 n 维空间中的两个点 PQ,其坐标分别为:

  • P = (p₁, p₂, …, pₙ)
  • Q = (q₁, q₂, …, qₙ)

它们之间的欧式距离公式为:

d ( P , Q ) = ∑ i = 1 n ( p i − q i ) 2 d(P, Q) = \sqrt{\sum_{i=1}^{n} (p_i - q_i)^2} d(P,Q)=i=1n(piqi)2

在二维空间中(即平面直角坐标系),公式简化为:

d = ( x 2 − x 1 ) 2 + ( y 2 − y 1 ) 2 d = \sqrt{(x_2 - x_1)^2 + (y_2 - y_1)^2} d=(x2x1)2+(y2y1)2

在三维空间中,公式为:

d = ( x 2 − x 1 ) 2 + ( y 2 − y 1 ) 2 + ( z 2 − z 1 ) 2 d = \sqrt{(x_2 - x_1)^2 + (y_2 - y_1)^2 + (z_2 - z_1)^2} d=(x2x1)2+(y2y1)2+(z2z1)2

在 KNN 算法中,通常使用欧式距离来计算样本点之间的距离,以找出最近的 K 个邻居。

2.曼哈顿距离(Manhattan Distance)

曼哈顿距离(Manhattan Distance)又称城市街区距离(City Block Distance),用于计算多维空间中两点在各坐标轴上的绝对轴距之和。

对于 n 维空间中的两个点 PQ,其坐标分别为:

  • P = (p₁, p₂, …, pₙ)
  • Q = (q₁, q₂, …, qₙ)

它们之间的曼哈顿距离公式为:

d ( P , Q ) = ∑ i = 1 n ∣ p i − q i ∣ d(P, Q) = \sum_{i=1}^{n} |p_i - q_i| d(P,Q)=i=1npiqi

在二维空间中(即平面直角坐标系),公式简化为:

d = ∣ x 2 − x 1 ∣ + ∣ y 2 − y 1 ∣ d = |x_2 - x_1| + |y_2 - y_1| d=x2x1+y2y1

在三维空间中,公式为:

d = ∣ x 2 − x 1 ∣ + ∣ y 2 − y 1 ∣ + ∣ z 2 − z 1 ∣ d = |x_2 - x_1| + |y_2 - y_1| + |z_2 - z_1| d=x2x1+y2y1+z2z1

在 KNN 算法中,曼哈顿距离常用于高维稀疏数据或特征尺度差异较大的场景,相比欧式距离对异常值更鲁棒。

💡 什么是「鲁棒」?
「鲁棒」是英文 Robust 的音译,意为稳健的、健壮的。在机器学习中,说一个算法「更鲁棒」,指它对异常值、噪声或数据波动不敏感,即使输入数据存在偏差或离群点,算法的表现依然稳定可靠。例如曼哈顿距离使用绝对值求和,相比欧式距离的平方求和,受单个异常值的影响更小,因此对异常值更鲁棒。


三、KNN算法–sklearn

1.Sklearn是什么?

Sklearn(Scikit-Learn)是基于Python语言的第三方机器学习库。它建立在Numpy,Scipy,Pandas和Matplotlib库之上,里面的API的设计非常好,所有对象的接口简单,适合新手。

2.Sklearn安装

在命令提示符中输入:

pip install scikit-learn -i https://pypi.tuna.tsinghua.edu.cn/simple

3.Sklearn的使用

使用sklearn官网API:https://scikit-learn.org/
knn算法的介绍 搜索k-nearest neighbors


四、实战案例

1. AI智能寝室分配系统

任务目标:将性格相似的学生分配在同一个寝室

1. 导入所需库

import numpy as np  # numpy是专门用于处理矩阵数据的库
from sklearn.neighbors import KNeighborsClassifier  # 从sklearn中导入KNN分类器

2. 加载并准备数据

# 使用numpy读取datingTestSet2.txt文件中的数据
# 该文件包含学生特征数据,最后一列为性格类别标签(1/2/3)
data = np.loadtxt('datingTestSet2.txt')

# 提取特征数据:取所有行的所有列,但不包含最后一列
# X 是特征矩阵,包含每个学生的各项性格指标
X = data[:, :-1]

# 提取标签数据:取所有行的最后一列
# y 是标签向量,表示每个学生的性格类别(1、2、3)
y = data[:, -1]

3. 创建并训练KNN模型

# 创建KNN分类器对象,设置邻居数量k=3
# n_neighbors=3 表示取距离最近的3个邻居,根据它们的类别进行投票(多数表决)
neight = KNeighborsClassifier(n_neighbors=3)

# 使用特征数据X和标签y对模型进行训练
# fit()方法会计算并存储所有训练样本的特征和标签
neight.fit(X, y)

4. 单次预测——测试模型效果

# predict()方法用于预测新样本的类别
# 传入的参数是一个二维数组,每个子数组代表一个新学生的特征数据
print(neight.predict([[42666, 13.276368, 0.543880]]))   # 预测结果:3
print(neight.predict([[44372, 4.391522, 0.807100]]))    # 预测结果:1
print(neight.predict([[14673, 0.460768, 0.689586]]))    # 预测结果:2

5. 批量预测——同时预测多个学生

# 准备一组待预测的学生数据,每个子列表包含3个特征值
predict_data = [
    [5569, 4.875435, 0.728658],    # 预期类别:2
    [65230, 9.972470, 0.881877],   # 预期类别:1
    [36788, 12.458258, 0.649517],  # 预期类别:3
    [7917, 3.007578, 0.297302],    # 预期类别:2
    [22329, 2.262014, 1.022169],   # 预期类别:1
    [38768, 5.308408, 0.030683],   # 预期类别:3
    [10933, 0.000000, 0.107476]    # 预期类别:2
]

print("再次多人同时预测")
print(neight.predict(predict_data))

2. 鸢尾花分类

1. 导入所需库并读取数据

import pandas as pd  # numpy可以读二维数据,pandas可以处理表格类型的数据

# 读取数据
# train_data:训练集
# test_data:测试集
# numpy:数组形式读取数据;pandas:以表格形式读取数据
train_data = pd.read_excel("鸢尾花训练数据.xlsx")
test_data = pd.read_excel("鸢尾花测试数据.xlsx")

2. 处理训练集数据——变量与标签分离

# 将特征变量与标签分离
train_X = train_data[['萼片长(cm)', '萼片宽(cm)', '花瓣长(cm)', '花瓣宽(cm)']]
train_y = train_data[['类型_num']]

3. 对训练数据进行标准化处理

"""
标准化方法说明:
1. 归一化:将数据缩放到 0~1 范围,对每个列(特征)分别进行
2. Z-Score标准化:将数据减去均值并除以标准差,结果通常在 -5~5 范围
"""
from sklearn.preprocessing import scale  # 对输入数据进行去均值并除以标准差的操作

data = pd.DataFrame()
data['萼片长标准化'] = scale(train_X['萼片长(cm)'])
data['萼片宽标准化'] = scale(train_X['萼片宽(cm)'])
data['花瓣长标准化'] = scale(train_X['花瓣长(cm)'])
data['花瓣宽标准化'] = scale(train_X['花瓣宽(cm)'])
# 数据预处理的目标是让每个特征的数据都在差不多大小的范围内

4. 创建并训练KNN模型

from sklearn.neighbors import KNeighborsClassifier

knn = KNeighborsClassifier(n_neighbors=2)  # 设置邻居数量k=2
knn.fit(data, train_y)  # 使用标准化后的训练数据训练模型

5. 使用训练数据进行自测评估

train_predicted = knn.predict(data)  # 用训练数据自测预测
score = knn.score(data, train_y)     # 计算模型得分:将data传入模型预测,将预测结果与train_y比较
print(score)

6. 准备测试集数据并标准化

# 提取测试集的特征和标签
test_X = test_data[['萼片长(cm)', '萼片宽(cm)', '花瓣长(cm)', '花瓣宽(cm)']]
test_y = test_data[['类型_num']]

# 对测试集进行Z-Score标准化
from sklearn.preprocessing import scale
data_test = pd.DataFrame()  # 传入全新的测试数据,从未传入过模型

data_test['萼片长标准化'] = scale(test_X['萼片长(cm)'])
data_test['萼片宽标准化'] = scale(test_X['萼片宽(cm)'])
data_test['花瓣长标准化'] = scale(test_X['花瓣长(cm)'])
data_test['花瓣宽标准化'] = scale(test_X['花瓣宽(cm)'])

7. 使用测试集进行预测并评估

# 预测测试集结果
test_predicted = knn.predict(data_test)
score = knn.score(data_test, test_y)  # 计算模型在测试集上的得分
print(score)

# # 预测概率(可选)
# test_predicted_pr = knn.predict_proba(data_test)
# print(test_predicted_pr)

总结

本文系统学习了KNN算法的三大核心板块:

  1. 算法原理:KNN通过寻找K个最近邻居进行投票分类,K值的选择直接影响模型性能——K过小易过拟合,K过大易欠拟合。
  2. 距离度量:欧式距离(直线距离)和曼哈顿距离(轴距之和)是KNN最常用的两种距离计算方式,后者对异常值更鲁棒。
  3. sklearn实战:完成了智能寝室分配和鸢尾花分类两个项目,掌握了从数据准备、模型训练到预测评估的完整流程。

更多推荐