实现逻辑回归随机梯度下降时theta值异常问题排查
你的逻辑回归SGD为啥theta没更新?
看起来你遇到的问题是theta完全没变化,和初始值一致——这说明你的梯度更新步骤根本没生效,大概率是实现细节出了问题,我帮你梳理几个最常见的坑:
1. 梯度计算逻辑错了
逻辑回归的SGD,单个样本的梯度公式是:gradient = (h(x_i) - y_i) * x_i,其中h(x_i)是sigmoid函数的输出(1/(1+exp(-theta%*%x_i)))。如果这里漏乘了x_i,或者sigmoid实现错误(比如符号写错、函数表达式出错),会导致梯度为0或者无效,theta自然不动。
2. 特征没做归一化,学习率又太小
SGD对特征尺度特别敏感,如果你的特征数值范围差异很大(比如一个特征是0-1,另一个是1000-2000),再加上你用的alpha=0.0009这么小的学习率,梯度更新的幅度会小到可以忽略,看起来theta就没变化。先试试把所有特征做标准化(比如(x - mean(x))/sd(x)),再调大学习率(比如0.01、0.1)试试。
3. 迭代循环的逻辑有问题
你贴的代码没写完(theta <- seq(from = 0, to = 1, len...),但很可能是循环里的坑:
- 是不是每次循环都重新初始化了theta?比如把
theta <- seq(...)放在循环里面,那每次迭代都会重置回初始值,等于白算 - 有没有真正遍历每个样本,并且在每个样本后执行
theta = theta - alpha * gradient的更新? - 有没有给数据加截距项?逻辑回归需要截距项(X的第一列全1),不然拟合会有偏差
给你一个可参考的正确实现
# 先实现sigmoid函数 sigmoid <- function(z) { 1 / (1 + exp(-z)) } train <- function(data, labels, alpha = 0.01, num_epochs = 100) { # 给数据添加截距项(必须!) X <- cbind(rep(1, nrow(data)), data) m <- nrow(X) # 样本数 n <- ncol(X) # 特征数(含截距) # 初始化theta,用全0或者小随机数都行 theta <- rep(0, n) for (epoch in 1:num_epochs) { # SGD的关键:每次迭代前打乱样本顺序,避免顺序影响 shuffle_idx <- sample(1:m, m) X_shuffled <- X[shuffle_idx, ] y_shuffled <- labels[shuffle_idx] # 遍历每个样本更新theta for (i in 1:m) { x_i <- X_shuffled[i, ] y_i <- y_shuffled[i] # 计算当前样本的预测值 h_i <- sigmoid(t(theta) %*% x_i) # 计算梯度 grad <- (h_i - y_i) * x_i # 更新theta theta <- theta - alpha * grad } } return(theta) }
你可以对照这个代码检查自己的实现:
- 有没有加截距项?
- sigmoid函数是不是正确?
- 梯度计算和theta更新的步骤是不是对应?
- 是不是在每个样本迭代后都更新了theta?
如果还是搞不定,把完整的代码贴出来,我帮你揪出具体问题~
内容的提问来源于stack exchange,提问作者Jatt
相关产品推荐
相关产品推荐

