梯度下降代码遇数值溢出警告与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())
关键修改点说明
- 用归一化特征训练:梯度下降传入
X_scaled和y_scaled,避免原始大数值引发的梯度爆炸 - 分离归一化器:
scaler_X处理年份,scaler_y处理产量,逆变换时用对应scaler保证数据正确 - 调整缺失值处理时机:分组后立即填充,确保提取的X/y无缺失
- 适配二维数组:归一化后的数据是二维数组,循环时取
X[i][0]获取单个数值 - 清理冗余代码:删除重复的库导入语句
额外优化建议
可以将梯度计算改为向量化操作,替代循环提升效率:
# 向量化版本的梯度计算(速度更快) 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
相关产品推荐
相关产品推荐

