保姆级教程:手把手教你用NumPy实现线性回归(含MSE和R²计算)

张开发
2026/6/7 14:40:06 15 分钟阅读

分享文章

保姆级教程:手把手教你用NumPy实现线性回归(含MSE和R²计算)
从零构建线性回归模型NumPy实战与数学原理深度解析线性回归是机器学习领域最基础也最重要的算法之一它不仅是数据科学入门的必修课更是理解更复杂模型的基石。很多初学者在学习理论后往往对如何用代码实现感到困惑——矩阵运算如何对应数学公式评估指标怎样计算参数如何优化本文将用NumPy从零开始构建完整的线性回归模型逐行解析代码背后的数学原理让你不仅会写代码更理解为什么这样写。我们将从最基础的矩阵运算开始逐步实现正规方程求解、预测函数、MSE和R²评估指标最终封装成一个完整的LinearRegression类。整个过程无需任何机器学习框架仅用NumPy就能完成。跟随本教程你将在Jupyter Notebook或Python环境中亲手实现一个可运行、可复现的线性回归模型真正掌握算法本质。1. 环境准备与数据理解在开始编码前我们需要确保环境配置正确并理解线性回归的基本假设。线性回归的核心是找到一条最佳拟合直线或超平面使得预测值与真实值之间的误差最小。数学上表示为y Xθ ε其中y是目标变量X是特征矩阵θ是参数向量ε是误差项准备工作清单安装Python 3.6和NumPy库pip install numpy推荐使用Jupyter Notebook进行交互式开发准备示例数据或使用sklearn内置数据集测试提示虽然我们会用NumPy实现但了解scikit-learn的API设计很有帮助。我们最终的类将模仿sklearn的fit/predict接口。2. 核心数学原理与NumPy实现2.1 正规方程推导线性回归的参数θ可以通过正规方程直接计算θ (XᵀX)⁻¹Xᵀy这个公式看起来简单但包含了几个关键矩阵运算# 计算θ的NumPy实现 X_with_bias np.hstack([X, np.ones((len(X), 1))]) # 添加偏置列 theta np.linalg.inv(X_with_bias.T.dot(X_with_bias)).dot(X_with_bias.T).dot(y)关键点解析np.hstack用于在特征矩阵X右侧添加一列1对应偏置项截距X.T.dot(X)计算XᵀX需要确保矩阵可逆即特征不共线np.linalg.inv计算矩阵逆对于大型矩阵可能效率较低2.2 预测函数实现得到θ后预测就是简单的矩阵乘法def predict(X, theta): X_with_bias np.hstack([X, np.ones((len(X), 1))]) return X_with_bias.dot(theta)这个预测函数将作为我们LinearRegression类的核心方法之一。3. 评估指标实现模型训练后我们需要量化其性能。最常用的两个指标是均方误差(MSE)和决定系数(R²)。3.1 均方误差(MSE)实现MSE衡量预测值与真实值的平均平方误差def mse_score(y_true, y_pred): return np.mean((y_pred - y_true)**2)MSE特点值越小越好完美模型为0对异常值敏感因为平方放大误差与目标变量同量纲的平方3.2 决定系数(R²)实现R²表示模型解释的方差比例计算为def r2_score(y_true, y_pred): y_mean np.mean(y_true) ss_total np.sum((y_true - y_mean)**2) ss_res np.sum((y_pred - y_true)**2) return 1 - (ss_res / ss_total)R²解读范围通常在0到1之间可能为负1表示完美拟合0表示不优于均值预测负数表示模型比简单取均值还差4. 完整LinearRegression类封装现在我们将上述功能封装成一个类模仿sklearn的API设计class LinearRegression: def __init__(self): self.theta None def fit(self, X, y): 使用正规方程拟合模型 X_with_bias np.hstack([X, np.ones((len(X), 1))]) self.theta np.linalg.inv(X_with_bias.T.dot(X_with_bias)).dot(X_with_bias.T).dot(y) return self def predict(self, X): 生成预测 if self.theta is None: raise ValueError(Model not fitted yet. Call fit() first.) X_with_bias np.hstack([X, np.ones((len(X), 1))]) return X_with_bias.dot(self.theta) def score(self, X, y): 计算R²分数 y_pred self.predict(X) return r2_score(y, y_pred)使用方法示例# 生成示例数据 np.random.seed(42) X 2 * np.random.rand(100, 1) y 4 3 * X np.random.randn(100, 1) # 创建并训练模型 model LinearRegression() model.fit(X, y) # 预测和评估 X_new np.array([[0], [2]]) y_pred model.predict(X_new) print(f模型参数: {model.theta}) print(fR²分数: {model.score(X, y)})5. 进阶优化与注意事项虽然我们的实现已经可用但在实际应用中还需要考虑以下方面5.1 数值稳定性优化正规方程中的矩阵求逆可能数值不稳定特别是当特征之间存在高度相关性时。可以添加一个小常数到对角线岭回归思想# 更稳健的θ计算 identity np.eye(X_with_bias.shape[1]) self.theta np.linalg.inv(X_with_bias.T.dot(X_with_bias) 1e-5 * identity).dot(X_with_bias.T).dot(y)5.2 大数据集处理对于非常大的数据集正规方程可能效率低下可以考虑使用梯度下降替代分批次计算使用伪逆而非直接求逆5.3 特征工程建议虽然线性回归简单但特征处理至关重要标准化/归一化特征特别是使用正则化时检查多重共线性考虑添加多项式特征6. 与scikit-learn对比测试为了验证我们的实现可以与sklearn的结果对比from sklearn.linear_model import LinearRegression as SKLinearRegression # sklearn实现 sk_model SKLinearRegression() sk_model.fit(X, y) print(f我们的θ: {model.theta.flatten()}) print(fsklearn的θ: {np.append(sk_model.coef_.flatten(), sk_model.intercept_)})在正确实现的情况下两者的参数估计应该非常接近可能因数值计算精度有微小差异。

更多文章