用Python代码拆解线性回归的正规方程从数学公式到NumPy实战线性回归是机器学习中最基础的算法之一而正规方程Normal Equation则是求解线性回归参数的经典方法。很多学习者虽然能记住θ (XᵀX)⁻¹Xᵀy这个公式但对其中每个矩阵运算的实际含义和计算过程却感到抽象。本文将用Python和NumPy一步步拆解这个黑箱让你真正理解正规方程背后的数学原理和代码实现。1. 线性回归与正规方程基础线性回归的目标是找到一组参数θ使得预测值ŷ Xθ与真实值y之间的误差最小。正规方程提供了一种解析解法直接计算出最优参数θθ (XᵀX)⁻¹Xᵀy这个看似简单的公式包含了多个关键步骤添加偏置项在原始特征矩阵X左侧添加一列1用于拟合截距项计算XᵀX特征矩阵的转置与自身的乘积矩阵求逆计算(XᵀX)的逆矩阵连乘计算依次完成(XᵀX)⁻¹Xᵀy的矩阵乘法注意正规方程法在特征数量较大时n10000计算效率会显著下降此时梯度下降法更为适合。2. 准备示例数据集为了更好地理解计算过程我们先创建一个简单的二维数据集import numpy as np # 创建特征矩阵X4个样本1个特征 X np.array([[1], [2], [3], [4]]) # 创建标签向量y y np.array([[2], [3.5], [5.5], [7]]) print(原始特征矩阵X:\n, X) print(标签向量y:\n, y)输出结果原始特征矩阵X: [[1] [2] [3] [4]] 标签向量y: [[2. ] [3.5] [5.5] [7. ]]3. 逐步拆解正规方程计算3.1 添加偏置列正规方程需要计算截距项θ₀因此我们需要在特征矩阵X左侧添加一列1# 添加偏置列全1列 X_b np.hstack([np.ones((len(X), 1)), X]) print(添加偏置后的矩阵X_b:\n, X_b) print(矩阵形状:, X_b.shape)输出添加偏置后的矩阵X_b: [[1. 1.] [1. 2.] [1. 3.] [1. 4.]] 矩阵形状: (4, 2)3.2 计算XᵀX接下来计算特征矩阵的转置与自身的乘积# 计算XᵀX XTX X_b.T.dot(X_b) print(XᵀX矩阵:\n, XTX) print(矩阵形状:, XTX.shape)输出XᵀX矩阵: [[ 4. 10.] [10. 30.]] 矩阵形状: (2, 2)3.3 计算(XᵀX)⁻¹这一步需要对矩阵求逆NumPy提供了np.linalg.inv()函数# 计算(XᵀX)的逆矩阵 XTX_inv np.linalg.inv(XTX) print((XᵀX)⁻¹矩阵:\n, XTX_inv) print(矩阵形状:, XTX_inv.shape)输出(XᵀX)⁻¹矩阵: [[ 1.5 -0.5] [-0.5 0.2]] 矩阵形状: (2, 2)3.4 计算Xᵀy现在计算特征矩阵转置与标签向量的乘积# 计算Xᵀy XTy X_b.T.dot(y) print(Xᵀy矩阵:\n, XTy) print(矩阵形状:, XTy.shape)输出Xᵀy矩阵: [[18. ] [49.5]] 矩阵形状: (2, 1)3.5 最终参数计算将前面所有步骤组合起来计算最终参数θ# 计算θ (XᵀX)⁻¹Xᵀy theta XTX_inv.dot(XTy) print(最优参数θ:\n, theta)输出最优参数θ: [[0.45] [1.65]]4. 验证计算结果为了验证我们的分步计算是否正确可以直接使用NumPy的一行代码实现# 使用NumPy直接计算 theta_np np.linalg.inv(X_b.T.dot(X_b)).dot(X_b.T).dot(y) print(NumPy直接计算结果:\n, theta_np)输出结果应与分步计算一致NumPy直接计算结果: [[0.45] [1.65]]5. 数学原理深度解析为什么正规方程能求出最优参数这背后是最小二乘法的数学原理损失函数线性回归使用均方误差(MSE)作为损失函数J(θ) 1/(2m) * Σ(ŷⁱ - yⁱ)² 1/(2m) * (Xθ - y)ᵀ(Xθ - y)求导置零对J(θ)关于θ求导并令导数为零得到正规方程∇J(θ) Xᵀ(Xθ - y) 0 ⇒ XᵀXθ Xᵀy解方程当XᵀX可逆时解得θ (XᵀX)⁻¹Xᵀy6. 实际应用中的注意事项虽然正规方程提供了解析解但在实际应用中需要考虑以下因素矩阵可逆性当特征之间存在线性相关性或样本数少于特征数时XᵀX可能不可逆计算复杂度矩阵求逆的复杂度是O(n³)特征维度高时计算代价大数值稳定性对于病态矩阵求逆可能导致数值不稳定替代方案包括使用伪逆np.linalg.pinv引入正则化岭回归采用梯度下降法7. 完整实现线性回归类将上述过程封装成一个完整的线性回归类class LinearRegression: def __init__(self): self.theta None def fit(self, X, y): # 添加偏置列 X_b np.hstack([np.ones((len(X), 1)), X]) # 计算正规方程 self.theta np.linalg.inv(X_b.T.dot(X_b)).dot(X_b.T).dot(y) return self def predict(self, X): # 添加偏置列 X_b np.hstack([np.ones((len(X), 1)), X]) return X_b.dot(self.theta)使用示例# 创建模型实例 model LinearRegression() # 训练模型 model.fit(X, y) # 预测新数据 X_new np.array([[5], [6]]) print(预测结果:, model.predict(X_new))8. 可视化理解为了更直观地理解线性回归的拟合效果我们可以绘制数据和回归线import matplotlib.pyplot as plt # 绘制原始数据点 plt.scatter(X, y, colorblue, labelData points) # 绘制回归线 X_range np.linspace(0, 5, 100).reshape(-1, 1) y_pred model.predict(X_range) plt.plot(X_range, y_pred, colorred, labelRegression line) plt.xlabel(Feature X) plt.ylabel(Target y) plt.legend() plt.show()这个可视化展示了我们的线性回归模型如何拟合数据点以及预测值如何沿着回归线分布。