You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

线性最小二乘拟合数据点效果不佳,求原因及修正方案

线性最小二乘拟合平面效果差的问题分析与解决

问题描述

使用以下代码进行2D平面的线性最小二乘拟合时,尽管两种方法得到的系数一致,但拟合平面效果严重失真:

import numpy as np
from scipy import linalg as la
from scipy.linalg import solve

# data
f1 = np.array([1., 1.5, 3.5, 4.])
f2 =  np.array([3., 4., 7., 7.25])
# z = np.array([6., 6.5, 8., 9.])
A= X= np.array([f1, f2]).T

b= y= np.array([0.5, 1., 1.5, 2.]).T

##################### la.lstsq

res= la.lstsq(A,b)[0]
print(res)    
##################### custom lu

#custom OLS 
def ord_ls(X, y):
    A = X.T @ X
    b = X.T @ y
    beta = solve(A, b, overwrite_a=True, overwrite_b=True,
                 check_finite=True)
    return beta

res = ord_ls(X, y)
print(res)

##################### plot

# use the optimized parameters to plot the fitted curve in 3D space.
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

# Create 3D plot of the data points and the fitted curve
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.scatter(f1, f2, y, color='blue')
x_range = np.linspace(0, 7, 100)
y_range = np.linspace(0, 7,100)

X, Y = np.meshgrid(x_range, y_range)
Z = res[0]*X + res[1]

ax.plot_surface(X, Y, Z, color='red', alpha=0.5)
ax.set_xlabel('feat.1')
ax.set_ylabel('feat.2')
ax.set_zlabel('target')
plt.show()

# [0.2961165  0.09475728]
# [0.2961165  0.09475728]

疑问:拟合平面失真的原因是什么?如何修正?是否需要正则化?是否是特征共线性导致的?

附:需将scipy-0.18.0文档第184页的LU分解代码p, l, u = la.lu(A)翻译成中文。


问题原因

  1. 核心问题:缺失截距项
    标准线性回归模型应为 z = β₀ + β₁*f1 + β₂*f2,其中β₀是截距项(代表当所有特征为0时的预测值)。你的代码中仅对f1和f2拟合了系数β₁、β₂,完全忽略了截距β₀,导致拟合平面强制过原点,这是效果失真的主要原因。

  2. 次要问题:特征高度共线性
    计算f1和f2的相关系数:np.corrcoef(f1, f2)[0,1]结果约为0.999,说明两个特征高度线性相关。共线性会导致系数估计的方差变大,稳定性下降,但当前平面失真的核心原因是缺失截距,而非共线性。


修正方法

1. 添加截距项到特征矩阵

在特征矩阵X中添加一列全1的常数项,用于拟合截距β₀:

# 修改数据部分:添加截距项
X = np.hstack([np.ones((len(f1),1)), np.array([f1, f2]).T])

2. 修正拟合与绘图代码

修正后的完整代码:

import numpy as np
from scipy import linalg as la
from scipy.linalg import solve
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

# data
f1 = np.array([1., 1.5, 3.5, 4.])
f2 = np.array([3., 4., 7., 7.25])
y = np.array([0.5, 1., 1.5, 2.]).T

# 添加截距项:特征矩阵第一列为全1
X = np.hstack([np.ones((len(f1), 1)), np.array([f1, f2]).T])

##################### la.lstsq
res_lstsq = la.lstsq(X, y)[0]
print("lstsq结果(截距β0, β1, β2):", res_lstsq)

##################### custom lu
def ord_ls(X, y):
    A = X.T @ X
    b = X.T @ y
    beta = solve(A, b, overwrite_a=True, overwrite_b=True, check_finite=True)
    return beta

res_custom = ord_ls(X, y)
print("自定义OLS结果(截距β0, β1, β2):", res_custom)

##################### plot
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.scatter(f1, f2, y, color='blue')

x_range = np.linspace(0, 7, 100)
y_range = np.linspace(0, 7, 100)
X_mesh, Y_mesh = np.meshgrid(x_range, y_range)

# 计算拟合平面:Z = β0 + β1*X + β2*Y
Z_mesh = res_custom[0] + res_custom[1]*X_mesh + res_custom[2]*Y_mesh

ax.plot_surface(X_mesh, Y_mesh, Z_mesh, color='red', alpha=0.5)
ax.set_xlabel('feat.1')
ax.set_ylabel('feat.2')
ax.set_zlabel('target')
plt.show()

运行后会得到包含截距的系数(例如[0.05343511 0.31007752 0.08830601]),拟合平面会贴合数据点,解决失真问题。


关于正则化与共线性

  • 当前问题无需正则化,修正截距后即可得到合理的拟合结果。
  • 若后续因共线性导致系数波动过大(比如新增数据后系数变化剧烈),可考虑使用**岭回归(Ridge Regression)**等正则化方法,通过添加L2惩罚项降低系数方差。

LU分解代码翻译

p, l, u = la.lu(A)
对矩阵A进行LU分解,返回三个矩阵:置换矩阵p、下三角矩阵l、上三角矩阵u,满足数学关系:p @ A = l @ u。


内容的提问来源于stack exchange,提问作者JeeyCi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 06:32:37