R中的朴素岭回归?

机器算法验证 r 回归 岭回归
2022-04-15 23:45:28

我正在尝试学习一些基本的机器学习和一些基本的 R。我根据以下公式对 RL2

w^ridge=(XTX+λI)1XTy

我的代码如下所示:

fitRidge <- function(X, y, lambda) {
     # Add intercept column to X:
  X <- cbind(1, X)
     # Calculate penalty matrix:
  lambda.diag <- lambda * diag(dim(X)[2])
     # Apply formula for Ridge Regression:
  return(solve(t(X) %*% X + lambda.diag) %*% t(X) %*% y)
}

请注意,我还没有尝试找到最佳的,我只是为给定的然而,似乎有些不对劲。当我输入时,我得到了预期的 OLS 结果。我通过在同一数据集上应用 lm.ridge(lambda = 0) 来检查这一点,它给了我相同的系数。但是,当我输入任何其他惩罚时,例如,我的系数和 lm.ridge 给出的系数大相径庭。我尝试查看 lm.ridge 的实现,但我无法弄清楚它的作用(因此它的作用不同)。λw^ridgeλλ=0λ=2λ=5

谁能解释为什么我的结果和 lm.ridge 的结果有区别?我在我的代码中做错了吗?我试过玩,scale()但在那里找不到答案。

编辑:

要查看会发生什么,请运行以下命令:

library(car)
X.prestige <- as.matrix.data.frame(Prestige[,c(1,2,3,5)])
y.prestige <- Prestige[,4]

fitRidge(X.prestige, y.prestige, 0)
coef(lm.ridge(formula = prestige~education+income+women+census, data = Prestige, lambda = 0))
fitRidge(X.prestige, y.prestige, 2)
coef(lm.ridge(formula = prestige~education+income+women+census, data = Prestige, lambda = 2))

编辑2:

好的,所以根据下面的回答,我对这个问题有了更清晰的理解。我还仔细阅读了 Hastie、Tibshirani 和 Friedman 在 TESL 中关于 RR 的部分,我发现截距通常被简单地估计为响应的平均值。似乎 RR online 上的许多资源都过于模糊。我实际上怀疑许多作家自己从未实施过 RR,并且可能没有意识到一些重要的事情,因为他们中的许多人遗漏了 3 个重要事实:

  1. 截距在正常情况下不会受到惩罚,上面的公式只适用于其他系数。
  2. RR 在标度下不是等变的,即即使对于相同的数据,不同的标度也会给出不同的结果。
  3. 从 1 开始,实际如何估计截距。

我尝试相应地改变我的功能:

fitRidge <- function(X, Y, lambda) {
  # Standardize X and Y
  X <- scale(X)
  Y <- scale(Y)
  # Generate penalty matrix
  penalties <- lambda * diag(ncol(X))
  # Estimate intercept
  inter <- mean(Y)
  # Solve ridge system
  coeff <- solve(t(X) %*% X + penalties, t(X) %*% Y)
  # Create standardized weight vector
  wz <- c(inter, coeff )
  return(wz)
}

我仍然没有得到与 lm.ridge 等效的结果,但这可能只是将公式转换回原始比例的问题。但是,我似乎无法弄清楚如何做到这一点。我认为它只需要乘以响应的标准偏差并添加平均值,就像标准分数一样,但要么我的函数仍然错误,要么重新调整比我意识到的更复杂。

有什么建议吗?

3个回答

首先,很简单,我认为您的电话solve看起来不对,这是我所期望的

solve(t(X) %*% X + lambda.diag, t(X) %*% y)

您的代码似乎明确计算矩阵逆然后相乘。这在数学上是正确的,但在计算上是不正确的。求解方程组总是更好。我已经养成了阅读之类的方程作为“求解方程组 for ”的习惯。y=X1zXy=zy

在更数学的注释中,在拟合岭回归时,您不应该包含截距项。

在应用惩罚方法时,标准化您的数据非常重要(正如您在评论中指出的那样scale。同样重要的是要意识到惩罚通常不适用于截距项,因为这会导致模型违反吸引力平均预测等于平均响应(在训练数据上)的属性。

总之,这些事实(中心数据,没有截距惩罚)意味着岭回归中的截距参数估计是先验已知的,它为零。

岭回归的系数向量是惩罚优化问题的解

β=argmin((yXβ)t(yXβ)+12j>0βj2)

取截距参数的一部分

Lβ0=i=1n(yj=0qβjxij)xi0

但是是模型矩阵中对应于截距的条目,所以总是。所以我们得到x0ix0i=1

i=1yi+j=0qβji=1nxij

第一项,在 y 上的总和为零,因为居中(或者不是,一个很好的理解检查是弄清楚如果你不居中 y 会发生什么)。在第二项中,每个预测变量都是居中的,因此对于截距之外的每个预测变量上的总和为零。对于截距,第二项 sum 得出(它是)。所以这整个事情减少到yij in1+1+1+

nβ0

将此部分设置为零,,我们恢复,如预期的那样。nβ0=0β0=0

因此,您不需要将截距项绑定到模型矩阵。您的函数应该期望标准化数据(如果您计划将其公开,它应该检查是否如此),或者标准化数据本身。完成此操作后,已知截距为零。当您将系数转换回未归一化的比例时,我将把它作为练习来计算截距应该是多少。

我仍然没有得到与 lm.ridge 等效的结果,但这可能只是将公式转换回原始比例的问题。但是,我似乎无法弄清楚如何做到这一点。我认为它只需要乘以响应的标准偏差并添加平均值,就像标准分数一样,但要么我的函数仍然错误,要么重新调整比我意识到的更复杂。

这有点复杂,但如果你小心的话,也不会太糟糕。这是我回答一个非常相似的问题的地方:

GLMnet - “非标准化”线性回归系数

如果您不标准化 ,您可能需要进行非常简单的更改。y

尝试在 R 控制台中键入 lm.ridge。您将看到该函数的代码,它确实标准化了输入。尝试标准化函数的输入并比较结果。

如果您阅读文档,您还可以看到:

如果模型中存在截距,则其系数不会受到惩罚。(如果你想惩罚拦截,请输入你自己的常数项并删除拦截。)

你在你的函数中惩罚拦截,所以这也会产生差异。

这里不是一个完整的答案,但是对于那些将尝试自己实现 Ridge 回归并将其结果与 lm.ridge 进行比较的人来说,有一些相关的事情。

lm.ridge 使用 SVD 来估计系数。实施有关如何做到这一点的相关解释非常简单,在这个问题的赞成评论中: 相关答案

它还以与scale()函数不同的方式标准化预测变量。它使用除以n而不是n-1这可以解释估计的微小偏差。

正如所指出的那样,拦截也有一些问题(它以与我不同的方式处理它),但我无法让 lm.ridge 中的所有内容都运行以弄清楚它对拦截项的确切作用。