《机器学习》笔记

1.机器学习建模流程

  1. 获取数据:搜集与完成机器学习任务相关的数据集
  2. 数据的预处理:数据集中异常值,缺失值的处理
  3. 特征工程:对数据特征进行提取,转成向量,让模型达到最好的效果
  4. 模型训练:选择合适的算法对模型进行训练,根据不同的任务来选中不同的算法,有监督学习,无监督学习,半监督学习,强化学习
  5. 模型评估:评估效果好上线服务,评估效果不好则重复上诉步骤
  6. 模型预测

2.特征工程介绍

  1. 知道特征工程是什么:利用专业背景知识和技巧处理数据,让机器学习算法效果最好。这个过程就是特征工程。数据和特征决定了机器学习的上限,而模型和算法只是逼近这个上限而已。

  2. 理解特征提取的作用:原始数据中提取与任务相关的特征,构成特征向量。新数据 = 特征提取(原数据)

    复制代码
  3. 理解特征预处理的作用:特征对模型产生影响,因量纲(单位)问题,有些特征对模型影响大,有些影响小。有两种思路,归一化和标准化(重点),归一化公式为:(当前值-最小值)/(最大值-最小值),使映射的值域在(0~1)之间

  4. 了解特征降维,特征选择,特征组合。特征降维 将原始数据的维度降低,叫做特征降维,一般会对原始数据产生影响。特征选择 :原始数据特征很多,从原特征中挑子集,通常不改原值。特征组合 (Feature Combination / Feature Interaction)是指:把两个或多个已有特征通过某种规则组合成一个新特征 ,用来表达单个特征无法表达的交互关系、非线性关系或业务含义。

3.模型拟合问题

模型拟合问题 ,本质是:模型对训练数据中的"真实规律"和"噪声"学习得是否恰当。拟合得太差叫欠拟合 ,拟合得太好但把噪声也学进去叫过拟合 ,理想状态是恰当拟合。

1. 三种拟合状态

状态 训练误差 验证/测试误差 本质 表现
欠拟合 高 高 模型太简单,没学到规律 训练集都做不好,预测偏差大
恰当拟合 低 低且接近训练误差 学到了可泛化规律 训练、验证表现稳定
过拟合 很低 明显高 模型太复杂,记住了噪声和偶然样本 训练集很好,新数据很差

一句话:

欠拟合是"没学会",过拟合是"学太死",恰当拟合是"学会了还能举一反三"。


2. 为什么会欠拟合

常见原因:

  1. 模型太简单:线性模型拟合强非线性关系。

  2. 特征不足或特征表达差:关键信息没提供,或原始特征不适合任务。

  3. 正则化过强:把模型约束得太狠。

  4. 训练不充分:迭代次数少、学习率不合适、优化没收敛。

  5. 数据质量问题:标签噪声大、特征缺失严重、采样偏差。

典型表现:

  • 训练误差和验证误差都高;

  • 增加数据后效果提升不明显;

  • 残差呈现明显系统模式,而不是随机分布;

  • 学习曲线在高误差处趋于平台。

解决方向:

  • 增加模型复杂度;

  • 构造更有表达力的特征,如特征组合、分桶、交互项;

  • 减少正则化;

  • 训练更充分、调学习率;

  • 换更合适的模型;

  • 检查数据和标签质量。


3. 为什么会过拟合

常见原因:

  1. 模型太复杂:参数太多、树太深、网络太大。

  2. 训练数据太少:样本不足以约束模型。

  3. 噪声和异常值被学习:模型把偶然现象当规律。

  4. 特征太多且无效:尤其大量稀疏类别交叉特征。

  5. 特征组合过细:如"城市×性别×商品×小时"组合爆炸,训练集覆盖好,验证集稀疏。

  6. 数据泄漏:训练时用了预测时拿不到的信息,造成"假的好效果"。

  7. 反复调参看测试集:测试集信息泄漏到模型选择中。

典型表现:

  • 训练误差持续下降,验证误差先降后升;

  • 训练集指标远好于验证集;

  • 换一批数据效果波动大;

  • 模型对少数样本或异常值非常敏感;

  • 特征重要性不稳定。

解决方向:

  • 增加数据、数据增强;

  • 降低模型复杂度;

  • L1/L2 正则、Dropout、树剪枝、早停;

  • 特征选择、降维、减少过细特征组合;

  • 交叉验证选参;

  • 集成学习;

  • 严格划分训练/验证/测试,防止数据泄漏。

4. 一句话总结

模型拟合问题就是模型对数据规律学习程度是否合适的问题:欠拟合是模型太简单没学会,过拟合是模型太复杂学太死;诊断看训练与验证误差差距及学习曲线,解决靠调整模型复杂度、特征表达、正则化、数据量和验证方式,最终目标是获得稳定可泛化的模型。

4. KNN算法


1. KNN算法简介

1.1 KNN思想

KNN(K-Nearest Neighbor,K-近邻算法)的核心思想可以概括为"近朱者赤,近墨者黑"或"物以类聚":如果一个样本在特征空间中的 k 个最相似(即距离最近)的样本中的大多数属于某一个类别,则该样本也属于这个类别。

KNN 是一种非参数统计方法 ,不对数据分布做任何先验假设;同时它也是一种惰性学习算法------训练阶段仅存储数据,真正的计算推迟到预测阶段才进行。这一特性使 KNN 原理直观、易于实现,但在数据规模较大时预测开销较高。

分类问题的处理流程:

  1. 计算未知样本到每一个训练样本的距离(通常使用欧氏距离)。

  2. 将训练样本按距离升序排列。

  3. 取距离最近的 k 个训练样本。

  4. 多数表决:统计这 k 个样本中哪个类别出现次数最多。

  5. 将未知样本归为该类别。

数学上,给定测试样本 xq,预测类别 y^为:

其中 Nk(xq)是 xq的 k 个最近邻,I(⋅)为指示函数。

回归问题的处理流程:

前 3 步与分类相同;第 4 步不再投票,而是计算这 k 个邻居目标值的平均值(或加权平均值),作为预测值。

1.2 K值的影响

K 是 KNN 唯一的核心超参数,其选择直接决定模型的偏差---方差权衡:

K 值 模型特点 风险
过小(如 K=1) 决策边界高度复杂,对噪声和异常点敏感 过拟合
过大 决策边界平滑,受样本均衡影响大 欠拟合
K=N(训练样本总数) 预测结果恒为训练集中最多的类别 完全忽略数据信息,严重欠拟合

实际工作中通常使用交叉验证从较小的奇数 K 值(如 3、5、7)中选取最优值。

2. KNN算法API介绍

sklearn.neighbors 提供了分类与回归两个对偶 API,两者参数体系几乎完全一致。

2.1 分类:KNeighborsClassifier

python

复制代码
"""
代码实现思路:
    1. 导包
    2. 准备数据集(测试集和训练集)
    3. 创建(KNN分类模型)模型对象
    4. 模型训练
    5. 模型预测
"""

# 1. 导包
from sklearn.neighbors import KNeighborsClassifier

# 2. 准备数据集(测试集和训练集)
x_train = [[0],[1],[2],[3]]
y_train = [0,0,1,1]
x_test = [[5]]

# 3. 创建(KNN分类模型)模型对象
estimator = KNeighborsClassifier(n_neighbors=2)

# 4. 模型训练
estimator.fit(x_train, y_train)

# 5. 模型预测
y_pred = estimator.predict(x_test)

# 6. 打印预测结果
print(y_pred)

关键参数:

  • n_neighbors:近邻个数 K,默认 5。

  • weights:投票权重。'uniform'(默认)表示所有近邻等权;'distance' 表示权重与距离成反比,距离越近权重越大。

  • metric 与 p:metric='minkowski' 为默认距离度量;p=1 退化为曼哈顿距离,p=2 退化为欧氏距离。

  • algorithm:近邻搜索算法,'auto' 根据数据自动在 'kd_tree'、'ball_tree'、'brute' 中选择。

注意 :predict 的输入必须是二维数组 ,即形状为 (n_samples, n_features),单样本预测应写成 [[x1, x2, ...]] 而非 [x1, x2, ...]。

2.2 回归:KNeighborsRegressor

python

复制代码
from sklearn.neighbors import KNeighborsRegressor

estimator = KNeighborsRegressor(n_neighbors=3)
estimator.fit(X_train, y_train)
y_pred = estimator.predict(X_test)  # 返回 k 个邻居目标值的平均

参数含义与分类器完全对应,差异仅在于输出:分类输出类别标签,回归输出连续数值。

3. 距离度量

KNN 的"近"由距离函数定义,距离度量的选择直接影响哪些样本成为邻居。

3.1 欧氏距离(Euclidean Distance)

最常用的距离度量,即 n 维空间中的直线距离:

优点:直观、计算简单;缺点:对特征尺度敏感------量纲大的特征会主导距离计算结果。

3.2 曼哈顿距离(Manhattan Distance)

又称"城市街区距离",沿坐标轴方向移动的总距离(对应维度差值的绝对值,求和):

适合特征之间存在"网格式"约束或希望降低单个维度极端差异影响的场景。

3.3 闵可夫斯基距离(Minkowski Distance)

闵可夫斯基距离是一个"距离家族",通过参数 pp 统一生成多种距离:

  • p=1:曼哈顿距离

  • p=2:欧氏距离

  • p→∞:切比雪夫距离

在 sklearn 的 KNeighborsClassifier / KNeighborsRegressor 中,metric='minkowski' 配合 p 参数即可切换上述距离。

3.4 余弦相似度(Cosine Similarity)

衡量两个向量在方向上的一致程度,而非数值大小:

取值范围 −1,1,越接近 1 方向越一致。特别适合文本数据(如 TF-IDF 向量),因为文本分类中词频的量级往往不如词语分布模式重要。

3.5 距离度量的选择要点

距离 适用场景 主要注意事项
欧氏距离 连续特征、低维、尺度相近 必须配合归一化/标准化
曼哈顿距离 高维稀疏特征、希望抑制极端差值 对尺度同样敏感
余弦相似度 文本、方向性特征 忽略向量模长
闵可夫斯基距离 需要通过 pp 调参的实验场景 pp 本身成为额外超参数

当各特征量纲不一致时,标准欧氏距离或先做标准化再使用普通欧氏距离是必要的修正手段。

4. 特征预处理

4.1 为什么 KNN 必须做特征预处理

KNN 完全依赖距离进行决策。如果某一特征的单位远大于其他特征(例如"收入"以元计,而"年龄"以岁计),该特征在距离计算中将占据压倒性权重,其他特征的信息被"淹没"。因此,在 KNN 中特征缩放不是可选项,而是必要步骤。

4.2 归一化(MinMaxScaler)

将每个特征线性映射到指定区间,默认 0,1:

python

复制代码
from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler(feature_range=(0, 1))
X_scaled = scaler.fit_transform(X)

特点 :保留原始分布形状;但对异常值敏感------一个极端最大值或最小值会压缩其余样本的缩放范围,鲁棒性较差。适合传统精确小数据场景。

4.3 标准化(StandardScaler)

将特征转换为均值为 0、标准差为 1 的分布:

μ 为特征的平均值

σ 为特征的标准差

python

复制代码
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

特点:对异常值的鲁棒性优于归一化,是 KNN 中更常用的预处理方式,尤其当特征分布近似正态或存在一定程度离群值时。

4.4 归一化 vs 标准化

MinMaxScaler StandardScaler
输出范围 固定区间(如 0,1) 均值 0,标准差 1,范围不固定
异常值影响 大(被极值主导) 相对较小
适用场景 数据边界明确、无强异常值 一般场景,KNN 默认推荐

4.5 鸢尾花识别案例(KNN + 标准化)

python

复制代码
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier

iris = load_iris()
X, y = iris.data, iris.target

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y
)

scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)   # 注意:测试集用 transform,不用 fit

knn = KNeighborsClassifier(n_neighbors=5)
knn.fit(X_train_scaled, y_train)
print("测试集准确率:", knn.score(X_test_scaled, y_test))

流程要点:先划分训练/测试集,再在训练集上 fit 预处理器 ,测试集只做 transform,避免数据泄漏。

5. 超参数选择方法

KNN 的核心超参数是 n_neighbors(K),辅以 weights、p 等。手动逐个尝试既不可靠也不高效,标准做法是交叉验证 + 网格搜索。

5.1 交叉验证(Cross-Validation)

K 折交叉验证将训练数据划分为 K 份,每次用其中 K−1 份训练、剩余 1 份验证,循环 K 次后取平均性能作为该组超参数的评估结果。这样每个样本都恰好被验证一次,评估结果比单次训练/验证划分更稳定,尤其适合数据量有限时使用。

5.2 网格搜索(GridSearchCV)

GridSearchCV 将交叉验证封装为自动化流程:给定超参数候选值构成的"网格",对每一个组合执行 K 折交叉验证,最终返回平均得分最高的参数组合。

python

复制代码
from sklearn.model_selection import GridSearchCV

param_grid = {
    "n_neighbors": [3, 5, 7, 9, 11],
    "weights": ["uniform", "distance"],
}

grid = GridSearchCV(
    estimator=KNeighborsClassifier(),
    param_grid=param_grid,
    cv=5,
    scoring="accuracy",
)
grid.fit(X_train_scaled, y_train)

print("最佳参数:", grid.best_params_)
print("最佳交叉验证得分:", grid.best_score_)
print("测试集得分:", grid.score(X_test_scaled, y_test))

GridSearchCV 在 fit 时自动完成所有参数组合的交叉验证;之后调用 predict 或 score 时,自动使用 best_estimator_,无需手动重建模型。

5.3 手写数字识别案例(digits + GridSearchCV)

python

复制代码
from sklearn.datasets import load_digits
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier
from sklearn.pipeline import Pipeline

digits = load_digits()
X, y = digits.data, digits.target      # 8×8 像素展平为 64 维

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y
)

pipe = Pipeline([
    ("scaler", StandardScaler()),
    ("knn", KNeighborsClassifier()),
])

param_grid = {
    "knn__n_neighbors": [3, 4, 5, 6, 7],
    "knn__weights": ["uniform", "distance"],
    "knn__p": [1, 2],                   # 1=曼哈顿,2=欧氏
}

grid = GridSearchCV(pipe, param_grid, cv=5, scoring="accuracy", n_jobs=-1)
grid.fit(X_train, y_train)

print("最佳参数:", grid.best_params_)
print("测试集准确率:", grid.score(X_test, y_test))

使用 Pipeline 的关键优势:交叉验证的每一折中,StandardScaler 只在当折的训练部分上 fit ,验证部分仅做 transform,彻底避免预处理阶段的数据泄漏。digits 数据集下 KNN 配合合理的 K 与距离度量,测试准确率通常可达 97% 以上。

相关推荐
武子康41 分钟前
Qwen-Drive 到底是什么:4B 级 VLM 如何成为驾驶策略底座
人工智能·算法·机器学习
坤坤子吖1 小时前
Linux网络编程:TCP服务器的多进程与多线程实现
linux·服务器·开发语言·网络·c++·笔记·学习
蒸蒸yyyyzwd3 小时前
后端相关学习笔记。
笔记·学习
旖旎夜光4 小时前
【C++ 基础入门】C++ 多态(上):虚函数、重写、override/final 与抽象类
开发语言·c++·笔记·学习
方方洛4 小时前
ray教程-28-附录G-CICD与Slurm与云上调度
人工智能·分布式·机器学习
Oll Correct5 小时前
Adobe illustrator 案例十二:视频播放(Media & Video)图标绘制
笔记·ui·adobe·illustrator
迪菲赫尔曼6 小时前
【基础篇 26】第一次在服务器完成训练:准备数据、断线继续、检查成果与备份
运维·服务器·人工智能·机器学习·计算机视觉
硅谷秋水6 小时前
RoboAtom:机器人学习的大规模原子-动作监督
人工智能·机器学习·计算机视觉·机器人
叼烟扛炮6 小时前
Linux 学习笔记(五十四):内网穿透实战——用 frp 让外网访问你的私人电脑
linux·服务器·网络·笔记·学习