【数学建模学习笔记】机器学习分类:KNN分类

KNN 分类算法详解(Python 实现)

KNN(K 近邻)算法是机器学习中最简单的监督学习分类算法之一。本文将为初学者详细解释 KNN 的原理和实现过程,并通过实际代码示例帮助理解。

什么是 KNN 算法?

KNN 的核心思想非常简单:物以类聚,人以群分。当我们要对一个新样本进行分类时,只需看看它周围最近的 K 个样本属于什么类别,然后让新样本 "跟随多数派"。

想象你在一个派对上,想知道自己应该坐在哪个区域。你看看离你最近的 3 个人(K=3)坐在哪里,如果 2 个在 A 区,1 个在 B 区,你很可能也会选择 A 区。这就是 KNN 的基本思想。

实现步骤

让我们一步步实现 KNN 分类算法,从数据准备到最终评估。

1. 导入需要的库

首先,我们需要导入一些 Python 库来帮助我们处理数据和实现算法:

python 复制代码
import numpy as np  # 用于数值计算
import pandas as pd  # 用于数据处理
from sklearn.model_selection import train_test_split  # 用于划分训练集和测试集
from sklearn.preprocessing import StandardScaler  # 用于数据标准化
from sklearn.neighbors import KNeighborsClassifier  # KNN分类器
from sklearn.metrics import accuracy_score, classification_report  # 评估指标
import matplotlib.pyplot as plt  # 用于可视化
from mpl_toolkits.mplot3d import Axes3D  # 用于3D可视化

2. 加载并查看数据

我们使用一个包含收入、年龄、学历和对应类别的数据集:

python 复制代码
# 加载数据
df = pd.read_excel('https://labfile.oss.aliyuncs.com/courses/40611/K%E8%BF%91%E9%82%BB%28KNN%29%E5%88%86%E7%B1%BB.xlsx')

# 查看前5行数据
df.head()

数据看起来是这样的:

收入 年龄 学历 类别
4956 22 专科 普通人
10397 21 本科 精英
5158 30 专科 普通人
4368 22 专科 普通人
12680 35 专科 精英

3. 数据预处理

计算机不理解文字,所以我们需要将中文类别转换为数字:

python 复制代码
# 将学历文本转换为数字
df['学历'] = df['学历'].map({
    "专科": 1,
    "本科": 2,
    "硕士": 3,
    "博士": 4
})

# 将类别文本转换为数字
df['类别'] = df['类别'].map({
    "普通人": 0,
    "精英": 1,
    "高质量": 2
})

# 查看转换后的数据
df.head()

为了符合国际惯例,我们将中文列名改为英文:

python 复制代码
column_mapping = {
    '收入': 'Income',
    '年龄': 'Age',
    '学历': 'Education_Level',
    '类别': 'Category'
}
df.rename(columns=column_mapping, inplace=True)

4. 准备特征和标签

在机器学习中,我们通常将数据分为 "特征"(输入)和 "标签"(输出):

复制代码
# 特征:收入、年龄、学历(用于预测的属性)
X = df[['Income', 'Age', 'Education_Level']]

# 标签:类别(我们要预测的结果)
y = df['Category']

5. 数据标准化

KNN 算法基于距离计算,不同特征的单位可能不同(如收入是几千,年龄是几十),这会影响距离计算。因此我们需要标准化数据:

python 复制代码
# 创建标准化器
scaler = StandardScaler()

# 对特征进行标准化处理
X_scaled = scaler.fit_transform(X)

标准化后的数据均值为 0,标准差为 1,确保每个特征对距离计算的影响是均衡的。

6. 划分训练集和测试集

我们需要一部分数据来训练模型,另一部分来测试模型的效果:

复制代码
# 划分数据集:80%用于训练,20%用于测试
X_train, X_test, y_train, y_test = train_test_split(
    X_scaled, y, test_size=0.2, random_state=42
)
  • X_train, y_train:训练数据和对应的标签
  • X_test, y_test:测试数据和对应的标签
  • test_size=0.2:测试集占 20%
  • random_state=42:固定随机种子,确保结果可重现

7. 实现 KNN 分类

现在我们可以创建并训练 KNN 模型了:

python 复制代码
# 创建KNN分类器,K=3(选择最近的3个邻居)
knn = KNeighborsClassifier(n_neighbors=3)

# 用训练数据训练模型
knn.fit(X_train, y_train)

# 用训练好的模型预测测试集
y_pred = knn.predict(X_test)

8. 评估模型效果

我们需要看看模型预测得准不准:

python 复制代码
# 计算准确率
accuracy = accuracy_score(y_test, y_pred)
# 生成详细的分类报告
report = classification_report(y_test, y_pred)

print(f'准确率: {accuracy}')
print('分类报告:\n', report)

输出结果:

python 复制代码
准确率: 0.85
分类报告:
               precision    recall  f1-score   support

           0       1.00      1.00      1.00        24
           1       0.93      0.62      0.74        21
           2       0.64      0.93      0.76        15

    accuracy                           0.85        60
   macro avg       0.85      0.85      0.83        60
weighted avg       0.88      0.85      0.85        60
  • 准确率 (accuracy):85%,表示总体预测正确的比例
  • 精确率 (precision):预测为某类且实际为此类的比例
  • 召回率 (recall):实际为某类且被正确预测的比例
  • F1 分数:精确率和召回率的调和平均

9. 可视化分类结果

我们可以用 3D 图直观地展示分类结果:

python 复制代码
# 创建3D图形
fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, projection='3d')

# 绘制测试数据点,用颜色表示预测的类别
scatter = ax.scatter(
    X_test[:, 0],  # 收入
    X_test[:, 1],  # 年龄
    X_test[:, 2],  # 学历
    c=y_pred,      # 用预测类别着色
    cmap='viridis' # 颜色映射
)

# 设置坐标轴标签
ax.set_xlabel('Income (标准化)')
ax.set_ylabel('Age (标准化)')
ax.set_zlabel('Education Level (标准化)')

# 调整视角
ax.view_init(elev=30, azim=70)

# 添加图例
legend1 = ax.legend(*scatter.legend_elements(), title="Category")
ax.add_artist(legend1)

plt.show()

K 值的选择

K 值是 KNN 算法中最重要的参数:

  • K 值太小:模型容易过拟合,对噪声敏感
  • K 值太大:模型过于简单,可能忽略数据的真实模式

通常可以通过尝试不同的 K 值(如 1, 3, 5, 7...),选择性能最好的那个。

python 复制代码
# 尝试不同的K值
for k in [1, 3, 5, 7, 9, 11]:
    knn = KNeighborsClassifier(n_neighbors=k)
    knn.fit(X_train, y_train)
    y_pred = knn.predict(X_test)
    accuracy = accuracy_score(y_test, y_pred)
    print(f'K={k} 时的准确率: {accuracy:.2f}')

距离计算

KNN 中常用的距离计算方法:

  1. 欧氏距离:最常用,计算两点之间的直线距离
  2. 曼哈顿距离:计算两点在坐标轴上的绝对距离之和
  3. 余弦相似度:衡量两个向量方向的相似性

在 scikit-learn 中,KNeighborsClassifiermetric参数可以指定距离度量方法,默认为欧氏距离。

KNN 的优缺点

优点

  • 简单易懂,容易实现
  • 不需要训练过程,是一种 "惰性学习" 算法
  • 可以处理多分类问题
  • 对异常值不敏感(当 K 较大时)

缺点

  • 计算量大,预测速度慢(需要计算与所有样本的距离)
  • 对高维数据效果不好("维度灾难")
  • 对不平衡数据敏感
  • 需要存储所有训练样本,内存占用大
相关推荐
ningmengjing_3 小时前
理解损失函数:机器学习的指南针与裁判
人工智能·深度学习·机器学习
四谎真好看3 小时前
Java 学习笔记(进阶篇2)
java·笔记·学习
程序猿炎义3 小时前
【NVIDIA AIQ】自定义函数实践
人工智能·python·学习
小陈phd3 小时前
高级RAG策略学习(四)——上下文窗口增强检索RAG
人工智能·学习·langchain
nju_spy3 小时前
Kaggle - LLM Science Exam 大模型做科学选择题
人工智能·机器学习·大模型·rag·南京大学·gpu分布计算·wikipedia 维基百科
中國龍在廣州4 小时前
GPT-5冷酷操盘,游戏狼人杀一战封神!七大LLM狂飙演技,人类玩家看完沉默
人工智能·gpt·深度学习·机器学习·计算机视觉·机器人
THMAIL4 小时前
深度学习从入门到精通 - 神经网络核心原理:从生物神经元到数学模型蜕变
人工智能·python·深度学习·神经网络·算法·机器学习·逻辑回归
Jayyih5 小时前
嵌入式系统学习DAY28(网络编程)
网络·学习·tcp/ip
dbdr09015 小时前
Linux 入门到精通,真的不用背命令!零基础小白靠「场景化学习法」,3 个月拿下运维 offer,第二十六天
linux·运维·服务器·网络·python·学习