多元线性回归入门:从原理推导到工程实践

发布时间:2026/10/16 18:15:12
多元线性回归入门:从原理推导到工程实践 1. 为什么从多元线性回归开始讲起如果你翻过任何一本机器学习的入门教材大概率会发现回归问题总是被放在最前面。这不是巧合也不是作者偷懒。回归是整个监督学习体系里最基础、最直观、也最容易建立直觉的一块内容。而多元线性回归又是回归家族里最核心的那根支柱。我见过不少朋友一上来就去啃神经网络、集成学习结果调参调得一头雾水损失函数震荡得像心电图最后回头补基础才发现很多问题的根子其实在回归这一层就没打牢。比如梯度下降为什么有时候不收敛、特征为什么要做标准化、正则化到底在惩罚什么这些问题在多元线性回归里全都能找到最朴素的答案。这篇文章要聊的就是多元线性回归。它解决的是一个非常现实的问题当我们面对多个影响因素时怎么用一个统一的模型去描述它们和目标值之间的关系。比如房价受面积、楼层、地段、房龄等多个因素影响销售额受广告投入、季节、定价、竞品数量等多个因素影响。单个变量的一元线性回归在这些场景下明显不够用多元线性回归就是用来处理这种多对一映射关系的。适合谁来读如果你刚接触机器学习正在学回归部分这篇文章可以帮你把概念、推导、代码实现和踩坑经验一次性串起来。如果你已经用过线性回归但只是调包没仔细想过背后的原理那正好可以借这个机会把底层逻辑补上。我会尽量用大白话把数学讲清楚同时给出可以直接跑的代码和实操中真正会遇到的问题。2. 多元线性回归到底在做什么2.1 从一元到多元的思维跃迁一元线性回归的公式大家应该都熟y wx b。一个输入x一个输出y模型要学的就是斜率w和截距b。放到二维平面上就是找一条直线去拟合散点。多元线性回归无非是把输入从一个变成多个。公式变成这样y w₁x₁ w₂x₂ ... wₙxₙ b这里的x₁到xₙ是n个特征w₁到wₙ是对应的权重b还是截距。虽然写起来只是多了几个字母但背后的几何意义变了。一元回归是在二维空间找一条线多元回归是在高维空间找一个超平面。三维空间里是一个平面四维以上就没法直观画出来了但数学上的处理方式是一致的。我习惯用一个类比来解释一元回归像是根据面积这一个指标去猜房价多元回归则是同时看面积、楼层、房龄、距离地铁远近等一堆指标综合判断。现实中显然后者更靠谱因为房价从来不是单一因素决定的。2.2 用矩阵形式统一表达逐个写w₁x₁ w₂x₂ ... 太啰嗦而且写代码的时候也不方便。所以实际中我们都会把它写成矩阵形式y Xw b其中X是m×n的特征矩阵m个样本n个特征w是n×1的权重向量y是m×1的预测值向量。如果习惯的话也可以把b吸收进w里给X额外加一列全为1的特征这样公式就简化成 y Xw更紧凑。为什么一定要用矩阵形式两个原因。第一表达简洁推导方便。第二计算效率高。矩阵运算在底层可以用BLAS这类高度优化的库来加速比写循环快几个数量级。你后面看sklearn或者PyTorch的源码线性层的实现本质上就是这个矩阵乘法。2.3 模型要学什么模型里未知的就是那组权重w和截距b。训练的过程就是找到一组最优的w和b使得模型预测值尽可能接近真实值。那怎么衡量接近这就引出了损失函数。最常用的是均方误差MSEL (1/m) * Σ(yᵢ - ŷᵢ)²其中yᵢ是真实值ŷᵢ是预测值m是样本数。这个损失函数对每个样本的误差取平方再求平均。取平方的好处是正负误差不会相互抵消而且对大误差的惩罚更重。求平均是为了让损失值和样本数量无关方便不同数据集之间比较。注意MSE对异常值非常敏感。因为误差被平方了一个偏离很远的点会贡献巨大的损失值把整个模型的参数往它那边拽。如果你的数据里有明显的异常点要么先清洗要么考虑用MAE平均绝对误差这类对异常值更鲁棒的损失函数。3. 参数怎么求两种主流解法3.1 正规方程一步到位的解析解对于线性回归损失函数是凸函数存在唯一的全局最优解。我们可以直接对损失函数求导令导数为零解出w的闭式解。推导过程这里不展开写每一步直接给结论w (XᵀX)⁻¹Xᵀy这就是著名的正规方程Normal Equation。它的优点是直接给出解析解不需要迭代不需要调学习率。对于特征数量比较少的数据集比如n小于几千用这个方法非常方便。但它有几个明显的局限。第一需要计算矩阵的逆时间复杂度大约是O(n³)特征一多就非常慢。第二XᵀX可能不可逆比如特征之间存在完全共线性或者样本数少于特征数。第三数值稳定性不如迭代方法当矩阵条件数很大时求逆的结果误差会比较大。实际中如果非要用正规方程一般会用伪逆pinv来替代直接求逆或者加一点正则化项让矩阵变得可逆。sklearn的LinearRegression默认用的就是类似正规方程的方法底层是SVD分解所以在中小规模数据上表现还不错。3.2 梯度下降迭代逼近的通用方法梯度下降是更通用的做法。它的思路很朴素先随机初始化一组参数然后计算损失函数对每个参数的梯度沿着梯度的反方向更新参数一步步逼近最优解。更新公式wⱼ : wⱼ - α * ∂L/∂wⱼ其中α是学习率控制每一步走多大。学习率太小收敛慢太大可能直接跨过最优点甚至发散。对于MSE损失梯度的推导结果是∂L/∂wⱼ (2/m) * Σ(yᵢ - ŷᵢ) * xᵢⱼ这个梯度有一个很直观的解释每个权重的更新量取决于预测误差和对应特征值的乘积。如果某个特征和误差正相关就减小这个特征的权重如果负相关就增大权重。梯度下降又分三种变体这个在实际操作中很关键类型每次用多少样本优点缺点批量梯度下降全部样本梯度准确收敛稳定数据量大时每步计算慢随机梯度下降1个样本每步快能跳出局部最优梯度噪声大收敛震荡小批量梯度下降一批样本兼顾速度和稳定性需要调batch size实际中几乎都用小批量梯度下降batch size一般取32、64、128、256这些值。为什么因为批量太大内存扛不住太小又利用不了矩阵运算的并行优势。小批量刚好卡在中间既快又稳。3.3 两种方法的选型建议我一般是这样判断的特征数在几千以内样本量也不算特别大直接用正规方程或者sklearn的默认解法省事。特征数上万或者数据量很大需要分批加载那就用梯度下降。另外如果你后面要扩展到逻辑回归、神经网络这些没有解析解的模型梯度下降是必须掌握的早点熟悉没坏处。实操心得不要一上来就纠结用哪种方法。先用sklearn的LinearRegression跑一个baseline出来看看效果。如果效果可以再考虑要不要自己手写梯度下降去优化。很多时候baseline已经够用了过度优化反而浪费时间。4. 手写实现从零搭建一个多元线性回归4.1 数据准备与特征工程我拿一个模拟数据集来演示。假设我们要预测某个商品的销量特征包括广告投入、价格、季节指数三个变量。数据是我用numpy随机生成的加了一些噪声模拟真实场景。import numpy as np import matplotlib.pyplot as plt np.random.seed(42) m 200 # 样本数 n 3 # 特征数 # 生成特征 X np.random.randn(m, n) # 真实权重和截距 true_w np.array([2.5, -1.8, 0.9]) true_b 4.0 # 生成目标值加噪声 y X true_w true_b np.random.randn(m) * 0.5生成完数据后有一件事必须做特征标准化。为什么因为不同特征的量纲可能差很多。比如广告投入可能是几十万价格可能是几十块季节指数在0到1之间。如果不做标准化梯度下降会走得很别扭因为不同维度的梯度尺度差异太大学习率很难同时适配所有维度。标准化的做法是每个特征减去均值再除以标准差X_mean X.mean(axis0) X_std X.std(axis0) X_norm (X - X_mean) / X_std注意测试集要用训练集的均值和标准差来标准化不能用自己的。这个细节很多人会忽略导致训练和推理时的数据分布不一致。4.2 损失函数与梯度计算损失函数用MSE梯度按前面推导的公式来def compute_loss(X, y, w, b): m len(y) y_pred X w b loss np.mean((y_pred - y) ** 2) return loss def compute_gradient(X, y, w, b): m len(y) y_pred X w b error y_pred - y dw (2 / m) * (X.T error) db (2 / m) * np.sum(error) return dw, db这里X.T error就是矩阵形式的梯度计算比写循环快很多。error是预测值减真实值形状是m×1。X.T是n×m乘起来得到n×1的梯度向量正好对应每个特征的权重梯度。4.3 训练循环与学习率选择训练循环的代码很直接def train(X, y, lr0.01, epochs1000): m, n X.shape w np.zeros(n) b 0.0 losses [] for epoch in range(epochs): dw, db compute_gradient(X, y, w, b) w - lr * dw b - lr * db loss compute_loss(X, y, w, b) losses.append(loss) if epoch % 100 0: print(fEpoch {epoch}, Loss: {loss:.4f}) return w, b, losses学习率的选择是个经验活。我一般从0.01开始试如果损失下降太慢就调大如果震荡或者发散就调小。有一个简单的判断方法把损失曲线画出来如果是一条平滑下降的曲线说明学习率合适如果上下抖动说明太大如果几乎不降说明太小。训练完之后把学到的权重和真实权重对比一下w, b, losses train(X_norm, y, lr0.05, epochs1000) print(学到的权重:, w) print(真实权重:, true_w) print(学到的截距:, b) print(真实截距:, true_b)正常情况下学到的权重应该和真实权重非常接近误差在0.1以内。如果差很多要么是学习率不对要么是迭代次数不够要么是数据本身有问题。4.4 用sklearn做对照验证手写实现跑通之后用sklearn跑一遍做对照确认自己的实现没问题from sklearn.linear_model import LinearRegression model LinearRegression() model.fit(X_norm, y) print(sklearn权重:, model.coef_) print(sklearn截距:, model.intercept_)如果两者结果接近说明手写实现是对的。如果差很多优先检查梯度公式有没有写错特别是那个2/m的系数很容易漏掉或者写错。注意事项手写实现的时候w的初始化不要全设为0以外的奇怪值。对于线性回归全零初始化是安全的因为损失函数是凸的不存在对称性问题。但如果你后面做神经网络全零初始化会导致所有神经元学到相同的东西那就必须用随机初始化了。5. 实操中真正会遇到的问题5.1 特征共线性模型看起来能用但权重不可信这是多元线性回归里最隐蔽的坑。什么叫共线性就是两个或多个特征之间存在高度相关性。比如你用面积和房间数同时预测房价这两个特征本身就高度相关模型就很难分清到底是哪个在起作用。共线性的后果是什么模型的预测值可能还行但权重的数值会变得非常大而且不稳定。你换一批数据重新训练权重可能完全变样。这就导致模型没法解释你没法说面积每增加一平米房价涨多少因为这个系数本身不可信。怎么检测计算特征之间的相关系数矩阵如果某两个特征的相关系数绝对值超过0.8就要警惕了。更严谨的方法是用方差膨胀因子VIFVIF大于10通常认为存在严重共线性。怎么解决三个思路。第一删掉其中一个特征保留物理意义更明确或者更容易获取的那个。第二用PCA降维把相关特征合并成主成分但代价是失去可解释性。第三用正则化岭回归L2对共线性有一定的缓解作用因为它会压缩权重。5.2 异常值一个点毁掉整个模型前面提过MSE对异常值敏感这里展开说。假设你的数据里有一个样本目标值因为录入错误多了一个零那这个点的误差会巨大平方之后更是天文数字。梯度下降会拼命去拟合这个点把整个超平面往它那边拉导致其他正常样本的预测全部变差。检测异常值的方法很多简单一点用箱线图的IQR规则复杂一点用孤立森林或者DBSCAN。我一般先用可视化看一眼散点图上明显偏离群体的点先标记出来再判断是删除、修正还是保留。实操心得不要无脑删异常值。有些异常值恰恰是业务上最有价值的样本比如欺诈检测里的异常交易。删之前先想清楚这个异常是数据错误还是真实信号。如果是真实信号删掉反而损失了信息。5.3 过拟合与欠拟合怎么判断怎么处理欠拟合的表现是训练集和测试集的损失都高模型太简单学不到数据的规律。对于线性回归欠拟合通常意味着特征不够或者特征和目标之间根本不是线性关系。解决办法是加特征、做特征交叉、或者换非线性模型。过拟合的表现是训练集损失很低测试集损失明显高出一截。线性回归本身不容易过拟合因为它的参数量等于特征数加一模型容量有限。但如果特征特别多、样本特别少照样会过拟合。解决办法是加正则化或者减少特征数量。判断方法很直接把数据分成训练集和测试集训练完看两个集合上的损失差距。差距大就是过拟合都大就是欠拟合。我习惯用70/30或者80/20的比例来分样本少的时候用交叉验证更稳。5.4 学习率调不好损失震荡或者不下降学习率的问题在梯度下降里太常见了。损失曲线如果出现明显的上下震荡基本可以确定是学习率太大。如果损失几乎不降那就是太小。还有一种情况是损失先降后升这叫发散也是学习率太大的表现。我的调参策略是从0.1开始每次除以3或者除以10试几个值看哪个损失曲线最平滑。另外如果特征标准化做好了学习率的容忍范围会宽很多。这也是为什么我一直强调标准化的重要性。进阶一点的做法是用学习率衰减比如每训练100轮学习率乘以0.9。这样前期步子大快速接近最优解后期步子小精细调整。或者用Adam这类自适应优化器它会自动调整每个参数的学习率省去手动调的麻烦。5.5 常见问题速查表问题现象可能原因排查方向解决办法损失不下降学习率太小、特征未标准化检查学习率和数据分布调大学习率、做标准化损失震荡学习率太大观察损失曲线调小学习率损失发散学习率过大、数据有异常值检查损失值和数据调小学习率、清洗异常值训练集好测试集差过拟合对比训练和测试损失加正则化、减特征权重数值异常大共线性计算相关系数矩阵删特征、用岭回归预测值偏移截距未学习、数据未中心化检查b的值确保b参与训练6. 正则化让模型更稳的两个武器6.1 岭回归给权重加一个约束岭回归Ridge在损失函数里加了一项L2正则化L MSE λ * Σwⱼ²这个λ控制正则化的强度。λ越大权重被压缩得越厉害模型越简单。λ为0就退化成普通线性回归。为什么L2正则化能缓解共线性因为当两个特征高度相关时普通回归会让它们的权重一个很大一个很小相互抵消。加了L2之后大权重会被惩罚模型倾向于把权重分摊到两个特征上数值更稳定。λ的选择一般用交叉验证来定。sklearn的RidgeCV可以自动帮你选from sklearn.linear_model import RidgeCV alphas [0.01, 0.1, 1.0, 10.0, 100.0] ridge RidgeCV(alphasalphas, cv5) ridge.fit(X_norm, y) print(最优alpha:, ridge.alpha_) print(权重:, ridge.coef_)6.2 Lasso回归顺便做特征选择Lasso用的是L1正则化L MSE λ * Σ|wⱼ|L1和L2的关键区别在于L1倾向于把不重要的特征权重直接压到0所以Lasso天然具有特征选择的功能。如果你的特征很多但真正有用的没几个Lasso能帮你自动筛掉那些没用的。不过Lasso也有缺点。当特征之间存在共线性时Lasso会随机保留其中一个而把其他的压到0这个选择过程不稳定。所以如果特征都有实际意义不想丢掉任何一个用岭回归更合适。from sklearn.linear_model import LassoCV lasso LassoCV(cv5, random_state42) lasso.fit(X_norm, y) print(非零权重数量:, np.sum(lasso.coef_ ! 0)) print(权重:, lasso.coef_)6.3 弹性网络两者兼顾弹性网络Elastic Net把L1和L2结合起来L MSE λ₁ * Σ|wⱼ| λ₂ * Σwⱼ²它既有Lasso的特征选择能力又有Ridge的稳定性。当特征数量特别多、且特征之间有相关性时弹性网络往往比单独用Lasso或Ridge效果更好。sklearn里用ElasticNetCV可以自动调参。实操心得正则化不是万能的。如果模型本身没有过拟合加正则化反而会让效果变差。我一般先跑一个不加正则化的baseline确认有过拟合迹象之后再考虑加正则化。不要一上来就默认加那样可能掩盖了真正的问题。7. 模型评估别只看MSE7.1 常用的几个评估指标MSE是最基础的但它的量纲是目标值的平方不好解释。比如你预测房价MSE是10000这个数字本身没有直观意义。所以实际中更常用RMSE均方根误差它把量纲还原回去了RMSE sqrt(MSE)还有MAE平均绝对误差它对异常值更鲁棒MAE (1/m) * Σ|yᵢ - ŷᵢ|以及R²决定系数它表示模型解释了目标值多少比例的方差R² 1 - SS_res / SS_totR²的范围是负无穷到1。等于1表示完美预测等于0表示模型和直接用均值预测一样差小于0表示模型还不如直接用均值。指标公式特点适用场景MSE均方误差对大误差敏感需要惩罚大偏差RMSE均方根误差量纲和目标一致通用评估MAE平均绝对误差对异常值鲁棒数据有噪声R²决定系数无量纲可跨数据集比较解释模型拟合程度7.2 交叉验证更可靠的评估方式单次划分训练集和测试集有个问题如果运气不好测试集恰好比较难或者比较容易评估结果就不准。交叉验证能缓解这个问题。K折交叉验证把数据分成K份每次用K-1份训练1份测试重复K次最后取平均。from sklearn.model_selection import cross_val_score scores cross_val_score(model, X_norm, y, cv5, scoringneg_mean_squared_error) rmse_scores np.sqrt(-scores) print(交叉验证RMSE:, rmse_scores.mean())注意sklearn的scoring参数里MSE是负数因为它默认分数越大越好而MSE越小越好所以取了个负号。这个细节第一次用的时候很容易搞混。7.3 残差分析看模型哪里没学好光看一个数字不够还要看残差。残差就是真实值减预测值。把残差画成图能看出很多问题。如果残差随机分布在0附近没有明显规律说明模型拟合得不错。如果残差呈现U型或者倒U型说明特征和目标之间可能存在非线性关系线性模型不够用。如果残差随着预测值增大而增大说明存在异方差性可能需要做目标值变换比如取对数。y_pred model.predict(X_norm) residuals y - y_pred plt.scatter(y_pred, residuals) plt.axhline(y0, colorr, linestyle--) plt.xlabel(预测值) plt.ylabel(残差) plt.show()这个图我每次做完回归都会看一眼比看MSE有用得多。MSE只告诉你误差多大残差图告诉你误差在哪里、为什么。8. 从多元线性回归往外延伸多元线性回归虽然简单但它是很多更复杂模型的基础。理解它之后往几个方向扩展都会很顺。第一个方向是多项式回归。如果特征和目标之间不是线性关系可以给特征加高次项比如x²、x³然后还是用线性回归去拟合。本质上是在更高维的空间里做线性拟合但映射回原始空间就是曲线。sklearn的PolynomialFeatures可以自动生成这些高次项。第二个方向是广义线性模型。线性回归假设目标值服从正态分布如果目标值是计数数据比如某段时间内的订单数可能更适合泊松回归如果目标值是二分类的买或不买那就是逻辑回归。这些都属于广义线性模型的范畴核心思想还是线性组合加一个链接函数。第三个方向是正则化和贝叶斯视角。岭回归其实等价于给权重加了高斯先验的贝叶斯线性回归Lasso等价于拉普拉斯先验。从贝叶斯角度理解正则化能帮你更清楚地知道什么时候该用哪种正则化。第四个方向是特征工程。线性回归的效果很大程度上取决于特征做得好不好。特征交叉、分箱、目标编码这些技巧在线性模型上往往比换模型更有效。我见过很多案例把特征工程做好之后线性回归的效果能逼近甚至超过一些复杂的非线性模型。最后分享一个小技巧如果你不确定该用哪个模型先把线性回归跑通作为baseline。它的训练速度快、可解释性强、不容易出幺蛾子。如果线性回归的效果已经满足业务需求那就没必要上更复杂的模型。很多时候简单模型加好特征比复杂模型加烂特征强得多。

关于本文作者

来自尧图内容编辑团队

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

尧图内容编辑团队

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

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

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

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

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

网站改版的5个关键决策

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

获取专属建站方案

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

立即免费咨询