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

Python实现线性回归梯度下降拟合出水平线,问题出在哪里?

问题原因分析
  • 你怀疑的误差正负抵消问题不成立:MSE损失的梯度推导本身就使用train_y - pred_y参与计算,每个误差项会和对应特征值相乘后求和,不会出现正负误差直接抵消的问题,你的梯度计算逻辑本身是正确的。
  • 第一个错误是MSE计算错误:当前代码中mse = errors.mean()计算的是平均偏差,不是均方误差,正确的MSE应为mse = (errors ** 2).mean(),该错误不影响梯度更新,但会导致打印的收敛指标完全失效。
  • 第二个也是导致你看到水平直线的核心错误是generateLine函数逻辑错误:
    1. 你构造x轴取值时混入了train_y的数值范围,还强制转成了整数,而make_regression生成的train_X是浮点型小范围值,生成的直线大部分x值不在散点的展示区间内,视觉上看起来像水平直线
    2. 正确做法是x轴起止范围直接取train_X的最小、最大值,生成连续的浮点型x点即可。
  • 可选优化:可以将学习率调整为0.1,收敛速度会更快。
修复后的完整代码
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from sklearn import datasets

def gradientDescent(train_X,train_y,lr,epochs,init_slope=1,init_intercept=0.1):
    if len(train_X) != len(train_y):
        raise Exception("train_X and train_Y must be the same length.")
    # 转为一维数组避免维度问题
    train_X = np.array(train_X).flatten()
    train_y = np.array(train_y)
    n = len(train_X)

    slope = init_slope
    intercept = init_intercept
    for e in range(epochs):
        pred_y = slope * train_X + intercept 
        errors = (train_y - pred_y)
        # 修复MSE计算
        mse = (errors ** 2).mean()

        slope -= lr * (-2/n) * np.sum(train_X * errors)
        intercept -= lr * (-2/n) * np.sum(errors)

    return mse, slope, intercept

# 修复直线生成逻辑
def generateLine(slope,intercept,x_min,x_max,point_cnt=100):
    x = np.linspace(x_min, x_max, point_cnt)
    y = slope * x + intercept
    return x, y


n_samples = 10
n_outliers = 2

train_X, train_y, coef = datasets.make_regression(n_samples=n_samples, n_features=1,
                                      n_informative=1, noise=20,
                                      coef=True, random_state=0)

# 调大学习率加快收敛
lr = 0.1
epochs = 1000

fig, ax = plt.subplots()
line, = ax.plot([0], [0])
plt.plot(train_X,train_y,'o')
# 固定坐标轴范围避免显示异常
plt.xlim(np.min(train_X)-0.2, np.max(train_X)+0.2)
plt.ylim(np.min(train_y)-5, np.max(train_y)+5)

slope=0
intercept = 0
def animate(i):
    global slope, intercept
    if i == 1:
        mse, slope, intercept = gradientDescent(train_X,train_y,lr=lr, epochs = 1,init_slope= np.random.random(), init_intercept=np.random.random())

    mse, slope, intercept = gradientDescent(train_X,train_y,lr=lr,epochs=1,init_slope = slope, init_intercept = intercept)
    # 仅使用train_X的范围生成直线
    line_x, line_y = generateLine(slope, intercept, np.min(train_X), np.max(train_X))

    line.set_xdata(line_x)
    line.set_ydata(line_y) 
    if i % 10 == 0:
        print(f'Epoch: {i}, MSE = {mse:.6f}, 拟合斜率: {slope:.2f}, 真实斜率: {coef:.2f}')

    return line,

def init():
    line.set_ydata([0])
    return line,

ani = animation.FuncAnimation(fig, animate, frames=range(1, epochs), init_func=init, interval=100, blit=True)
plt.show()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 15:24:01