用Python+NumPy手把手实现最小二乘法:从拟合直线到理解投影矩阵
2026/4/22 21:58:56 网站建设 项目流程

用Python+NumPy手把手实现最小二乘法:从拟合直线到理解投影矩阵

在数据科学和机器学习领域,最小二乘法是一个基础但极其重要的概念。无论是简单的线性回归还是复杂的神经网络,最小二乘法的思想都贯穿其中。本文将通过Python和NumPy库,从零开始实现最小二乘法,并通过可视化的方式帮助理解其背后的线性代数原理——特别是投影矩阵的概念。

1. 最小二乘法基础与问题设定

最小二乘法要解决的核心问题是:当线性方程组Ax=b无解时,如何找到一个"最优"的近似解x̂。这种情况在实际中非常常见,比如当我们有大量观测数据点,希望用一条直线来拟合它们时。

考虑一个具体例子:有三个数据点(1,1)、(2,2)、(3,2),我们希望找到一条直线y=kx+b最好地拟合这些点。这可以表示为:

[1 1][k] [1] [2 1][b] = [2] [3 1] [2]

显然,这个方程组无解,因为没有一条直线能同时通过这三个点。最小二乘法的目标就是找到k和b,使得所有点到直线的垂直距离的平方和最小。

2. 投影矩阵法实现

投影矩阵法基于线性代数中的正交投影概念。核心思想是将向量b投影到矩阵A的列空间上,得到投影p,然后求解Ax̂=p。

实现步骤:

  1. 构造矩阵A和向量b:
import numpy as np A = np.array([[1, 1], [2, 1], [3, 1]]) b = np.array([1, 2, 2])
  1. 计算投影矩阵P:
P = A @ np.linalg.inv(A.T @ A) @ A.T
  1. 计算投影向量p:
p = P @ b
  1. 求解最小二乘解x̂:
x_hat = np.linalg.inv(A.T @ A) @ A.T @ b k, b = x_hat

关键点解析:

  • 投影矩阵P = A(AᵀA)⁻¹Aᵀ将任何向量投影到A的列空间
  • 误差向量e = b - p正交于A的列空间
  • 当A的列向量线性无关时,AᵀA可逆,保证了方法的可行性

3. 正规方程法实现

正规方程法是另一种常用的最小二乘法求解方式,直接求解方程AᵀAx̂ = Aᵀb。

实现代码:

# 构造正规方程 ATA = A.T @ A ATb = A.T @ b # 求解 x_hat = np.linalg.solve(ATA, ATb)

两种方法的比较:

方法优点缺点适用场景
投影矩阵法直观体现几何意义计算量大,需要求逆需要理解投影概念时
正规方程法计算直接高效数值稳定性较差大多数实际应用

提示:在实际应用中,当矩阵条件数较大时,建议使用QR分解或SVD等更稳定的方法。

4. 可视化理解与误差分析

为了更直观地理解最小二乘法,我们可以用matplotlib进行可视化:

import matplotlib.pyplot as plt # 原始数据点 x_data = A[:,0] y_data = b # 拟合直线 x_line = np.linspace(0, 4, 100) y_line = k * x_line + b plt.scatter(x_data, y_data, color='red', label='Data points') plt.plot(x_line, y_line, label=f'Fit line: y={k:.2f}x+{b:.2f}') # 绘制误差线 for x, y in zip(x_data, y_data): y_proj = k * x + b plt.plot([x, x], [y, y_proj], 'k--', alpha=0.3) plt.legend() plt.xlabel('x') plt.ylabel('y') plt.title('Least Squares Fit') plt.grid(True) plt.show()

误差分析:

  • 计算总误差平方和:
error = b - (A @ x_hat) total_error = np.sum(error**2)
  • 可以验证误差向量确实与A的列空间正交:
print(A.T @ error) # 应该接近[0, 0]

5. 实际应用与扩展

最小二乘法在实际中有广泛应用,从简单的线性回归到复杂的机器学习模型。理解其背后的数学原理对于处理更复杂的问题至关重要。

处理不可逆情况:当AᵀA不可逆时(A的列线性相关),可以:

  1. 使用伪逆(np.linalg.pinv)
  2. 添加正则化项(岭回归)
# 使用伪逆的例子 x_hat_pinv = np.linalg.pinv(A) @ b

扩展到多项式拟合:最小二乘法不仅限于直线拟合,可以扩展到多项式:

# 二次多项式拟合 A_quad = np.column_stack([x_data**2, x_data, np.ones_like(x_data)]) x_hat_quad = np.linalg.inv(A_quad.T @ A_quad) @ A_quad.T @ y_data

在实际项目中,我经常发现理解投影矩阵的概念对于调试模型非常有帮助。当拟合效果不理想时,检查误差向量是否确实与特征空间正交,可以快速判断实现是否正确。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询