FEATURED · 精选文章

线性回归算法代码实战:从最小二乘到sklearn正则化

发布时间 / 2026/9/12 2:39:58
来源 / 创域科博编辑部
栏目 / 资讯中心
线性回归算法代码实战:从最小二乘到sklearn正则化 简介线性回归算法代码.zip 是一份面向机器学习初学者的 Python 实现示例通过实际代码演示线性回归的完整建模流程包括数据准备、模型训练、预测与评估。压缩包共 3 个文件内含两个分场景的 Python 脚本和一份说明文档整体仅 324KB轻量易用适合快速下载学习。已有 1082 人学习使用是入门线性回归时值得参考的动手素材。两个脚本分别针对单自变量与多自变量情形帮助读者理解简单线性回归与多元线性回归的差异代码基于 sklearn 实现并利用最小二乘法拟合最佳直线同时展示 R² 分数评估模型效果。配套文档对算法原理、关键函数和参数做了简要注释便于结合数学推导深入掌握。通过研读这份资源学习者既能掌握线性回归的 Python 实现也能为后续学习岭回归、Lasso 等扩展模型建立扎实基础。1. 线性回归算法代码解压就能跑的两个Python文件藏着哪些门道拿到线性回归算法代码.zip的时候我第一反应是先看那两个问题1.py和问题2.py是演示脚本还是半成品作业。解压后发现它们互为递进一个是单变量回归另一个是多变量回归而且都没有用复杂封装适合直接改数据换成自己的场景。很多人在sklearn里调一行LinearRegression().fit(X, y)就把线性回归学完了但真正遇到实际问题时会卡在数据切分、特征尺度、共线性诊断这些步骤上。这篇博文就顺着这两个脚本把线性回归的最小二乘原理、sklearn实现、评估指标和正则化边界拆开讲一遍目标是让你拿到代码后不仅会跑还知道怎么改参数、什么时候该换模型。2. 从ywxb到最小二乘线性回归的数学模型和sklearn选型边界2.1 损失函数和解析解为什么最小二乘法是默认选择线性回归的核心假设是目标变量y和特征X之间存在线性关系模型写成y wX b。其中w是回归系数b是截距。训练过程要找到一组w和b让所有样本的预测值和真实值之间的差距尽量小。这里的“差距”通常用残差平方和表示也就是损失函数L Σ(y_i - ŷ_i)^2。最小二乘法的名字就来自这个“最小化平方残差”的过程。sklearn里的LinearRegression默认使用最小二乘法它通过矩阵运算直接求解析解而不是用梯度下降迭代。解析解的形式是w (X^T X)^{-1} X^T y在包含截距的增广矩阵下。这个解成立的前提是X^T X可逆也就是特征之间不存在完全的多重共线性。如果两个特征完全线性相关矩阵就退化了计算结果会不稳定。import numpy as np def linear_regression_closed_form(X, y): # 在X前面加一列1用来拟合截距b X_b np.c_[np.ones((X.shape[0], 1)), X] # 使用正规方程求解 w (X^T X)^-1 X^T y theta np.linalg.inv(X_b.T X_b) X_b.T y return theta[0], theta[1:]这段代码展示了最小二乘的矩阵实现np.c_把全1列拼到特征矩阵左侧让截距变成普通系数的一部分是矩阵乘法np.linalg.inv求逆矩阵。实际项目中很少手写这个逻辑因为sklearn在数值稳定性上做了优化比如使用SVD分解而不是直接求逆但理解这个公式能帮你明白为什么特征过多或共线性严重时系数会变得很大甚至符号异常。2.2 简单回归与多元回归的适用场景简单线性回归只有一个自变量模型形式是y wx b可以在二维坐标里画出一条直线。它最大的优点是可视化友好能直接看到拟合线是否穿过数据云。代码包里的问题1.py就属于这一类。多元线性回归则包含两个或两个以上自变量模型写成y w1*x1 w2*x2 ... wn*xn b。此时不能再靠肉眼判断拟合效果必须依赖R2、残差图等统计量。维度简单线性回归多元线性回归自变量数量1个2个及以上模型复杂度低中低可视化方式散点图拟合直线残差图、预测值对比图主要风险欠拟合多重共线性、过拟合评估指标R2、均方误差MSER2、调整R2、交叉验证选择哪种回归不是看文件大小而是看业务问题里到底有几个可能影响结果的变量。比如做房价预测只有面积一个特征是合理起步一旦加入房龄、地段、楼层就必须用多元回归。问题2.py演示的正是后者。2.3 sklearn LinearRegression之外的选项sklearn的LinearRegression适用于特征间相关性不强、样本量相对充足、且目标变量近似服从正态分布的场景。当数据存在多重共线性时岭回归Ridge通过在损失函数中加入L2正则项来缩小系数Lasso则用L1正则项把部分系数压缩到0起到特征选择作用。两者都是在LinearRegression基础上的改进后面的问题2.py对比就会涉及。3. 问题1.py单变量回归实战从数据切分到R2评估的最小可运行示例3.1 模拟数据为什么要加噪声问题1.py如果用sklearn实现通常会先构造一份带噪声的数据。常见做法是用numpy随机生成自变量X再通过一个已知线性关系计算出目标值并添加高斯噪声。噪声的作用是模拟真实环境里的观测误差。如果没有噪声拟合出的直线会完全精确但这种情况在现实中不存在。import numpy as np from sklearn.model_selection import train_test_split from sklearn.linear_model import LinearRegression # 固定随机种子保证结果可复现 rng np.random.RandomState(42) X rng.uniform(0, 10, size(120, 1)) # 真实关系是 y 2.5x 3噪声标准差为2 y 2.5 * X.ravel() 3 rng.randn(120) * 2 X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42 ) model LinearRegression() model.fit(X_train, y_train) print(系数 w:, model.coef_) print(截距 b:, model.intercept_) print(训练集 R2:, model.score(X_train, y_train)) print(测试集 R2:, model.score(X_test, y_test))这里rng.uniform(0, 10, size(120, 1))生成120个在0和10之间均匀分布的值形状是120行1列符合sklearn要求的二维特征矩阵。Ravel()把形状压成一维是为了能直接和y的长度匹配。rng.randn(120) * 2产生均值为0、标准差为2的高斯噪声模拟真实数据中无法解释的随机波动。虽然最终拟合出的系数不会精确等于2.5但会落在2.5附近这正是线性回归通过最小化残差平方和找到的最佳近似直线。3.2 训练集测试集划分参数怎么设train_test_split里两个参数需要特别留意test_size0.2表示随机抽取20%的样本作为测试集剩下的80%用于训练。二八分是一种工程默认值样本量很小的时候可以调到test_size0.3但要注意测试集如果太小评估结果方差会很大。random_state42是随机种子固定它可以保证每次运行切分结果一致方便复现。调试阶段建议固定正式实验阶段可以考虑用交叉验证替代单一切分。提示解压zip文件后如果直接运行记得先确认工作目录里有问题1.py或者在终端里cd到对应目录否则可能出现ModuleNotFoundError。更稳妥的做法是pip install numpy scikit-learn之后再执行。3.3 系数、截距和R2的解读边界拟合后打印的coef_是斜率通过它可以看出X每增加1个单位y平均增加多少。intercept_是截距代表X0时的预测值。这两个参数是线性回归中最容易解释的部分但要注意它们只在当前特征尺度下有意义如果后续做了标准化系数含义会变。score方法返回R2分数公式为R2 1 - SS_res / SS_tot其中SS_res是残差平方和SS_tot是总离差平方和。R2越接近1说明模型解释的变异比例越高。但它有两个盲区一是只看R2无法判断是否存在过拟合所以必须同时对比训练集和测试集分数二是在预测任务里R2不是唯一的评价标准还要结合MSE看误差的绝对量级。运行上面代码后训练集R2通常落在0.6到0.8之间具体值取决于噪声大小。4. 问题2.py多元回归多重共线性、特征缩放与正则化对比4.1 读取真实数据集和标准化流程问题2.py相比问题1.py的关键升级是特征从1个变成了多个。以sklearn自带的糖尿病数据集为例每个样本有10个生理指标属性目标变量是一年后病情进展的数值。这类数据通常量纲不一致比如年龄和血压就完全不在一个尺度上。如果直接用原始值做回归大数值的特征会主导w的计算结果且系数解空间变得病态。import pandas as pd from sklearn.datasets import load_diabetes from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler from sklearn.linear_model import LinearRegression, Ridge, Lasso data load_diabetes() X data.data y data.target X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state0 ) # 用训练集的均值和标准差做标准化然后应用到测试集 scaler StandardScaler() X_train_s scaler.fit_transform(X_train) X_test_s scaler.transform(X_test) models { LinearRegression: LinearRegression(), Ridge(alpha1.0): Ridge(alpha1.0), Lasso(alpha0.1): Lasso(alpha0.1) } for name, model in models.items(): model.fit(X_train_s, y_train) train_score model.score(X_train_s, y_train) test_score model.score(X_test_s, y_test) print(f{name} 训练集R2{train_score:.3f} 测试集R2{test_score:.3f})StandardScaler的fit_transform先用训练集数据计算出均值和标准差再把训练集做标准化。测试集上只能调用transform不能用它自己的数据重新fit否则会造成信息泄漏让测试集评估结果虚高。这一步是所有线性模型最容易出错的地方。Ridge和Lasso的alpha参数控制正则化强度alpha越大系数被压缩得越厉害偏差会增加但方差减少。4.2 线性回归在多元场景下的不稳定表现多元线性回归的问题在于特征之间如果存在强相关关系X^T X的条件数会变得很大。此时最小二乘解虽然存在但对数据中的微小扰动极其敏感。一个典型现象是训练集R2很高但测试集R2骤降或者某个特征的系数符号和业务直觉相反。这就是多重共线性的典型信号。以糖尿病数据集为例有些特征天然存在相关性。直接用LinearRegression得到的结果往往测试集R2偏低。对比上面代码输出的三个模型分数你会看到LinearRegression在训练集上表现很好但在测试集上可能还不如Ridge。原因就是正则化通过对系数施加惩罚抑制了那些由共线性带来的大系数波动。场景推荐手段原因特征间完全无关普通线性回归解析解稳定系数可解释特征间中度相关RidgeL2惩罚限制系数大小特征多且希望筛选LassoL1惩罚将部分系数置零数据量小于特征数不能直接用普通线性回归最小二乘无唯一解必须正则化4.3 Ridge和Lasso正则化的系数收缩Ridge的损失函数在最小二乘基础上加了alpha * Σ(w_i^2)它的作用是均匀地缩小所有特征的系数但不把任何系数变成0。Lasso加的是alpha * Σ|w_i|因为L1约束在几何上更容易让解落在坐标轴上系数会精确变成0所以可以把Lasso当成一种嵌入式的特征选择方法。调整alpha时常见错误是直接取默认值。一般来说我会先用GridSearchCV在1e-3到1e2的对数空间里搜一遍以交叉验证分数的均值和方差为准。需要特别说明的是Lasso对特征尺度更敏感标准化比Ridge更关键。如果alpha调得过大模型会把所有系数都压到0训练集和测试集R2都会变成负值说明模型反而比直接用均值预测更差。注意不要只对比一个测试集上的R2就下结论。多元线性回归的测试集分数会受数据划分方式影响换一个random_state可能结果就不同。正确做法是搭配本章后面讲到的交叉验证来看总体趋势。5. 残差检验和交叉验证线性回归代码上线前的两个加固动作5.1 残差图里看模型假设立没立住线性回归的数学推导依赖几个关键假设误差独立、正态分布、均值为0、方差恒定。很多人拟合完模型只看R2就完事但R2高不代表误差模式健康。一个快速检查方法是把预测值放在横轴残差放在纵轴画散点图。如果残差是均匀分布在0两侧的随机带说明模型结构合理如果出现明显的漏斗形状也就是预测值变大时残差散布范围也变大就说明存在异方差性需要使用加权最小二乘或对目标变量做变换。import matplotlib.pyplot as plt # 用Ridge模型预测测试集并绘制残差图 y_pred models[Ridge(alpha1.0)].predict(X_test_s) residuals y_test - y_pred plt.scatter(y_pred, residuals, alpha0.6) plt.axhline(y0, colorred, linestyle--) plt.xlabel(Predicted Value) plt.ylabel(Residuals)这段代码把模型在测试集上的残差可视化。如果发现红色水平线上下两侧的点基本对称且没有明显的曲线关系说明线性假设基本成立如果残差随预测值增大而扩散就要考虑给目标变量取对数。残差图是判断模型假设是否被突破时优先使用的工具。5.2 交叉验证避免用一个测试集定结论单个训练集/测试集划分的问题是结果方差大尤其是数据集只有几百条时。把数据切成5份轮流用其中4份训练、1份验证最后得到5个验证分数平均数和标准差才是更稳的评价。sklearn里的cross_val_score可以直接复用已经标准化的模型。from sklearn.model_selection import cross_val_score ridge Ridge(alpha1.0) scores cross_val_score(ridge, X_train_s, y_train, cv5, scoringr2) print(交叉验证 R2:, scores) print(平均 R2:, scores.mean().round(3), 标准差:, scores.std().round(3))cv5表示五折交叉验证scoringr2指定评估指标。输出数组里的每个元素代表一折验证集上的R2。如果标准差很大说明模型在部分数据子集上很不稳定此时优先检查特征是否包含极端离群点或考虑增强正则化。5.3 模型持久化的顺手写法脚本调试完成后实际部署时一般会把训练好的模型保存下来避免每次预测都重新训练。joblib和pickle都能做到joblib对大数组的序列化效率更高是业内常见做法。from joblib import dump, load dump(ridge, ridge_model.joblib) # 新环境里加载 loaded_model load(ridge_model.joblib) new_pred loaded_model.predict(X_test_s)dump保存模型时建议把特征标准化器scaler也一起保存因为新数据进入预测流程之前必须使用同样的均值和标准差做变换。常见坑是只存模型不存scaler导致线上预测时数据尺度不一致结果完全失真。保存代码和加载代码最好成对出现并记录对应的特征名列表这样后续排查问题时不至于对着一个训练集与测试集分布不一致的模型盲目调参数。本文还有配套的精品资源点击获取
RELATED — 相关阅读

相关资讯

LATEST — 最新资讯

最新发布

TODAY — 本日精选

新闻

WEEKLY — 本周精选

新闻

MONTHLY — 本月精选

新闻