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

实现带Lasso修正的LARS算法遇阻:步骤3理解与编程求助

我太懂卡在LARS-Lasso步骤3的滋味了——这部分是算法里最绕的核心,既要处理新变量的加入,还要兼顾Lasso的系数压缩(也就是剔除活跃集变量),很容易搞混。先帮你拆解清楚步骤3的逻辑,再结合你已经写好的标准化代码补全实现。


先回顾你已完成的基础代码(补全了y的初始化方便后续演示)

set.seed(19875) 
n <- 10 
p <- 5 
real_p <- 5 
x <- matrix(rnorm(n*p), nrow=n, ncol=p) 
# 步骤1:标准化预测变量为均值0、单位范数
x <- x - matrix(apply(x,2,mean), ncol=ncol(x), nrow=nrow(x), byrow=T) 
x <- x / matrix(apply(x,2,sd), ncol=ncol(x), nrow=nrow(x), byrow=T) 
# 补全y的生成(模拟真实数据)
beta_true <- rnorm(real_p)
y <- x[,1:real_p] %*% beta_true + rnorm(n, sd=0.1)

拆解LARS-Lasso步骤3的核心逻辑

LARS-Lasso的步骤3本质是每一步迭代要做两件事:找下一个要加入的变量,同时检查当前活跃集里有没有变量的系数会被压缩到0(这就是Lasso的修正,区别于普通LARS只加不减)。具体分4个子步骤:

  1. 计算当前残差与所有变量的相关性(因为x已标准化,相关性=协方差)
  2. 找到当前最大的绝对相关性,确定候选加入的变量
  3. 计算系数更新的方向向量
  4. 计算两个关键步长:
    • gamma1:把新变量加入活跃集的步长
    • gamma2:把活跃集中某个变量系数压到0的步长
    • 取两者的最小值作为最终步长,若gamma2更小,就先剔除变量,否则加入新变量

步骤3的完整代码实现

# 初始化算法所需变量
beta <- rep(0, p)          # 系数向量,初始全为0
r <- y                     # 初始残差=真实y(因为beta初始为0)
active_set <- c()          # 活跃集,初始为空
corr <- t(x) %*% r         # 初始相关性:残差与每个变量的内积

# 迭代终止条件:活跃集包含所有变量,或相关性小到可忽略
while(length(active_set) < p && max(abs(corr)) > 1e-6) {
  # 1. 找到当前最大的绝对相关性,确定候选变量
  max_corr <- max(abs(corr))
  candidate_vars <- which(abs(corr) == max_corr)
  
  if(length(active_set) == 0) {
    # 第一次迭代:直接加入第一个候选变量
    active_set <- candidate_vars[1]
  } else {
    # 2. 计算活跃集的方向向量u_A
    x_A <- x[, active_set]
    inv_xtx_A <- solve(t(x_A) %*% x_A)  # 活跃集变量的X'X逆矩阵
    sign_corr_A <- sign(corr[active_set])
    u_A <- inv_xtx_A %*% sign_corr_A    # 活跃集内的方向向量
    u <- rep(0, p)
    u[active_set] <- u_A                # 全局方向向量(非活跃集为0)
    
    # 3. 计算gamma1:加入新变量的步长
    non_active <- setdiff(1:p, active_set)
    if(length(non_active) > 0) {
      numerator_gamma1 <- max_corr - corr[non_active]
      denominator_gamma1 <- (t(x[, non_active]) %*% x_A %*% u_A) - sign(corr[non_active])
      gamma1 <- numerator_gamma1 / denominator_gamma1
      gamma1 <- gamma1[gamma1 > 1e-8]  # 只保留正步长(避免数值误差)
      gamma1 <- ifelse(length(gamma1) > 0, min(gamma1), Inf)
    } else {
      gamma1 <- Inf  # 无新变量可加
    }
    
    # 4. 计算gamma2:剔除活跃集变量的步长(Lasso修正核心)
    gamma2 <- -beta[active_set] / u_A
    gamma2 <- gamma2[gamma2 > 1e-8]
    gamma2 <- ifelse(length(gamma2) > 0, min(gamma2), Inf)
    
    # 5. 取最小步长更新系数和残差
    gamma <- min(gamma1, gamma2)
    beta <- beta + gamma * u
    r <- r - gamma * x %*% u
    
    # 6. 更新活跃集:优先处理剔除(如果gamma2更小)
    if(gamma == gamma2) {
      drop_idx <- which(-beta[active_set]/u_A == gamma2)[1]
      active_set <- active_set[-drop_idx]
    } else {
      # 加入新变量
      new_var <- non_active[which(numerator_gamma1/denominator_gamma1 == gamma1)[1]]
      active_set <- c(active_set, new_var)
    }
  }
  
  # 更新相关性,打印中间过程(可选)
  corr <- t(x) %*% r
  cat("当前活跃集:", active_set, "\n")
  cat("当前系数:", round(beta, 4), "\n\n")
}

关键细节说明

  • Lasso修正的核心:gamma2的计算是为了提前发现哪些活跃变量的系数会在更新后被压缩到0,这一步是LARS-Lasso区别于普通LARS的关键——普通LARS只会不断加入变量,不会剔除。
  • 数值阈值1e-8:用来避免浮点数误差导致的极小/负步长,保证算法稳定。
  • 活跃集的动态变化:每一步都可能加入新变量或剔除旧变量,直到所有变量都被处理或残差足够小。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 09:21:31