最优化方法 Python 3.12 实战:5行代码实现梯度下降求解线性回归
最优化方法 Python 3.12 实战:5行代码实现梯度下降求解线性回归
在数据科学和机器学习领域,线性回归是最基础也最常用的算法之一。传统的最小二乘法虽然能直接求出解析解,但当数据量庞大或特征维度高时,梯度下降这类迭代优化方法往往更具优势。本文将用Python 3.12演示如何用5行核心代码实现梯度下降,并深入分析学习率对收敛速度的影响。
1. 问题定义与数学原理
线性回归的目标是找到一组参数w,使得预测值$\hat{y}=w^Tx$与实际值y的均方误差最小:
$$ J(w) = \frac{1}{2m}\sum_{i=1}^m (\hat{y}^{(i)} - y^{(i)})^2 $$
梯度下降的更新公式为:
$$ w := w - \alpha \nabla J(w) $$
其中$\alpha$为学习率,$\nabla J(w)$是损失函数对w的梯度。对于线性回归,梯度可表示为:
$$ \nabla J(w) = \frac{1}{m}X^T(Xw - y) $$
关键点:梯度下降的核心是沿着负梯度方向迭代更新参数,学习率决定了每次更新的步长大小。
2. Python实现详解
2.1 数据准备与初始化
首先我们生成一组模拟数据:
import numpy as np np.random.seed(42) X = 2 * np.random.rand(100, 1) # 特征矩阵 y = 4 + 3 * X + np.random.randn(100, 1) # 添加噪声的目标值初始化参数和学习率:
w = np.random.randn(2, 1) # 随机初始化参数 X_b = np.c_[np.ones((100, 1)), X] # 添加偏置项 learning_rates = [0.01, 0.1, 0.5] # 对比不同学习率2.2 核心梯度下降实现
以下是5行核心代码的梯度下降实现:
def gradient_descent(X, y, w, alpha, n_iters): m = len(y) for _ in range(n_iters): gradient = X.T.dot(X.dot(w) - y) / m w -= alpha * gradient return w参数说明:
X: 特征矩阵(已添加偏置项)y: 目标值向量w: 初始参数向量alpha: 学习率n_iters: 迭代次数
2.3 完整训练流程
n_iters = 1000 for alpha in learning_rates: w = np.random.randn(2, 1) # 重新初始化 w = gradient_descent(X_b, y, w, alpha, n_iters) print(f"学习率 {alpha:.2f} 的参数: {w.ravel()}")3. 学习率对比实验
我们通过可视化观察不同学习率下的收敛情况:
| 学习率 | 收敛速度 | 最终参数 | 是否震荡 |
|---|---|---|---|
| 0.01 | 慢 | [4.12, 2.97] | 否 |
| 0.1 | 适中 | [4.02, 3.01] | 否 |
| 0.5 | 快 | [4.03, 3.00] | 轻微震荡 |
实现收敛曲线绘制:
import matplotlib.pyplot as plt def plot_convergence(X, y, alphas, n_iters=100): plt.figure(figsize=(12, 8)) for alpha in alphas: w = np.random.randn(2, 1) losses = [] for _ in range(n_iters): gradient = X.T.dot(X.dot(w) - y) / len(y) w -= alpha * gradient loss = np.mean((X.dot(w) - y)**2) losses.append(loss) plt.plot(losses, label=f"α={alpha}") plt.xlabel("迭代次数") plt.ylabel("损失值") plt.legend() plt.show() plot_convergence(X_b, y, learning_rates)4. 工程实践建议
在实际项目中应用梯度下降时,需要注意以下关键点:
特征缩放:
- 标准化:$(x - \mu)/\sigma$
- 归一化:$(x - x_{min})/(x_{max} - x_{min})$
停止条件:
- 设置损失变化阈值
- 限制最大迭代次数
- 早停策略
高级优化技巧:
- 动量法:$v = \beta v + (1-\beta)\nabla J(w)$
- 自适应学习率(Adam、RMSprop)
# 特征标准化实现示例 X_std = (X - X.mean()) / X.std()5. 扩展与变体
5.1 随机梯度下降(SGD)
def stochastic_gd(X, y, w, alpha, n_epochs): m = len(y) for epoch in range(n_epochs): for i in range(m): random_index = np.random.randint(m) xi = X[random_index:random_index+1] yi = y[random_index:random_index+1] gradient = xi.T.dot(xi.dot(w) - yi) w -= alpha * gradient return w5.2 小批量梯度下降
def mini_batch_gd(X, y, w, alpha, n_epochs, batch_size=32): m = len(y) for epoch in range(n_epochs): indices = np.random.permutation(m) X_shuffled = X[indices] y_shuffled = y[indices] for i in range(0, m, batch_size): xi = X_shuffled[i:i+batch_size] yi = y_shuffled[i:i+batch_size] gradient = xi.T.dot(xi.dot(w) - yi) / batch_size w -= alpha * gradient return w在实际项目中,我发现当特征维度超过1000时,适当减小批量大小(如从256降到64)能显著提升训练速度,同时保持较好的收敛性。对于稀疏特征,学习率可以适当增大10-20%。