学习日记 7.27
前言
大家好!今天我们来聊聊机器学习里一个特别适合新手入门的算法——K 近邻算法,也就是大家常说的 KNN(K-Nearest Neighbors)。它的核心思想特别形象,就是咱们常说的“近朱者赤,近墨者黑”:一个样本在特征空间里,离它最近的 k 个邻居中,哪个类别占多数,这个样本就属于哪个类别。
KNN 属于“懒学习”,训练阶段它啥也不干,就是把数据集存起来。真正的计算都发生在预测阶段,需要把待测样本和所有训练样本的距离都算一遍。
这篇文章,我会带着大家通过两个完整的实战案例,把 KNN 的工程流程完整走一遍。
一、KNN 核心基础知识
适用场景:KNN 既能做多分类、二分类,也能做回归任务。它比较适合特征维度适中、样本量不是特别大的数据。
距离度量:在 scikit-learn 里,KNN 默认用的是欧氏距离。简单来说,距离越小,就代表两个样本越相似。
超参数 k:这个 k 值的选择很有讲究。如果 k 选得太小,模型会变得很敏感,容易过拟合,一点噪声就能把它带偏。反过来,如果 k 选得太大,模型又会变得太"懒",容易欠拟合,连那些八竿子打不着的远邻都会跑来影响预测结果。
重要 API(KNeighborsClassifier)
.fit(X, y) 把训练特征和标签喂给模型,完成"训练"(其实就是把数据存起来)。.predict(X) 输入新样本,输出预测的类别。.predict_proba(X) 这个更有意思,它会输出每个样本属于各个类别的概率。.score(X, y) 直接返回模型在给定数据集上的分类准确率。
二、案例一:学生分类数据集 studentTestSet2—— 数据可视化 + KNN 基础预测
任务目标
我们先来读一个学生分类数据集,用三维图把三种学生类型直观地展示出来。然后搭建一个 KNN 分类器,对几条未知的样本进行类型预测,最后咱们手动算一下预测的准确率。这个数据集有 3 个特征,最后一列是标签(1、2、3 分别代表三种类型:爱学习的、爱玩的、中等的)。
核心代码思路解读
# 加载数据
data = np.loadtxt('studentTestSet2.txt')
x = data[:,:-1] # 特征:前三列
y = data[:,-1] # 标签:最后一列
3D可视化,按类别拆分样本
data_2 = data[data[:, -1] == 2]
data_3 = data[data[:, -1] == 3]
fig = plt.figure()
ax= plt.axes(projection ='3d')
不同类别使用不同颜色、标记区分
ax.scatter(...)
plt.show()

代码绘制的图片如上,通过这个三维散点图,我们能一眼看出不同类别的样本在特征空间里是不是“抱团”的。可视化是数据分析的第一步,它能帮你快速判断这个分类任务靠不靠谱。
# 构建KNN模型 k=3
neigh = KNeighborsClassifier(n_neighbors=3)
neigh.fit(x,y)
单样本预测
print(neigh.predict([[8998,4.156252,0.097129]]))
批量样本预测
predict_data = [[19739,2.816770,1.686209],...]
b = neigh.predict(predict_data)
手动计算预测正确率
a = np.array([2,1,3,1,3,1,2,2,1,2])
equal_mask = (a == b)
similarity = equal_mask.mean()
print("相似度:", similarity)
这里我们手动用数组比对来计算准确率,就是为了让大家理解准确率的底层逻辑:预测正确的样本数除以总样本数。
本案例暴露的问题
第一个大问题:没有做特征标准化!
学生数据的三个特征(每年旅行公里数、每周游戏时间占比、每周吃零食重量),数值量级差距非常大。KNN 是靠距离吃饭的,数值大的特征会完全主导距离的计算结果,导致模型产生偏差。这也是我们下一个鸢尾花案例必须引入标准化的原因。
第二个问题:没有划分独立的测试集。
我们直接用训练集来预测和评估,这没法客观衡量模型的泛化能力(也就是处理新数据的能力)。
三、案例二:鸢尾花数据集 —— 引入标准化,规范训练 / 测试分离流程
鸢尾花数据集是机器学习领域的"Hello World",有 4 个花朵特征,对应 3 种鸢尾花。这个案例,我们重点解决上一个案例的缺陷:引入 Z-Score 标准化,并且严格区分训练集和测试集。
任务流程拆解
整个流程是这样的:先用 pandas.read_excel 分别读取训练集和测试集(两个文件),把特征 X 和标签 Y 分开,然后对特征进行 Z-Score 标准化。接着实例化一个 KNN 模型(k=2),用标准化后的训练集来训练,最后分别在训练集和测试集上评估准确率,输出预测标签,还有每个样本属于各个类别的概率(predict_proba)。
Z-Score 标准化原理
公式是:z = (x - μ) / σ
其中,μ 是特征的平均值,σ 是特征的标准差。标准化之后,每个特征的均值会接近 0,标准差接近 1,这样就消除了不同特征之间量纲的差异。记住,用 KNN 必须做标准化! 因为距离计算对特征的尺度超级敏感。
✅ 标准化的正确做法
应该用 StandardScaler,只从训练集计算均值和标准差,然后用这些参数去转换测试集:
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
# 用训练集来"学习"均值和方差
X_train_scaled = scaler.fit_transform(train_X)
# 对测试集只做转换,绝对不能再 fit!
X_test_scaled = scaler.transform(test_X)
关键函数拓展理解
knn.score(data_test, test_Y) 返回的是测试集上的准确率,是衡量模型泛化能力的关键指标。knn.predict_proba(data_test) 会输出一个二维数组,每一行代表一个样本,数值是它属于每一类的概率,可以用这个来分析模型预测的"自信程度"。
四、两套案例横向对比总结
| 对比维度 | 约会数据集案例 | 鸢尾花数据集案例 |
|---|---|---|
| 数据源读取方式 | numpy.loadtxt(纯数组) | pandas.read_excel(表格 DataFrame) |
| 数据预处理 | 无标准化,存在尺度问题 | 引入了 Z-score 标准化(思路对,但实现方式错了) |
| 数据分析手段 | 3D 可视化探索样本分布 | 没有可视化,重点放在模型评估上 |
| 模型评估方式 | 手动数组比对计算准确率 | 调用 sklearn 内置的 score 评估,还输出了预测概率 |
| 工程规范 | 没区分训练集和测试集,有缺陷 | 手动分开了训练文件和测试文件,流程更规范 |
两套案例是循序渐进的:约会案例带你学会数据加载、可视化、KNN 的基础调用,直观理解分类任务是怎么回事。鸢尾花案例则让你意识到特征尺度问题的严重性,学习数据标准化,理解训练集和测试集必须严格隔离这个重要的工程准则。
五、KNN 算法优缺点复盘
优点方面,KNN 的原理简单,特别好理解,没有什么复杂的数学假设;无需训练,对于小数据集可以快速上手;而且天然支持多分类任务,不用做额外处理。
缺点方面,首先是预测速度慢,预测的时候得遍历所有训练样本算距离,数据量一大就扛不住了。高维数据表现差,这就是所谓的"维度灾难",维度一高,距离计算就失效了。对不平衡数据集也不友好,容易偏向样本数量多的类别。最后,对异常值和特征尺度极其敏感,所以预处理(比如标准化)必须做好。
学习感悟
通过这两个案例,我们完整地走了一遍机器学习的标准流程:数据读取 → 数据探索 → 特征预处理 → 模型训练 → 样本预测 → 效果评估。
新手最容易忽视的一点是:只要是基于距离的模型(比如 KNN、SVM),特征标准化或归一化是必须的。
更多推荐

所有评论(0)