小木的机器学习日记-KNN算法实战


结构总览

  1. 准备工作:导入神兵利器(Python库)。

  2. 数据探索:与我们的“主角”——鸢尾花数据集初次见面。

  3. 数据集划分:切分“课本”与“考卷”的正确姿势。

  4. 模型训练:让KNN模型“学习”起来。

  5. 预测与评估:检验模型的“学习成果”。


知识点重要性评级 (实战常用度)

在本文中,我们会对关键的函数和概念进行星级评定,帮助你快速识别哪些是必须牢记的,哪些是了解即可。

  • ⭐⭐⭐⭐⭐:核心中的核心,几乎所有项目中都会用到。

  • ⭐⭐⭐⭐:非常重要,高频使用。

  • ⭐⭐⭐:重要,但可能有替代方案或在特定场景使用。

  • ⭐⭐:了解其原理即可,实际中常被更高级的工具替代。

  • ⭐:概念性了解。


第一步:准备工作 - 导入我们的工具箱

和任何工程师一样,开工前要先准备好工具。在Python中,这意味着导入我们需要的库。这次,我们会见到一位新朋友:sklearn.datasets,它是Scikit-learn内置的数据集仓库。

      import numpy as np
from sklearn import datasets # 新朋友!用于加载内置数据集
from sklearn.model_selection import train_test_split # 老朋友,但极其重要
from sklearn.neighbors import KNeighborsClassifier # 我们今天的主角:KNN分类器
from sklearn.metrics import accuracy_score # 模型的评分工具
    

第二步:加载与探索数据集

Scikit-learn非常贴心地为我们准备了许多经典数据集,鸢尾花(Iris)就是其中最著名的一个,非常适合新手入门。

2.1 加载数据
      # 使用 datasets.load_iris() 加载数据集
iris = datasets.load_iris()
    
2.2 探索数据结构

这个iris变量像一个“百宝箱”,里面装着关于数据集的一切。我们可以用.keys()看看里面都有什么宝贝:

      # 查看'百宝箱'里有什么
iris.keys()
# 输出: dict_keys(['data', 'target', 'frame', 'target_names', 'DESCR', 'feature_names', 'filename', 'data_module'])
    

  • data: 这就是样本特征矩阵 X,每一行是一个样本,每一列是一个特征。

  • target: 这就是样本的标签(类别)y,与data中的每一行一一对应。

  • target_names: 标签代表的真实含义(花的名字)。

  • feature_names: 特征的名字(花萼、花瓣的长宽)。

  • DESCR: 数据集的详细描述文档。

2.3 分离特征(X)和标签(y)

为了后续操作方便,我们把特征和标签分别提取出来。

      # 特征矩阵 X
X = iris.data
# 标签向量 y
y = iris.target

print("特征矩阵的形状 (X.shape):", X.shape)
print("前5个样本的特征:\n", X[:5])
print("-" * 30)
print("标签向量的形状 (y.shape):", y.shape)
print("前5个样本的标签:", y[:5])
print("-" * 30)
print("特征名称 (feature_names):", iris.feature_names)
print("标签含义 (target_names):", iris.target_names)
    

输出解读:
我们有150个样本,每个样本有4个特征(花萼长、宽,花瓣长、宽)。标签0, 1, 2分别对应setosa, versicolor, virginica这三种鸢尾花。


第三步:数据集划分 - 科学地切分数据

这是机器学习中至关重要的一步!如果划分不当,整个模型的评估将毫无意义。

⚠️ 核心痛点:为什么要先“打乱”数据?

观察原始的y向量,你会发现它是[0,0,...,0, 1,1,...,1, 2,2,...,2]这样有序排列的。
如果我们直接按8:2的比例切分:

  • 训练集可能只包含类别0和1的花。

  • 测试集将只包含类别2的花。

后果是灾难性的:模型从未见过类别2,却让它去预测类别2,这好比教一个学生认识猫和狗,却去考他会不会认老虎。这样的测试结果完全不可信!

解决方案:在切分前,必须先将数据随机打乱(Shuffle),同时保持X和y的对应关系。

3.1 手动实现划分(理解原理)

了解原理有助于我们更好地使用工具。我们可以通过打乱索引的方式来实现。

      # 【了解即可】手动实现数据划分
# 1. 创建乱序索引--从而更加科学的对模型进行训练

shuffle_indices = np.random.permutation(len(X))

# 2. 定义训练集比例和大小
train_ratio = 0.8
train_size = int(len(X) * train_ratio)

# 3. 划分索引
train_indices = shuffle_indices[:train_size]
test_indices = shuffle_indices[train_size:]

# 4. 根据索引取数据
X_train_manual = X[train_indices]
y_train_manual = y[train_indices]
X_test_manual = X[test_indices]
y_test_manual = y[test_indices]

print("手动划分的训练集形状:", X_train_manual.shape)
print("手动划分的测试集形状:", X_test_manual.shape)
    

np.random.permutation()
重要性: ⭐⭐ (原理重要,但实际操作中不常用)
说明: 这是理解随机化核心思想的好方法,但在实战中,我们有更方便的“瑞士军刀”。

3.2 Scikit-learn的优雅之道 (train_test_split)

忘记上面的手动实现吧!在实战中,我们永远使用train_test_split,它能一行代码帮你搞定“打乱”和“划分”两件大事。

train_test_split()
重要性: ⭐⭐⭐⭐⭐ (绝对核心,必须掌握!)
说明: 任何监督学习项目的第一步。它封装了随机化和划分逻辑,高效且不易出错。

      # 使用一行代码完成打乱和划分
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42
)

print("X_train shape:", X_train.shape)
print("y_train shape:", y_train.shape)
print("X_test shape:", X_test.shape)
print("y_test shape:", y_test.shape)
    

参数解读:

  • X, y: 我们要划分的特征和标签。

  • test_size=0.2: 指定测试集占比20%,训练集则自动为80%。你也可以用train_size=0.8。

  • random_state=42: 随机种子。这是一个非常重要的参数!它保证了你每次运行这段代码,得到的随机划分结果都是完全一样的。这对于复现实验结果至关重要。42只是一个惯例数字,你可以设为任何整数。


第四步:模型训练 - 让KNN开始学习

数据准备就绪,现在轮到我们的主角——KNN分类器登场了。

KNeighborsClassifier()
重要性: ⭐⭐⭐⭐ (KNN算法的核心实现,是分类器大家族中的重要一员)

.fit(X_train, y_train)
重要性: ⭐⭐⭐⭐⭐ (所有Scikit-learn模型的“学习”指令)
说明: fit就是训练。你把“课本”(X_train)和“标准答案”(y_train)交给模型,它就会去学习其中的规律。

      # 1. 创建一个KNN分类器实例
# n_neighbors=5 表示我们选择最近的5个邻居来投票,这个'5'就是K值。
knn_classifier = KNeighborsClassifier(n_neighbors=5)

# 2. 用训练数据来“喂养”模型,进行训练
knn_classifier.fit(X_train, y_train)

print("模型训练完成!")
    

fit的过程非常快,因为KNN算法的“训练”阶段其实只是把训练数据存储起来,它是一个“懒惰学习者”。


第五步:预测与评估 - 见证奇迹的时刻

模型学完了,现在我们要用“模拟考卷”(X_test)来测试它,看看它的预测结果(y_predict)和“真实答案”(y_test)相差多少。

5.1 进行预测

.predict(X_test)
重要性: ⭐⭐⭐⭐⭐ (所有Scikit-learn模型的“预测”指令)
说明: 给定新的、未见过的数据,让训练好的模型给出它的判断。

      # 让训练好的模型对测试集进行预测
y_predict = knn_classifier.predict(X_test)

print("预测结果 (y_predict):", y_predict)
print("真实答案 (y_test):   ", y_test)
    

5.2 评估模型准确度

最直观的方法就是比较y_predict和y_test有多少个是完全一样的。

accuracy_score()
重要性: ⭐⭐⭐ (直观且常用,但对于复杂问题有其局限性)
说明: 最基础的分类评估指标,表示“预测正确的样本数 / 总样本数”。

      # 方法一:手动计算
correct_predictions = sum(y_predict == y_test)
total_predictions = len(y_test)
accuracy = correct_predictions / total_predictions
print(f"手动计算的准确度: {accuracy}")

# 方法二:使用sklearn的工具
accuracy_sklearn = accuracy_score(y_test, y_predict)
print(f"使用accuracy_score计算的准确度: {accuracy_sklearn}")
    

5.3 终极捷径:.score()方法

如果你只关心准确度,Scikit-learn提供了一个更便捷的方法:直接调用分类器自身的.score()方法。它会自动完成预测比对两个步骤。

.score(X_test, y_test)
重要性: ⭐⭐⭐⭐ (非常方便的快速评估工具)
说明: 这是.predict()和accuracy_score()的便捷封装,一步到位得到准确度。

      # 直接调用模型的score方法,传入测试数据和真实标签
accuracy_direct = knn_classifier.score(X_test, y_test)

print(f"使用.score()方法直接得到的准确度: {accuracy_direct}")
    

在这个例子中,你会发现准确度是1.0,也就是100%!这说明我们的模型在这次测试中完美地预测了所有花的种类。这在真实世界的复杂问题中是很少见的,但鸢尾花数据集确实相对简单。


本章小结与展望

恭喜你!你已经成功地完成了你的第一个完整的机器学习项目!让我们回顾一下我们走过的路:
加载数据: 使用datasets.load_iris()。
划分数据: 使用train_test_split(),并理解了random_state的重要性。
创建模型: KNeighborsClassifier()。
训练模型: .fit()。
预测与评估: .predict() 和 .score()。

思考与展望:
在今天的项目中,我们随意地设置了k=5。但这个k值到底取多少才是最好的呢?k=3会不会更好?k=10呢?

这个k值,就是机器学习中一个非常重要的概念——超参数(Hyperparameter)。它是在模型训练之前就需要我们手动设置的参数。如何科学地找到最优的超参数,是提升模型性能的关键。

在下一篇文章中,我们将深入探讨超参数搜索的奥秘,让你的模型变得更“聪明”!敬请期待!

### 关于头歌平台中KNN算法机器学习教程与实例 #### 头歌平台概述 头歌(Tougo)是一个专注于计算机科学教育的学习平台,提供丰富的在线课程资源和实践环境。对于机器学习领域的内容,尤其是像KNN这样经典的算法,通常会通过理论讲解、代码实现以及实际应用案例相结合的方式进行教学。 #### KNN算法简介 KNN(K-Nearest Neighbors)是一种基于实例的学习方法,既可用于分类也可用于回归分析。其核心思想是:给定一个测试样本,在训练集中找到与其最近的K个邻居,并依据这K个邻居的信息来进行决策[^2]。 #### KNN算法的主要步骤 1. 数据预处理阶段,包括标准化或归一化操作以消除不同特征间量纲差异的影响。 2. 计算待测样本到所有已知样本的距离,常用欧氏距离或其他形式的距离度量方式。 3. 找出距离最小的前K个样本作为近邻点集合。 4. 对于分类任务采用投票机制决定最终类别;而对于回归任务则取平均值或者加权平均值得出结果。 #### 距离计算公式示例 以下是两种常见距离公式的Python实现: ```python import numpy as np def euclidean_distance(x, y): """欧几里得距离""" return np.sqrt(np.sum((np.array(x) - np.array(y)) ** 2)) def manhattan_distance(x, y): """曼哈顿距离""" return np.sum(abs(np.array(x) - np.array(y))) ``` 上述函数分别实现了欧氏距离和曼哈顿距离的计算过程。 #### 实际应用场景举例 假设我们有一个简单的电影分类场景,其中每部影片由两个属性描述:“拥抱次数”和“打斗次数”。利用已有标注的数据集可以构建模型并预测未知标签的新样例所属类型[^4]。 #### 可能存在的挑战及优化方向 尽管KNN易于理解和实现,但在大规模数据集上的性能可能较差,因为每次都需要遍历整个数据库寻找最接近的邻居。因此可以通过KD树索引结构加速查询效率,或是引入降维技术减少维度灾难带来的影响[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值