¿Por qué la regresión de cresta glmnet me da una respuesta diferente al cálculo manual?

28

Estoy usando glmnet para calcular las estimaciones de regresión de crestas. Obtuve algunos resultados que me hicieron sospechar que glmnet realmente está haciendo lo que creo que hace. Para verificar esto, escribí un script R simple donde comparo el resultado de la regresión de cresta realizada por resolver y el de glmnet, la diferencia es significativa:

n    <- 1000
p.   <-  100
X.   <- matrix(rnorm(n*p,0,1),n,p)
beta <- rnorm(p,0,1)
Y    <- X%*%beta+rnorm(n,0,0.5)

beta1 <- solve(t(X)%*%X+5*diag(p),t(X)%*%Y)
beta2 <- glmnet(X,Y, alpha=0, lambda=10, intercept=FALSE, standardize=FALSE, 
                family="gaussian")$beta@x
beta1-beta2

La norma de la diferencia es generalmente alrededor de 20, lo que no puede deberse a algoritmos numéricamente diferentes, debo estar haciendo algo mal. ¿Cuáles son las configuraciones que tengo que configurar glmnetpara obtener el mismo resultado que con la cresta?

John
fuente
1
¿Has visto esta pregunta ?
cdeterman
1
Sí, pero todavía no obtengo el mismo resultado con la normalización.
John
¿Podría publicar su código entonces?
shadowtalker
¡Acabo de tener el mismo problema! a = data.frame (a = jitter (1:10), b = jitter (1:10), c = jitter (1:10), d = jitter (1:10), e = jitter (1:10) , f = jitter (1:10), g = muestra (jitter (1:10)), y = seq (10,100,10)); coef (lm.ridge (y ~ a + b + c + d + e + f + g, a, lambda = 2.57)); coef (glmnet (as.matrix (a [, 1: 7]), a $ y, family = "gaussian", alpha = 0, lambda = 2.57 / 10)) Los resultados difieren bastante y se vuelven mucho más similares cuando Utilizo lambdas mucho más altas para glmnet.
a11msp
Intrigante. Los coeficientes parecen diferir aproximadamente por el factor 10.
tomka

Respuestas:

27

La diferencia que está observando se debe a la división adicional por el número de observaciones, N, que GLMNET utiliza en su función objetivo y la estandarización implícita de Y por su desviación estándar de muestra como se muestra a continuación.

12norteysy-Xβ22+λβ22/ /2

donde usamos en lugar de para , 1 / ( n - 1 ) s y s y = i ( y i - ˉ y ) 21/ /norte1/ /(norte-1)sy

sy=yo(yyo-y¯)2norte

Al diferenciar con respecto a beta, establecer la ecuación a cero,

XTXβ-XTysy+norteλβ=0 0

Y resolviendo para beta, obtenemos la estimación,

β~solLMETROnortemiT=(XTX+norteλyopags)-1XTysy

Para recuperar las estimaciones (y sus penalizaciones correspondientes) en la métrica original de Y, GLMNET multiplica tanto las estimaciones como las lambdas por y devuelve estos resultados al usuario,sy

lambda u n s t d . = s y λ

β^GLMNET=syβ~GLMNET=(XTX+NλIp)1XTy
λunstre.=syλ

Compare esta solución con la derivación estándar de regresión de cresta.

β^=(XTX+λyopags)-1XTy

Tenga en cuenta que se escala por un factor adicional de N. Además, cuando usamos la función o , la penalización se escalará implícitamente por . Es decir, cuando usamos estas funciones para obtener las estimaciones de coeficientes para algunos , estamos efectivamente obteniendo estimaciones para .1 / s y λ λ = λ / s yλpredict()coef()1/ /syλλ=λ/ /sy

Basándose en estas observaciones, la pena utilizado en GLMNET necesita ser reducido por un factor de .sy/ /norte

set.seed(123)

n    <- 1000
p   <-  100
X   <- matrix(rnorm(n*p,0,1),n,p)
beta <- rnorm(p,0,1)
Y    <- X%*%beta+rnorm(n,0,0.5)

sd_y <- sqrt(var(Y)*(n-1)/n)[1,1]

beta1 <- solve(t(X)%*%X+10*diag(p),t(X)%*%(Y))[,1]

fit_glmnet <- glmnet(X,Y, alpha=0, standardize = F, intercept = FALSE, thresh = 1e-20)
beta2 <- as.vector(coef(fit_glmnet, s = sd_y*10/n, exact = TRUE))[-1]
cbind(beta1[1:10], beta2[1:10])

           [,1]        [,2]
[1,]  0.23793862  0.23793862
[2,]  1.81859695  1.81859695
[3,] -0.06000195 -0.06000195
[4,] -0.04958695 -0.04958695
[5,]  0.41870613  0.41870613
[6,]  1.30244151  1.30244151
[7,]  0.06566168  0.06566168
[8,]  0.44634038  0.44634038
[9,]  0.86477108  0.86477108
[10,] -2.47535340 -2.47535340

Los resultados generalizan a la inclusión de una intercepción y variables X estandarizadas. Modificamos una matriz X estandarizada para incluir una columna de unos y la matriz diagonal para tener una entrada cero adicional en la posición [1,1] (es decir, no penalizar la intersección). A continuación, puede desestandarizar las estimaciones por sus respectivas desviaciones estándar de muestra (nuevamente asegúrese de estar usando 1 / n al calcular la desviación estándar).

β^j=βj~sXj

β^0 0=β0 0~-X¯Tβ^
mean_x <- colMeans(X)
sd_x <- sqrt(apply(X,2,var)*(n-1)/n)
X_scaled <- matrix(NA, nrow = n, ncol = p)
for(i in 1:p){
    X_scaled[,i] <- (X[,i] - mean_x[i])/sd_x[i] 
}
X_scaled_ones <- cbind(rep(1,n), X_scaled)

beta3 <- solve(t(X_scaled_ones)%*%X_scaled_ones+1000*diag(x = c(0, rep(1,p))),t(X_scaled_ones)%*%(Y))[,1]
beta3 <- c(beta3[1] - crossprod(mean_x,beta3[-1]/sd_x), beta3[-1]/sd_x)

fit_glmnet2 <- glmnet(X,Y, alpha=0, thresh = 1e-20)
beta4 <- as.vector(coef(fit_glmnet2, s = sd_y*1000/n, exact = TRUE))

cbind(beta3[1:10], beta4[1:10])
             [,1]        [,2]
 [1,]  0.24534485  0.24534485
 [2,]  0.17661130  0.17661130
 [3,]  0.86993230  0.86993230
 [4,] -0.12449217 -0.12449217
 [5,] -0.06410361 -0.06410361
 [6,]  0.17568987  0.17568987
 [7,]  0.59773230  0.59773230
 [8,]  0.06594704  0.06594704
 [9,]  0.22860655  0.22860655
[10,]  0.33254206  0.33254206

Código agregado para mostrar X estandarizado sin intercepción:

set.seed(123)

n <- 1000
p <-  100
X <- matrix(rnorm(n*p,0,1),n,p)
beta <- rnorm(p,0,1)
Y <- X%*%beta+rnorm(n,0,0.5)

sd_y <- sqrt(var(Y)*(n-1)/n)[1,1]

mean_x <- colMeans(X)
sd_x <- sqrt(apply(X,2,var)*(n-1)/n)

X_scaled <- matrix(NA, nrow = n, ncol = p)
for(i in 1:p){
    X_scaled[,i] <- (X[,i] - mean_x[i])/sd_x[i] 
}

beta1 <- solve(t(X_scaled)%*%X_scaled+10*diag(p),t(X_scaled)%*%(Y))[,1]

fit_glmnet <- glmnet(X_scaled,Y, alpha=0, standardize = F, intercept = 
FALSE, thresh = 1e-20)
beta2 <- as.vector(coef(fit_glmnet, s = sd_y*10/n, exact = TRUE))[-1]
cbind(beta1[1:10], beta2[1:10])

             [,1]        [,2]
 [1,]  0.23560948  0.23560948
 [2,]  1.83469846  1.83469846
 [3,] -0.05827086 -0.05827086
 [4,] -0.04927314 -0.04927314
 [5,]  0.41871870  0.41871870
 [6,]  1.28969361  1.28969361
 [7,]  0.06552927  0.06552927
 [8,]  0.44576008  0.44576008
 [9,]  0.90156795  0.90156795
[10,] -2.43163420 -2.43163420
skijunkie
fuente
3
+6. Bienvenido a CV y ​​gracias por responder esta vieja pregunta de una manera tan clara.
ameba dice Reinstate Monica
1
Debe ser la matriz de identidad en lugar de en la solución de , ¿correcto? ˜ βββ~
user1769197
También noté que para la segunda parte donde dijo "Los resultados se generalizan a la inclusión de una intercepción y variables X estandarizadas"; para esta parte, si excluye la intercepción, luego de seguir los mismos cálculos, los resultados de glmnet se vuelven diferentes del cálculo manual.
user1769197
Correcto, he actualizado la solución con la matriz de identidad en lugar de según sea necesario. Verifiqué la solución para X estandarizada sin intercepción y aún obtengo resultados idénticos (ver código adicional arriba). β
skijunkie
3

De acuerdo con https://web.stanford.edu/~hastie/glmnet/glmnet_alpha.html , cuando la familia está gaussian, glmnet()debe minimizar

(1)12norteyo=1norte(yyo-β0 0-XyoTβ)2+λj=1pags(αEl |βjEl |+(1-α)βj2/ /2).

Cuando se usa glmnet(x, y, alpha=1)para ajustar el lazo con las columnas en estandarizadas, la solución para la penalización reportada es la solución para minimizar Sin embargo, al menos en , cuando se usa para ajustar la regresión de cresta, la solución para una penalización reportada es la solución para minimizar donde es la desviación estándar de . Aquí, la penalización debería haberse informado como .Xλ

12norteyo=1norte(yyo-β0 0-XyoTβ)2+λj=1pagsEl |βjEl |.
glmnet_2.0-13glmnet(x, y, alpha=0)λ
12norteyo=1norte(yyo-β0 0-XyoTβ)2+λ12syj=1pagsβj2.
syyλ/ /sy

Lo que podría suceder es que la función primero estandariza a y luego minimiza que efectivamente es minimizar o equivalente, para minimizar yy0 0

(2)12norteyo=1norte(y0 0yo-XyoTγ)2+ηj=1pags(αEl |γjEl |+(1-α)γj2/ /2),
12nortesy2yo=1norte(yyo-β0 0-XyoTβ)2+ηαsyj=1pagsEl |βjEl |+η1-α2sy2j=1pagsβj2,
12norteyo=1norte(yyo-β0 0-XyoTβ)2+ηsyαj=1pagsEl |βjEl |+η(1-α)j=1pagsβj2/ /2)

Para el lazo ( ), volver a escalar para informar la penalización como tiene sentido. Entonces, para todos , debe ser reportado como la penalización para mantener la continuidad de los resultados en . Esta es probablemente la causa del problema anterior. Esto se debe en parte al uso de (2) para resolver (1). Solo cuando o existe cierta equivalencia entre los problemas (1) y (2) (es decir, una correspondencia entre en (1) y en (2)). Para cualquier otroα=1ηηsyαηsyαα=0 0α=1ληα(0 0,1), los problemas (1) y (2) son dos problemas de optimización diferentes, y no hay correspondencia uno a uno entre en (1) y en (2).λη

Chun Li
fuente
1
No puedo ver en qué difiere su respuesta de la anterior. ¿Podría explicar, por favor?
Firebug
1
@Firebug Quería aclarar por qué la función informa la lambda de esta manera, lo que parece poco natural cuando se ve únicamente desde la perspectiva de la regresión de cresta, pero tiene sentido (o tiene que ser así) cuando se ve desde la perspectiva de todo el espectro incluyendo tanto la cresta como el lazo.
Chun Li