
简介这份资源面向想用 Java 入门监督学习的开发者聚焦线性回归这一最基础的机器学习模型通过一个可运行的小程序演示如何用梯度下降与正态方程拟合数据点的“最佳拟合线”。示例以 y Mx B 为学习目标从训练数据中求出常数 M 与 B并说明选择非线性特征后也能拟合高阶多项式训练数据取自 Andrew Ng 的 Coursera 机器学习课程。压缩包共 13 个文件约 44KB包含 3 个 Java 源文件、5 个 txt 训练数据、Jama 矩阵运算 jar 包及 README、工程配置等源码与数据分离便于对照阅读和替换数据集实验。已有 253 人学习适合作为理解梯度下降迭代过程与正态方程解析解差异的练手项目。1. 线性回归到底在做什么从“猜房价”说起你手里有一张表左边是房子面积右边是成交价。看了几十行之后你心里大概会冒出一句面积越大价格越高。这句话本身没什么稀奇稀奇的是——能不能把“大概”变成一个公式让新来一套房子你直接算出它值多少钱线性回归干的就是这件事找一条直线让它尽可能贴近所有已知数据点然后用这条直线去预测未知。它是最基础的机器学习模型之一也是很多人入门时第一个真正动手跑起来的算法。搞懂它不只是学会一个公式而是理解“模型如何从数据里学规律”这件事的起点。而“梯度下降”和“正态方程”就是求这条直线的两种截然不同的路子。2. 为什么一条直线值得反复琢磨线性回归的两个求解思路2.1 直线背后的假设输入和输出之间存在线性关系线性回归的核心假设非常朴素输出 y 可以近似写成输入的加权和再加一个偏置。用一维情况说就是 y wx b。这里的 w 是斜率b 是截距。模型要学的就是这两个数。打个比方你在调一个老式收音机的两个旋钮一个控制音量一个控制音调目标是让声音听起来最舒服。w 和 b 就是那两个旋钮数据就是你的耳朵你要拧到某个位置让整体误差最小。多维情况下输入不止一个特征公式变成 y w₁x₁ w₂x₂ … wₙxₙ b。写成向量形式就是 y wᵀx b。不管维度多少本质还是“加权求和”。这个假设很强现实数据往往不完全满足但它是理解更复杂模型的台阶。为什么值得反复琢磨因为线性回归把“学习”这件事压缩到了极致没有隐藏层没有激活函数没有花哨的结构只剩下“怎么把误差压到最小”这一个问题。把这个问题的两种解法吃透后面遇到神经网络的梯度下降你会发现骨子里是一样的。2.2 误差怎么量损失函数是模型的“打分器”直线画得好不好得有个标准。最常用的是均方误差MSE把每个样本的预测值和真实值之差平方再取平均。平方的作用有两个一是让正负误差不互相抵消二是放大离谱预测的惩罚。通俗地说这就像考试打分错一道扣一分错得越离谱扣得越狠。模型训练的目标就是让这个总分越低越好。损失函数写成 L(w, b) (1/n) Σ (yᵢ - (wᵀxᵢ b))²。注意它是关于 w 和 b 的函数数据是固定的。所以“训练模型”翻译过来就是在 w 和 b 的空间里找一个让 L 最小的点。这个空间可能有很多维但几何直觉不变——你在一个碗形曲面上找最低点。提示均方误差对异常值敏感。一个极端离群点能把整条直线拽偏实际使用前先看看数据分布。2.3 两条路的分岔迭代逼近 vs 一步到位找最低点有两条路。第一条是梯度下降先随便站一个位置看看脚下往哪个方向最陡往下走一小步重复直到走不动。第二条是正态方程直接解一个方程一步算出最低点的坐标。打个比方你要找山谷的最低处。梯度下降是蒙着眼一步步摸下去正态方程是手里有一张地形图直接算出谷底坐标。前者慢但通用后者快但有门槛。这个分岔决定了后面所有的区别梯度下降需要调学习率、需要迭代、对特征尺度敏感正态方程需要算矩阵逆、特征多时算不动。两者没有绝对优劣只有适不适合。理解这个分岔比记住哪个“更好”重要得多。3. 梯度下降蒙着眼下山的那套办法3.1 梯度的直觉为什么沿着反方向走就能下降梯度是一个向量指向函数上升最快的方向。所以要让损失变小就往梯度的反方向走。这个结论不需要背想象你站在山坡上最陡的上坡方向就是梯度那下坡自然就是反方向。数学上w 的更新规则是 w : w - α · ∂L/∂wb 同理。α 是学习率控制每步走多大。偏导数告诉你每个旋钮该往哪拧、拧多少。这里有个容易翻车的地方学习率太大会跨过谷底来回震荡太小则走半天还在半山腰。血泪经验是先用一个不大不小的值试比如 0.01观察损失曲线是否稳定下降再决定调大还是调小。3.2 批量、随机与小批量三种走法各有取舍梯度下降按每次用多少数据算梯度分成三种。批量梯度下降用全部样本算一次梯度方向准但每步都慢随机梯度下降每次只用一个样本快但方向抖小批量梯度下降折中每次用一小撮样本。用生活类比批量像每次问全班同学意见再行动稳但慢随机像逮着一个人就问快但容易被带偏小批量像问一个小组兼顾效率和稳定。实际工程里小批量最常见因为它在计算效率和梯度质量之间取得了平衡。方式每次用样本数优点缺点批量全部梯度稳定大数据集每步极慢随机1每步极快方向抖动大小批量一小批平衡需选批量大小3.3 学习率和迭代次数两个必须盯住的旋钮学习率决定步长迭代次数决定走多少步。这两个参数没有万能值得看数据。判断方法很直接把每次迭代的损失记下来画成曲线。正常情况曲线应该先快速下降后趋于平缓如果上下乱跳学习率偏大如果几乎不降学习率偏小或特征没标准化。特征标准化这件事值得单独提一句。如果两个特征的量纲差很远比如一个在 0 到 1 之间另一个在几千的量级损失曲面会变成狭长的椭圆梯度下降会来回锯齿收敛极慢。把特征缩放到相近范围曲面接近圆形下降就顺畅得多。这是很多人第一次跑梯度下降时遇到的坑。# 梯度下降核心循环伪代码风格突出参数含义 for epoch in range(n_iterations): grad_w (2/n) * X.T.dot(X.dot(w) b - y) # 对 w 的偏导 grad_b (2/n) * sum(X.dot(w) b - y) # 对 b 的偏导 w w - learning_rate * grad_w # 沿反方向更新 b b - learning_rate * grad_b这段代码里grad_w 和 grad_b 是损失对两个参数的偏导learning_rate 就是步长。注意每次更新用的是同一批数据算出的梯度这就是批量梯度下降。改成小批量只需每次取数据的一个子集。4. 正态方程一步算出答案的“后悔药”4.1 从求导到解方程为什么能直接得到最优解均方误差是一个凸二次函数形状像一个碗只有一个最低点。对凸函数来说导数为零的点就是全局最优。把损失对 w 求导令其为零整理之后得到一个线性方程组解出来就是最优的 w。写成矩阵形式是 θ (XᵀX)⁻¹Xᵀy其中 θ 把 w 和 b 打包在一起X 是加了偏置列的设计矩阵。这个公式就是正态方程。它不需要迭代不需要学习率一步到位。打个比方梯度下降是试错法找钥匙正态方程是直接根据锁的结构配一把。配钥匙快但你得先有锁的完整图纸而且锁太复杂时配钥匙的机器也算不动。4.2 矩阵逆的代价特征一多就“算不动”正态方程的瓶颈在 (XᵀX)⁻¹。求逆的计算量大致随特征数的立方增长。特征几十个时还好几百个就开始吃力上万维基本不现实。另外如果特征之间存在完全共线性XᵀX 不可逆公式直接失效接近共线时数值也不稳定。所以正态方程适合特征数不多的场景比如几个到几十个特征的回归问题。特征一多梯度下降的优势就出来了——它每步只算梯度不碰矩阵逆代价随样本数和特征数线性增长。注意特征共线性不是小问题。两个特征高度相关时正态方程给出的系数可能数值巨大且符号反常解释性会很差。4.3 两种解法怎么选一张对照表说清边界维度梯度下降正态方程是否需要调参需要学习率、迭代次数不需要特征很多时可扩展求逆代价高特征少时也能用但多此一举一步到位特征共线性仍可运行可能不可逆实现复杂度循环逻辑一行矩阵运算选择逻辑不复杂特征少、想要确定性结果、不想调参用正态方程特征多、数据量大、需要在线更新用梯度下降。两者算出的最优解在理想条件下是一致的差别在过程和适用边界。5. 常见误区这几个概念最容易搅在一起5.1 线性回归和逻辑回归名字像任务完全不同易混点两者都带“回归”二字公式形式也相似都是加权求和。为什么混名字误导加上都用了类似的线性组合。怎么区分看输出。线性回归输出连续值用于预测数值逻辑回归输出概率用于分类。逻辑回归在加权和外面套了一个函数把结果压到 0 到 1 之间本质是分类模型。记住一句话线性回归答“多少”逻辑回归答“哪类”。5.2 损失函数和评估指标训练时看的和验收时看的不是一回事易混点均方误差既像损失又像指标容易以为是一回事。为什么混数值上确实可能相同。怎么区分损失函数是训练时用来求梯度的必须可导评估指标是训练后衡量模型好坏的不参与优化。你可以用均方误差训练却用平均绝对误差验收。两者目的不同别混着谈。5.3 梯度和导数多维情况下的叫法差异易混点一维时叫导数多维时叫梯度很多人以为梯度是另一种东西。为什么混术语切换没有明显提示。怎么区分梯度就是把各方向的偏导数打包成向量。一维时梯度退化成导数。理解上不用分开都是“变化最快的方向”。5.4 特征标准化和归一化目的相近做法有别易混点两个词经常混用有人以为完全等价。为什么混都是把特征缩放到相近范围。怎么区分标准化是减均值除标准差结果均值 0 方差 1归一化通常指缩放到固定区间如 0 到 1。对梯度下降来说两者都能改善收敛但标准化对异常值更稳健。选哪个看数据分布不必纠结名词。5.5 过拟合和欠拟合误差大不一定是模型太简单易混点训练误差高就以为模型不行训练误差低就以为模型很好。为什么混只看一个数字容易误判。怎么区分训练误差高、验证误差也高是欠拟合训练误差低、验证误差明显高是过拟合。线性回归本身容量有限过拟合不常见但特征一多、样本一少照样会发生。判断要看两组误差的差距不是单看一组。6. 什么时候该用线性回归边界判断和一个具体例子线性回归不是万能钥匙它的适用边界很清楚。输入和输出大致呈线性关系、需要可解释的系数、数据量不大且特征不多这几种情况下它往往是第一选择。反过来关系明显非线性、特征维度极高、数据里异常值很多又没处理硬上线性回归大概率翻车。举个具体例子。某公司想根据房屋面积、房龄、楼层三个特征预测租金。特征只有三个样本几百条用正态方程一行矩阵运算就能出结果系数还能直接解释为“面积每多一平米租金平均变化多少”。这种场景用梯度下降反而多此一举。但如果特征扩展到几百个比如加入周边设施的各种编码正态方程的求逆就开始吃力这时候换成小批量梯度下降更合适。判断流程可以简化成三个问题关系是否近似线性特征数量是否可控是否需要系数解释三个都答是线性回归直接上有一个答否就得考虑别的模型或先做特征工程。# 正态方程求解特征少时的直接解法 import numpy as np X_b np.c_[np.ones((len(X), 1)), X] # 加一列偏置项 theta np.linalg.inv(X_b.T.dot(X_b)).dot(X_b.T).dot(y) # theta[0] 是截距theta[1:] 是各特征系数这段代码对应 θ (XᵀX)⁻¹Xᵀy。np.c_ 用来拼接偏置列inv 求逆。特征多时这行会变慢甚至报奇异矩阵错误那时候就该换梯度下降了。我自己的习惯是拿到回归问题先跑一遍正态方程当基准看系数和误差量级再决定要不要上梯度下降做大规模版本。这个顺序帮我省过不少时间——有几次数据明明只有十几个特征却先写了梯度下降调了半天学习率回头一看正态方程一秒出结果。从那以后我每次遇到线性回归都先问一句特征到底多不多希望这个判断顺序也能帮到你。本文还有配套的精品资源点击获取