一、多变量线性回归梯度下降调参实验

这是一个房价预测的多变量线性回归任务:

  • 特征:房屋面积(平方英尺)、卧室数量、楼层数、房龄
  • 目标:预测房价(千美元)
  • 核心任务:调试梯度下降的学习率 α,观察不同 α 对收敛的影响。

1. 环境与数据加载

import numpy as np
import matplotlib.pyplot as plt
from lab_utils_multi import load_house_data, run_gradient_descent, plot_cost_i_w

# 加载数据集
X_train, y_train = load_house_data()
X_features = ['size(sqft)','bedrooms','floors','age']
  • X_train:形状为 (m, n),其中 m 是样本数,n=4 是特征数
  • y_train:形状为 (m,),是房价标签

2. 特征 - 价格关系可视化

从散点图可以看出:

  • 面积(size)与价格有明显的正相关趋势,是强特征
  • 卧室数、楼层数、房龄与价格的线性相关性较弱,是弱特征 / 噪声特征

3. 多变量梯度下降公式

重复迭代直到收敛:

其中偏导数为:


4. 不同学习率的效果对比

(1)学习率过大:α=9.9e−7

  • 现象:成本函数(Cost)随迭代次数上升,模型不收敛
  • 原因:学习率过高,参数更新步长过大,导致在损失函数曲面上来回震荡,甚至越过最小值点,成本不降反升
  • 可视化验证:Cost vs Iteration 曲线持续上升,Cost vs w [0] 曲线显示参数在最小值两侧大幅来回跳动

(2)学习率适中:α=9e−7

  • 现象:成本函数随迭代次数稳定下降,模型收敛
  • 特点:参数在最小值附近小幅波动,每次迭代都向最优解靠近,收敛速度较快
  • 可视化验证:Cost vs Iteration 曲线单调下降,Cost vs w [0] 曲线显示参数在最小值附近小幅震荡

(3)学习率过小:α=1e−7

  • 现象:成本函数缓慢下降,模型收敛,但速度远慢于适中的 α
  • 特点:参数更新步长太小,每次迭代只向最优解移动很小的距离,需要更多迭代次数才能收敛
  • 可视化验证:Cost vs Iteration 曲线下降平缓,Cost vs w [0] 曲线显示参数一直向最小值靠近,没有越过最小值

5.关键结论与调参技巧

(1)学习率 α 的影响规律

学习率大小 成本函数变化 收敛性 特点
过大 上升 / 震荡 不收敛 参数更新步长过大,越过最小值点
适中 稳定下降 收敛 收敛速度快,效果好
过小 缓慢下降 收敛 收敛速度慢,需要更多迭代

(2)如何选择合适的 α

  • 调试方法:从较大的 α 开始尝试,观察成本函数曲线:
    • 若成本上升 / 震荡,说明 α 过大,除以 10 或 2,重新尝试
    • 若成本缓慢下降,可适当增大 α,提高收敛速度
    • 找到成本稳定下降的最大 α,即为合适的学习率
  • 收敛判断:当成本函数的下降幅度小于某个阈值(如10−3)时,可认为模型收敛

(3)优化建议:特征缩放

本实验中,不同特征的数值范围差异很大(如面积在 1000-3000,房龄在 0-100),会导致梯度下降收敛缓慢。可以通过特征缩放(如标准化 / 归一化)解决:

# 标准化示例
X_mean = X_train.mean(axis=0)
X_std = X_train.std(axis=0)
X_norm = (X_train - X_mean) / X_std

缩放后,不同特征的数值范围相近,梯度下降的收敛速度会显著提升,对学习率的选择也更友好。

import numpy as np
import matplotlib.pyplot as plt
from lab_utils_multi import load_house_data, run_gradient_descent, plot_cost_i_w

# 1. 加载数据
X_train, y_train = load_house_data()
X_features = ['size(sqft)','bedrooms','floors','age']

# 2. 可视化特征与价格的关系
fig,ax=plt.subplots(1, 4, figsize=(12, 3), sharey=True)
for i in range(len(ax)):
    ax[i].scatter(X_train[:,i],y_train)
    ax[i].set_xlabel(X_features[i])
ax[0].set_ylabel("Price (1000's)")
plt.show()

# 3. 调试不同学习率
# α=9.9e-7(过大)
_,_,hist = run_gradient_descent(X_train, y_train, 10, alpha = 9.9e-7)
plot_cost_i_w(X_train, y_train, hist)

# α=9e-7(适中)
_,_,hist = run_gradient_descent(X_train, y_train, 10, alpha = 9e-7)
plot_cost_i_w(X_train, y_train, hist)

# α=1e-7(过小)
_,_,hist = run_gradient_descent(X_train, y_train, 10, alpha = 1e-7)
plot_cost_i_w(X_train, y_train, hist)

二.分数归一化

1.为什么要做特征缩放?

在房价预测任务中,不同特征的数值范围差异极大:

  • 房屋面积:约 1000-3000 平方英尺
  • 卧室数 / 楼层数:约 0-4
  • 房龄:约 0-100

这种尺度差异会带来两个严重问题:

  1. 参数更新失衡:梯度下降时,数值大的特征会主导成本函数,导致权重更新步长差异巨大,模型收敛缓慢甚至震荡。
  2. 成本曲面扭曲:成本等高线会变成 “狭长椭圆”,梯度下降需要大量迭代才能找到最小值;缩放后等高线近似圆形,收敛速度大幅提升。

2.三种常见特征缩放方法

方法 公式 特点
最大缩放 xi​=xi​​/max(x) 仅适用于非负特征,简单易用
均值归一化 xi​=xi​−μ​/max(x)−min(x) 将特征缩放到[-1,1]区间
Z 分数归一化 xi​=xi​−μ/​σ 均值为 0、标准差为 1,对异常值更鲁棒,工业界最常用

其中,μj​ 是特征j的均值,σj​ 是特征j的标准差:


3.Z 分数归一化实现与验证

import numpy as np

def zscore_normalize_features(X):
    """
    对特征矩阵X按列进行Z分数归一化
    Args:
        X (ndarray (m,n)): 输入数据,m个样本,n个特征
    Returns:
        X_norm (ndarray (m,n)): 归一化后的数据
        mu (ndarray (n,)): 每个特征的均值
        sigma (ndarray (n,)): 每个特征的标准差
    """
    # 计算每列(特征)的均值
    mu = np.mean(X, axis=0)
    # 计算每列(特征)的标准差
    sigma = np.std(X, axis=0)
    # 归一化:(X - 均值) / 标准差
    X_norm = (X - mu) / sigma
    
    return X_norm, mu, sigma

归一化效果验证

# 加载数据
X_train, y_train = load_house_data()
X_features = ['size(sqft)','bedrooms','floors','age']

# 归一化处理
X_norm, X_mu, X_sigma = zscore_normalize_features(X_train)

# 查看归一化前后的特征范围
print(f"原始数据峰峰值(每列): {np.ptp(X_train, axis=0)}")
print(f"归一化后峰峰值(每列): {np.ptp(X_norm, axis=0)}")
  • 原始数据:峰峰值跨度从几千(面积)到个位数(卧室数)
  • 归一化后:所有特征的峰峰值都缩小到 2-6 之间,数值范围趋于一致

4.归一化前后的梯度下降对比

(1)关键差异

对比项 未归一化 归一化后
学习率 只能取极小值(如10−7级别),否则震荡 可以取较大值(如 0.1),收敛速度快
迭代次数 需要上千次迭代才能收敛 几百次迭代即可收敛
成本曲线 下降缓慢,易震荡 快速平滑下降,稳定收敛
成本等高线 狭长椭圆,梯度下降路径曲折 近似圆形,梯度下降路径直接

(2) 归一化后梯度下降代码

# 归一化后的数据运行梯度下降,学习率设为0.1(远大于之前的1e-7)
w_norm, b_norm, hist = run_gradient_descent(X_norm, y_train, 1000, alpha=1.0e-1)
  • 结果:迭代 1000 次后成本就稳定收敛,参数梯度趋近于 0,收敛速度大幅提升。

5.归一化后预测新数据

⚠️ 重要提醒:对新数据进行预测时,必须使用训练集的均值和标准差进行归一化,不能用测试数据的统计量!

# 预测一套1200平方英尺、3间卧室、1层、房龄40年的房屋价格
x_house = np.array([1200, 3, 1, 40])
# 使用训练集的均值和标准差归一化
x_house_norm = (x_house - X_mu) / X_sigma
print(x_house_norm)  # [-0.53  0.43 -0.79  0.06]

# 预测价格
x_house_predict = np.dot(x_house_norm, w_norm) + b_norm
print(f"预测价格: ${x_house_predict*1000:0.0f}")  # $318709

6.关键结论

  1. 特征缩放是多变量线性回归的必备步骤,尤其是在特征尺度差异大的场景中。
  2. Z 分数归一化是最通用的缩放方法,它能让所有特征的分布标准化,大幅提升梯度下降的效率和稳定性。
  3. 缩放必须基于训练集统计量,测试 / 预测数据必须使用训练集的均值和标准差,避免数据泄露。
  4. 归一化后可以使用更大的学习率,显著减少迭代次数,同时避免成本震荡问题。
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐