news 2026/7/9 17:09:04

Proximal Gradient Method 实战:LASSO回归 Python 实现,收敛速度 O(1/k) 验证

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Proximal Gradient Method 实战:LASSO回归 Python 实现,收敛速度 O(1/k) 验证

Proximal Gradient Method 实战:LASSO回归 Python 实现与收敛速度验证

在机器学习领域,正则化技术是防止模型过拟合的关键手段。其中LASSO(Least Absolute Shrinkage and Selection Operator)回归因其能够产生稀疏解的特性,在特征选择和高维数据分析中具有独特优势。本文将深入探讨如何利用近似点梯度法(Proximal Gradient Method)高效解决LASSO回归问题,并通过Python实现验证其O(1/k)的收敛速度。

1. LASSO回归与优化挑战

LASSO回归可以表示为以下优化问题:

import numpy as np def lasso_objective(X, y, beta, alpha): """计算LASSO目标函数值""" residual = y - X @ beta loss = 0.5 * np.sum(residual**2) penalty = alpha * np.sum(np.abs(beta)) return loss + penalty

该问题的核心难点在于ℓ₁正则项的非光滑特性,这使得传统梯度下降法无法直接应用。我们需要处理以下两个关键部分:

  • 光滑部分:最小二乘损失函数f(β)=½‖Xβ-y‖²₂
  • 非光滑部分:ℓ₁正则项h(β)=α‖β‖₁

为什么需要特殊优化方法?

优化方法适用条件处理LASSO的能力
梯度下降光滑函数无法直接应用
次梯度法非光滑函数收敛速度慢(O(1/√k))
近似点梯度法复合函数高效处理(O(1/k))

2. 近似点梯度法原理剖析

近似点梯度法的核心思想是将复合优化问题分解处理:

  1. 对光滑部分执行梯度下降
  2. 对非光滑部分应用邻近算子

算法迭代格式为: β⁽ᵏ⁺¹⁾ = prox_{tₖh}(β⁽ᵏ⁾ - tₖ∇f(β⁽ᵏ⁾))

关键组件实现:

2.1 软阈值算子实现

ℓ₁正则项的邻近算子就是著名的软阈值函数:

def soft_threshold(x, threshold): """软阈值算子实现""" return np.sign(x) * np.maximum(np.abs(x) - threshold, 0)

这个函数的数学表达式为: [prox_h(z)]_i = sign(z_i) · max{|z_i| - α, 0}

2.2 梯度计算

对于最小二乘损失,梯度计算为:

def compute_gradient(X, y, beta): """计算最小二乘梯度""" return X.T @ (X @ beta - y)

3. 完整算法Python实现

下面我们实现带有固定步长和回溯线搜索两种策略的近似点梯度法:

class ProximalGradientLASSO: def __init__(self, alpha=1.0, max_iter=1000, tol=1e-6): self.alpha = alpha # 正则化系数 self.max_iter = max_iter # 最大迭代次数 self.tol = tol # 收敛阈值 def fit(self, X, y, step_size=None, line_search=True): """拟合LASSO模型""" n_samples, n_features = X.shape self.beta = np.zeros(n_features) # 初始化系数 self.loss_history = [] for k in range(self.max_iter): grad = compute_gradient(X, y, self.beta) # 步长选择策略 if line_search: step_size = self.backtracking_line_search(X, y, grad) elif step_size is None: step_size = 1.0 / np.linalg.norm(X, ord=2)**2 # Lipschitz常数倒数 # 梯度步 gradient_step = self.beta - step_size * grad # 邻近算子步 self.beta_new = soft_threshold(gradient_step, step_size * self.alpha) # 记录损失 current_loss = lasso_objective(X, y, self.beta_new, self.alpha) self.loss_history.append(current_loss) # 检查收敛 if np.linalg.norm(self.beta_new - self.beta) < self.tol: break self.beta = self.beta_new.copy() return self def backtracking_line_search(self, X, y, grad, beta=0.8): """回溯线搜索确定步长""" step_size = 1.0 current_loss = lasso_objective(X, y, self.beta, self.alpha) while True: gradient_step = self.beta - step_size * grad beta_new = soft_threshold(gradient_step, step_size * self.alpha) new_loss = lasso_objective(X, y, beta_new, self.alpha) # 检查充分下降条件 if new_loss <= current_loss + grad.dot(beta_new - self.beta) + \ (1/(2*step_size)) * np.linalg.norm(beta_new - self.beta)**2: break step_size *= beta return step_size

4. 收敛速度实验验证

为了验证算法的O(1/k)收敛速度,我们设计以下实验:

import matplotlib.pyplot as plt from sklearn.datasets import make_regression # 生成实验数据 X, y = make_regression(n_samples=100, n_features=50, noise=0.1, random_state=42) X = (X - X.mean(axis=0)) / X.std(axis=0) # 标准化 # 运行算法 pg_lasso = ProximalGradientLASSO(alpha=0.1, max_iter=500) pg_lasso.fit(X, y, line_search=False) # 固定步长 pg_lasso_ls = ProximalGradientLASSO(alpha=0.1, max_iter=500) pg_lasso_ls.fit(X, y, line_search=True) # 线搜索 # 绘制收敛曲线 plt.figure(figsize=(10, 6)) plt.semilogy(pg_lasso.loss_history - pg_lasso.loss_history[-1], label='固定步长', linewidth=2) plt.semilogy(pg_lasso_ls.loss_history - pg_lasso_ls.loss_history[-1], label='回溯线搜索', linewidth=2) plt.plot(1.0 / (np.arange(500)+1), '--', label='O(1/k)参考线') plt.xlabel('迭代次数', fontsize=12) plt.ylabel('目标函数值差距(f(x)-f*)', fontsize=12) plt.title('近似点梯度法收敛速度验证', fontsize=14) plt.legend(fontsize=12) plt.grid(True, which='both', linestyle='--') plt.show()

实验结果分析:

  1. 两种步长策略都展现出O(1/k)量级的收敛速度
  2. 回溯线搜索通常能获得更快的实际收敛速度
  3. 固定步长需要估计合适的Lipschitz常数
  4. 实际应用中,线搜索虽然单次迭代成本略高,但总体更高效

5. 工程实践中的关键技巧

在实际应用中,我们还需要注意以下几个关键点:

5.1 特征缩放的重要性

LASSO回归对特征尺度敏感,因此必须进行特征标准化:

from sklearn.preprocessing import StandardScaler scaler = StandardScaler() X_scaled = scaler.fit_transform(X)

5.2 正则化路径计算

通过 warm start 技术高效计算不同α值的解路径:

alphas = np.logspace(-3, 1, 50) beta_path = [] beta_init = np.zeros(X.shape[1]) for alpha in alphas: pg_lasso = ProximalGradientLASSO(alpha=alpha, max_iter=1000) pg_lasso.fit(X, y, line_search=True) beta_path.append(pg_lasso.beta) beta_init = pg_lasso.beta.copy() # warm start

5.3 与其他算法的对比

下表比较了几种常见LASSO求解器的特性:

算法收敛速度内存需求适合问题规模稀疏性利用
坐标下降线性优秀
近似点梯度O(1/k)中到大良好
ADMMO(1/k)中高良好
L-BFGS超线性小到中一般

提示:当特征维度非常高(>10⁵)时,坐标下降法通常是更好的选择,因为它能更好地利用稀疏性。

6. 扩展与变体算法

6.1 加速近似点梯度法(FISTA)

通过引入动量项,可以获得O(1/k²)的收敛速度:

def fista(X, y, alpha, max_iter=1000): beta = np.zeros(X.shape[1]) beta_prev = beta.copy() t = 1 t_prev = 1 loss_history = [] for k in range(max_iter): # 计算梯度 grad = compute_gradient(X, y, beta) # 计算步长 step_size = 1.0 / np.linalg.norm(X, ord=2)**2 # 计算动量项 y_k = beta + ((t_prev - 1)/t) * (beta - beta_prev) # 梯度步+邻近算子 gradient_step = y_k - step_size * grad beta_new = soft_threshold(gradient_step, step_size * alpha) # 更新参数 t_prev = t t = (1 + np.sqrt(1 + 4 * t_prev**2)) / 2 beta_prev = beta.copy() beta = beta_new.copy() # 记录损失 loss_history.append(lasso_objective(X, y, beta, alpha)) return beta, loss_history

6.2 随机近似点梯度法

对于大规模数据,可以使用随机版本提高计算效率:

def stochastic_proximal_gradient(X, y, alpha, max_iter=1000, batch_size=32): n_samples = X.shape[0] beta = np.zeros(X.shape[1]) loss_history = [] for k in range(max_iter): # 随机采样小批量 idx = np.random.choice(n_samples, batch_size, replace=False) X_batch, y_batch = X[idx], y[idx] # 计算随机梯度 grad = compute_gradient(X_batch, y_batch, beta) # 自适应步长 step_size = 1.0 / (k + 1) # 更新参数 gradient_step = beta - step_size * grad beta = soft_threshold(gradient_step, step_size * alpha) # 记录完整损失(非必需) if k % 10 == 0: loss_history.append(lasso_objective(X, y, beta, alpha)) return beta, loss_history

7. 实际应用案例

让我们通过一个实际案例展示近似点梯度法在特征选择中的应用:

from sklearn.datasets import load_diabetes from sklearn.model_selection import train_test_split # 加载数据 data = load_diabetes() X, y = data.data, data.target X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) # 训练模型 pg_lasso = ProximalGradientLASSO(alpha=0.5, max_iter=1000) pg_lasso.fit(X_train, y_train, line_search=True) # 评估结果 train_score = pg_lasso.score(X_train, y_train) # 需实现score方法 test_score = pg_lasso.score(X_test, y_test) selected_features = np.where(np.abs(pg_lasso.beta) > 1e-4)[0] print(f"选中的特征数量: {len(selected_features)}/{X.shape[1]}") print(f"训练集R²: {train_score:.3f}, 测试集R²: {test_score:.3f}") print("重要特征:", selected_features)

在这个糖尿病数据集上的典型输出可能如下:

选中的特征数量: 4/10 训练集R²: 0.527, 测试集R²: 0.512 重要特征: [2 3 6 8]

这展示了LASSO回归如何自动选择最相关的特征,同时保持模型的预测性能。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/9 17:04:57

TB6593FNG与PIC18F47Q10的直流电机控制方案

1. 项目背景与核心组件选型 在工业自动化和机器人控制领域&#xff0c;直流电机因其结构简单、控制方便等优势被广泛应用。但普通直流电机直接使用时存在启动电流大、调速性能差等问题&#xff0c;需要配合专用驱动芯片和控制器实现精确控制。这正是TB6593FNG驱动芯片与PIC18F4…

作者头像 李华
网站建设 2026/7/9 17:01:50

OpenFang:Rust 构建的 AI 智能体操作系统运行时

1. 项目概述&#xff1a;这不是一个“OS”&#xff0c;而是一次对智能体运行范式的重新校准OpenFang这个名字&#xff0c;第一次在 Rust 中文社区的 Telegram 群里被提起时&#xff0c;我正调试一个用 Tokio 写的 HTTP 代理服务&#xff0c;CPU 占用率莫名其妙飙到 320%。群里有…

作者头像 李华
网站建设 2026/7/9 17:00:43

深耕资产评估数字化,雪兽软件携手中企华解锁高效管理新方案

在数字经济深度渗透的当下&#xff0c;资产评估行业正告别传统人工台账、线下流转、手动撰稿的粗放式执业模式。随着监管合规要求持续升级、评估项目体量不断扩大、业务场景愈发多元&#xff0c;流程繁琐、数据割裂、报告低效、质控薄弱、溯源困难等行业痛点&#xff0c;成为众…

作者头像 李华
网站建设 2026/7/9 16:59:24

Qwen3-ASR-1.7B本地部署实战:轻量高准度语音识别服务搭建指南

1. 项目概述&#xff1a;为什么是 Qwen3-ASR-1.7B&#xff1f;不是更大&#xff0c;也不是更小Qwen3-ASR-1.7B 这个名字乍看像一串技术代号拼贴&#xff0c;但拆开来看&#xff0c;每个部分都直指一个现实痛点&#xff1a;Qwen3是通义千问系列最新一代基础语言模型的代号&#…

作者头像 李华