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

梯度下降代码遇数值溢出警告与NaN预测结果,请求代码排查

问题根源与解决方案

核心问题:归一化后未使用归一化特征训练

你已经对X做了归一化,但梯度下降函数传入的是原始X(年份数值如1998、1999等,数值过大),导致梯度计算时出现数值溢出,最终参数b和m变成无穷大,后续预测必然出现NaN。

其他次要问题

  • 重复导入库(多次导入pandas、numpy、matplotlib),冗余且无意义
  • 填充缺失值时机错误:应该在分组后立即处理缺失值,再提取特征X和标签y
  • 逆变换时混用了标签的归一化器:X和y的归一化范围不同,需分别保存对应scaler

修改后的完整代码

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.preprocessing import MinMaxScaler

# 读取数据并预处理
df = pd.read_csv("D:/Code/Vscode/test1/honeyproduction (3).csv")
prod_per_year = df.groupby('year').totalprod.mean().reset_index()
# 先填充缺失值再提取特征
prod_per_year.fillna(method='ffill', inplace=True)

X = prod_per_year["year"].values.reshape(-1, 1)
y = prod_per_year["totalprod"].values.reshape(-1, 1)

# 分别初始化X和y的归一化器,避免混淆
scaler_X = MinMaxScaler()
scaler_y = MinMaxScaler()
X_scaled = scaler_X.fit_transform(X)
y_scaled = scaler_y.fit_transform(y)

# 梯度下降函数(适配归一化后的二维数组)
def get_gradient_at_b(X, y, b, m):
    N = len(X)
    diff = 0
    for i in range(N):
        X_val = X[i][0]
        y_val = y[i][0]
        diff += y_val - ((X_val * m) + b)
    return -(2/N) * diff    

def get_gradient_at_m(X, y, b, m):
    N = len(X)
    diff = 0
    for i in range(N):
        X_val = X[i][0]
        y_val = y[i][0]
        diff += X_val * (y_val - ((X_val * m) + b))
    return -(2/N) * diff

def step_gradient(X, y, lr, b_current, m_current):
    b_grad = get_gradient_at_b(X, y, b_current, m_current)
    m_grad = get_gradient_at_m(X, y, b_current, m_current)
    return [b_current - lr * b_grad, m_current - lr * m_grad]

def gradient_descent(X, y, lr, iterations):
    b, m = 0, 0
    for _ in range(iterations):
        b, m = step_gradient(X, y, lr, b, m)
    return b, m

# 使用归一化后的特征训练模型
b, m = gradient_descent(X_scaled, y_scaled, 0.004, 1000)

# 预测并逆变换回原始尺度
y_pred_scaled = np.array([x[0] * m + b for x in X_scaled]).reshape(-1,1)
y_pred = scaler_y.inverse_transform(y_pred_scaled)

# 可视化结果
X_original = prod_per_year["year"].values
y_original = prod_per_year["totalprod"].values

plt.scatter(X_original, y_original)
plt.plot(X_original, y_pred, color='red')
plt.show()

# 打印结果
print("原始年份:", X_original.tolist())
print("真实产量:", y_original.tolist())
print("预测产量:", y_pred.flatten().tolist())

关键修改点说明

  1. 用归一化特征训练:梯度下降传入X_scaled和y_scaled,避免原始大数值引发的梯度爆炸
  2. 分离归一化器:scaler_X处理年份,scaler_y处理产量,逆变换时用对应scaler保证数据正确
  3. 调整缺失值处理时机:分组后立即填充,确保提取的X/y无缺失
  4. 适配二维数组:归一化后的数据是二维数组,循环时取X[i][0]获取单个数值
  5. 清理冗余代码:删除重复的库导入语句

额外优化建议

可以将梯度计算改为向量化操作,替代循环提升效率:

# 向量化版本的梯度计算(速度更快)
def get_gradient_at_b(X, y, b, m):
    N = len(X)
    diff = y.flatten() - (X.flatten() * m + b)
    return -(2/N) * diff.sum()

def get_gradient_at_m(X, y, b, m):
    N = len(X)
    diff = X.flatten() * (y.flatten() - (X.flatten() * m + b))
    return -(2/N) * diff.sum()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 12:47:51