多项式拟合正弦曲线:机器学习入门实验,理解过拟合与正则化

发布时间:2026/10/3 13:45:30
多项式拟合正弦曲线:机器学习入门实验,理解过拟合与正则化 简介这份资源面向机器学习初学者与课程实验学习者围绕多项式拟合正弦曲线这一经典课题提供完整的Python实现与实验报告。内容涵盖最小二乘法解析解、带2范数惩罚项的正则化优化、梯度下降与共轭梯度法的手写实现并引导读者通过调整数据量、超参数与多项式阶数直观理解过拟合现象及其克服方法。资源包共4个文件包含3个py源码与1份doc实验报告压缩包约581KB源码按数据生成、最小二乘求解、梯度下降等模块拆分注释详尽便于对照实验报告逐步复现。目前已有183人学习下载。读者可借此掌握从数据加噪、模型拟合到优化求解的完整流程理解无正则与有正则损失函数的差异并学会在不依赖自动微分框架的前提下自行推导梯度、编写迭代优化代码适合作为课程作业参考或自学练手材料。1. 多项式拟合正弦曲线为什么它是机器学习入门最值得亲手跑一遍的实验多项式拟合正弦曲线是很多人翻开《机器学习》或吴恩达课程后遇到的第一个能看见结果的实验。它不依赖真实数据集不需要爬虫也不用配置复杂环境只要 Python 加 NumPy、Matplotlib 就能跑通。但恰恰是这个小实验把机器学习里最核心的几个概念——模型容量、欠拟合、过拟合、训练集与验证集、正则化——全部串在了一起。正弦曲线本身是光滑的周期函数用多项式去逼近它阶数低了拟合不上阶数高了在两端疯狂震荡这种肉眼可见的翻车是任何教科书插图都替代不了的。这篇笔记面向的是想真正动手复现一遍的读者从环境搭建、数据生成、模型训练到画出对比图、看懂误差曲线再到把代码整理成一份能交的实验报告。如果你正在准备机器学习期末复习或者刚学完 Python 想找个练手项目这个实验的性价比非常高。2. 先把数学讲透多项式拟合正弦曲线到底在拟合什么2.1 从泰勒展开到最小二乘多项式为什么能逼近正弦正弦函数在数学上可以展开成无穷级数去掉高阶项之后就是一个多项式。这给了我们一个直觉只要阶数足够多项式能在一定区间内逼近正弦曲线。但机器学习里的做法不是去算泰勒系数而是把问题转化成给定一批带噪声的观测点找一组多项式系数让预测值和真实值差距最小。形式化地设多项式为y w0 w1·x w2·x² ... wM·x^M其中 M 是阶数w 是待求系数。我们手上有一批训练样本 (x_i, t_i)t_i 是带噪声的目标值。目标是最小化平方误差E(w) 1/2 · Σ (y(x_i, w) - t_i)²这是一个标准的线性最小二乘问题。虽然它对 x 是非线性的因为有 x²、x³但对系数 w 是线性的所以可以直接求解析解也可以用梯度下降。解析解的形式是w (XᵀX)⁻¹ Xᵀt其中 X 是范德蒙德矩阵每一行是 [1, x_i, x_i², ..., x_i^M]。这个公式在阶数不高、数据量不大时非常稳定也是很多入门代码直接用的方式。理解这一点很关键多项式拟合正弦曲线不是神经网络它没有隐藏层、没有激活函数本质是一个线性回归模型套了一层特征变换。你把 x 扩展成 [1, x, x², ..., x^M]剩下的就是普通线性回归。这也是为什么它适合入门——所有复杂度都来自特征工程选阶数而不是模型结构本身。2.2 阶数 M 是唯一的超参数欠拟合与过拟合的分界线在这个实验里唯一需要你手动决定的超参数就是阶数 M。M 太小模型表达能力不够曲线太平拟合不上正弦的起伏这叫欠拟合。M 太大模型开始记住训练数据里的噪声曲线在数据点之间剧烈震荡尤其在区间两端会飞出天际这叫过拟合。常见的观察结果是M0 和 M1 明显欠拟合M3 已经能大致跟上正弦的形状M9 在训练点上几乎完美但两端开始翘M15 以上基本就是灾难现场。这个从欠拟合到刚好再到过拟合的过程是理解模型容量最直观的方式。但要注意过拟合不是单纯由 M 决定的它和训练样本数量也强相关。同样的 M9如果只有 10 个训练点过拟合会非常严重如果有 100 个点可能看起来还不错。所以这个实验真正想让你体会的是模型复杂度要和数据量匹配。2.3 训练误差下降不代表模型变好验证集的作用如果你只画训练误差随 M 变化的曲线会发现它几乎单调下降——M 越大训练误差越小M 足够大时甚至能降到接近零。但这不代表模型变好了只代表它把训练数据背下来了。正确做法是留出一部分数据作为验证集或测试集同时观察训练误差和验证误差。典型曲线是训练误差一直降验证误差先降后升那个最低点对应的 M 就是相对合理的阶数。这条U 形曲线是机器学习里最经典的图之一也是这个实验报告里必须呈现的内容。在实际写代码时我一般会生成两批数据一批用于训练一批用于验证两批都加同样的高斯噪声。然后对每个 M 分别训练、分别计算两边的均方误差最后画在一张图上。3. 用 Python 从零跑通数据生成、模型训练与可视化3.1 环境准备与依赖安装这个实验对环境的依赖非常轻只需要 Python 3.8 以上加上 NumPy 和 Matplotlib。如果你还没装 Python去官网下载安装包即可安装时记得勾选Add Python to PATH。装好之后在命令行里执行pip install numpy matplotlib如果你用 VS Code建议同时装一下 Python 扩展这样可以直接在编辑器里运行和调试。不需要 sklearn也不需要 PyTorch这个实验用纯 NumPy 就能完成反而更能看清每一步在做什么。提示如果你后续想对比 sklearn 的 PolynomialFeatures LinearRegression也可以装 scikit-learn但建议先用 NumPy 手写一遍理解矩阵构造过程。3.2 生成带噪声的正弦数据先写数据生成部分。核心是在 [0, 2π] 区间内均匀取点计算 sin 值再加上高斯噪声。import numpy as np import matplotlib.pyplot as plt # 固定随机种子保证每次运行结果一致 np.random.seed(42) # 生成训练数据20 个点均匀分布在 [0, 2π] N_train 20 x_train np.linspace(0, 2 * np.pi, N_train) # 真实正弦值 高斯噪声均值 0标准差 0.3 t_train np.sin(x_train) np.random.normal(0, 0.3, N_train) # 生成验证数据另外 20 个点位置稍微错开 N_val 20 x_val np.linspace(0, 2 * np.pi, N_val) 0.05 t_val np.sin(x_val) np.random.normal(0, 0.3, N_val) # 用于画真实曲线的密集点 x_plot np.linspace(0, 2 * np.pi, 200) y_plot np.sin(x_plot)这段代码里有两个参数值得注意。一个是噪声标准差 0.3它决定了数据点偏离正弦的程度噪声越大过拟合越容易发生。另一个是训练点数量 20这个数量对 M9 来说偏少正好能制造出明显的过拟合现象。如果你想观察数据量对过拟合的影响可以把 N_train 改成 100 再跑一次对比 M9 的曲线形状。验证集的 x 坐标我特意加了 0.05 的偏移避免和训练点完全重合这样验证误差更能反映模型在没见过的位置上的表现。3.3 构造范德蒙德矩阵并求解系数接下来是核心部分给定阶数 M构造特征矩阵并求系数。def fit_polynomial(x, t, M): 用最小二乘法拟合 M 阶多项式 x: 输入坐标形状 (N,) t: 目标值形状 (N,) M: 多项式阶数 返回: 系数向量 w形状 (M1,) # 构造范德蒙德矩阵每一列是 x 的 0 到 M 次幂 X np.vander(x, M 1, increasingTrue) # 最小二乘解析解w (X^T X)^(-1) X^T t # 用 lstsq 比直接求逆更稳定 w, _, _, _ np.linalg.lstsq(X, t, rcondNone) return w def predict_polynomial(x, w): 用求得的系数预测 M len(w) - 1 X np.vander(x, M 1, increasingTrue) return X w这里用np.linalg.lstsq而不是手动求逆是因为当 M 较大时XᵀX 可能接近奇异直接求逆数值不稳定。lstsq内部用 SVD 分解能给出更可靠的结果。np.vander的increasingTrue表示列的顺序是从 x⁰ 到 x^M和我们的公式一致。如果你手动实现求逆版本可以写成w np.linalg.inv(X.T X) X.T t但在 M15 以上时可能会看到明显的数值误差甚至报奇异矩阵错误。这也是一个值得在实验报告里提一句的坑。3.4 画出不同阶数的拟合曲线对比图有了拟合和预测函数就可以批量跑不同阶数并画图了。fig, axes plt.subplots(2, 2, figsize(12, 8)) M_list [1, 3, 9, 15] for ax, M in zip(axes.ravel(), M_list): w fit_polynomial(x_train, t_train, M) y_pred predict_polynomial(x_plot, w) ax.scatter(x_train, t_train, colorred, s20, label训练数据) ax.plot(x_plot, y_plot, g--, label真实 sin(x)) ax.plot(x_plot, y_pred, b-, labelfM{M} 拟合) ax.set_ylim(-2, 2) ax.legend() ax.set_title(f多项式阶数 M{M}) plt.tight_layout() plt.show()运行后你会看到四张子图。M1 是一条直线完全跟不上正弦M3 已经能看出正弦的轮廓M9 在训练点上贴合得很好但两端开始有轻微上翘M15 则在两端剧烈震荡甚至超出了 y 轴范围。这个对比图是实验报告里最有说服力的部分。set_ylim(-2, 2)是为了让四张图尺度一致方便对比。如果你发现 M15 的曲线飞出太远可以适当放宽范围但那样其他图就看不清了所以固定范围更好。3.5 计算训练误差与验证误差并画 U 形曲线最后一步是把误差量化画出误差随 M 变化的曲线。def mse(x, t, w): 均方误差 y_pred predict_polynomial(x, w) return np.mean((y_pred - t) ** 2) M_range range(0, 16) train_errors [] val_errors [] for M in M_range: w fit_polynomial(x_train, t_train, M) train_errors.append(mse(x_train, t_train, w)) val_errors.append(mse(x_val, t_val, w)) plt.figure(figsize(8, 5)) plt.plot(M_range, train_errors, o-, label训练误差) plt.plot(M_range, val_errors, s-, label验证误差) plt.xlabel(多项式阶数 M) plt.ylabel(均方误差) plt.yscale(log) # 对数坐标因为误差跨度大 plt.legend() plt.grid(True) plt.show()这张图通常会呈现训练误差随 M 增大持续下降验证误差先降后升在 M3 到 M6 之间有一个低谷。yscale(log)是为了让误差跨度大的时候也能看清趋势如果你觉得对数坐标不直观也可以改成线性坐标但 M15 的验证误差可能会把其他点压扁。到这里一个完整的多项式拟合正弦曲线实验就跑通了。代码总量不到 80 行但覆盖了数据生成、模型定义、训练、评估、可视化全流程。4. 避坑与排查这个实验里最容易翻车的 5 个地方4.1 现象M15 时程序报奇异矩阵错误或系数异常大原因直接用np.linalg.inv(X.T X)求逆时高阶范德蒙德矩阵的条件数非常大XᵀX 接近奇异数值误差被放大。解决改用np.linalg.lstsq它内部用 SVD 分解对病态矩阵更鲁棒。如果坚持用求逆可以加一个很小的正则项也就是岭回归的思路w inv(X.T X λI) X.T tλ 取 1e-6 到 1e-3 之间。4.2 现象每次运行结果都不一样曲线形状变化很大原因没有固定随机种子每次生成的噪声不同训练数据就不同。解决在生成数据前加np.random.seed(42)。如果你想让实验报告更严谨可以跑多次取平均误差但入门阶段固定种子就够了。4.3 现象验证误差曲线一直下降没有出现 U 形原因可能是验证集和训练集来自同一批点或者验证集太小、噪声太低。也可能是 M 的范围不够大还没进入过拟合区域。解决确认验证集的 x 坐标和训练集不完全重合把 M 范围扩大到 20 甚至 25适当增大噪声标准差让过拟合更容易出现。4.4 现象M9 的曲线看起来很好但 M15 也没有明显过拟合原因训练点数量太多比如 N_train100此时 M15 相对数据量来说并不算高。解决这其实不是 bug而是说明模型复杂度和数据量要匹配。如果你想看到明显过拟合把 N_train 降到 10 到 15 之间再试。4.5 现象画图时中文显示成方框原因Matplotlib 默认字体不支持中文。解决在画图前设置字体例如plt.rcParams[font.sans-serif] [SimHei]或者直接把图里的标签改成英文。如果是在 Linux 或 Mac 上SimHei 可能不存在可以换成Arial Unicode MS或DejaVu Sans。5. 把实验写成报告结构、图表与一个进阶技巧一份能交的机器学习实验报告核心不是代码有多长而是能不能把现象—原因—结论这条线讲清楚。我一般会按这个结构组织实验目的、实验原理、实验环境、实验步骤、实验结果与分析、实验结论。其中实验结果与分析是重点要放三张图不同阶数的拟合曲线对比图、训练误差与验证误差随 M 变化的曲线图、以及一组最优 M 下的拟合效果图。在写分析时不要只写M3 最好要写出依据验证误差在 M3 时取得最小值同时训练误差和验证误差差距不大说明没有明显过拟合。再对比 M15训练误差很小但验证误差很大两者差距悬殊说明模型记住了噪声。这种用数据说话的写法比单纯描述曲线形状更有说服力。如果你想让报告更有深度可以加一个进阶实验固定 M9改变训练样本数量比如 10、20、50、100观察验证误差的变化。你会发现随着数据量增加同一个 M 的过拟合程度会减轻。这个实验能直观说明数据量是抵抗过拟合的第一道防线。另一个值得尝试的技巧是加 L2 正则化。在损失函数里加一项 λ·||w||²然后观察不同 λ 下 M9 的拟合曲线。λ 很小时曲线仍然震荡λ 适中时曲线变得平滑λ 很大时曲线又变得过于平坦。这个对比能帮你理解正则化系数的作用也是很多机器学习课程里的经典练习。我自己做这个实验时最大的教训是一开始只盯着训练误差看觉得 M 越大越好结果画出来的曲线在两端飞得离谱还以为是代码写错了。后来才明白训练误差小不等于模型好验证集才是照妖镜。这个习惯后来一直跟着我——不管做什么模型先留验证集再看训练误差和验证误差的差距。希望帮到你。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询