Perché la regressione della cresta glmnet mi dà una risposta diversa rispetto al calcolo manuale?


28

Sto usando glmnet per calcolare le stime di regressione della cresta. Ho ottenuto alcuni risultati che mi hanno fatto sospettare che glmnet stia davvero facendo quello che penso faccia. Per verificare questo ho scritto un semplice script R in cui comparo il risultato della regressione della cresta effettuata da risolvere e quello in glmnet, la differenza è 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 della differenza è di solito intorno ai 20, che non può essere dovuta a algoritmi numericamente diversi, devo fare qualcosa di sbagliato. Quali sono le impostazioni che devo configurare glmnetper ottenere lo stesso risultato della cresta?


1
Hai visto questa domanda ?
cdeterman,

1
Sì, ma non riesco ancora a ottenere lo stesso risultato usando la normalizzazione.
Giovanni,

Potresti pubblicare il tuo codice allora?
Shadowtalker,

Ho appena avuto lo stesso 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 = campione (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)) I risultati differiscono un po 'e diventano molto più simili quando Uso lambda molto più alte per glmnet.
a11msp,

Intrigante. I coefficienti sembrano differire grosso modo dal fattore 10.
tomka

Risposte:


27

La differenza che stai osservando è dovuta alla divisione aggiuntiva per il numero di osservazioni, N, che GLMNET utilizza nella loro funzione oggettiva e nella standardizzazione implicita di Y per la sua deviazione standard del campione, come mostrato di seguito.

12NysyXβ22+λβ22/2

dove usiamo al posto di per , 1 / ( n - 1 ) s y s y = i ( y i - ˉ y ) 21/n1/(n1)sy

sy=i(yiy¯)2n

Differenziando rispetto alla beta, impostando l'equazione su zero,

XTXβXTysy+Nλβ=0

E risolvendo per la beta, otteniamo il preventivo,

β~GLMNET=(XTX+NλIp)1XTysy

Per recuperare le stime (e le relative penalità) sulla metrica originale di Y, GLMNET moltiplica sia le stime che le per e restituisce questi risultati all'utente,sy

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

Confronta questa soluzione con la derivazione standard della regressione della cresta.

β^=(XTX+λIp)1XTy

Si noti che viene ridimensionato di un fattore aggiuntivo di N. Inoltre, quando si utilizza la funzione o , la penalità verrà ridimensionata implicitamente di . Vale a dire, quando usiamo queste funzioni per ottenere le stime dei coefficienti per alcuni , stiamo effettivamente ottenendo stime per .λpredict()coef()1/syλλ=λ/sy

Sulla base di queste osservazioni, la sanzione utilizzato in GLMNET deve essere scalato di un fattore .sy/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]

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

I risultati si generalizzano all'inserimento di un'intercetta e di variabili X standardizzate. Modifichiamo una matrice X standardizzata per includere una colonna di una e la matrice diagonale per avere un'entrata zero aggiuntiva nella posizione [1,1] (cioè non penalizzare l'intercettazione). È quindi possibile annullare la standardizzazione delle stime in base alle rispettive deviazioni standard del campione (di nuovo assicurarsi di utilizzare 1 / n durante il calcolo della deviazione standard).

β^j=βj~sxj

β^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

Codice aggiunto per mostrare X standardizzata senza intercettazione:

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

3
+6. Benvenuto in CV e grazie per aver risposto a questa vecchia domanda in modo così chiaro.
ameba dice di ripristinare Monica

1
Dovrebbe essere la matrice identità invece di nella soluzione di , corretta? ββ~
user1769197,

Noto anche che per la seconda parte in cui hai detto "I risultati si generalizzano all'inserimento di un'intercetta e variabili X standardizzate"; per questa parte, se si esclude l'intercettazione, quindi seguendo gli stessi calcoli, i risultati di glmnet diventano diversi dal calcolo manuale.
user1769197

Corretto, ho aggiornato la soluzione con la matrice identità al posto di se necessario. Ho verificato la soluzione per X standardizzata senza intercettazione e ancora ottenere risultati identici (vedere il codice aggiuntivo sopra). β
skijunkie,

3

Secondo https://web.stanford.edu/~hastie/glmnet/glmnet_alpha.html , quando la famiglia è gaussian, glmnet()dovrebbe minimizzare

(1)12ni=1n(yiβ0xiTβ)2+λj=1p(α|βj|+(1α)βj2/2).

Quando si utilizza glmnet(x, y, alpha=1)per adattare il lazo con le colonne in standardizzate, la soluzione per la penalità riportata è la soluzione per ridurre al minimo Tuttavia, almeno in , quando si utilizza per adattarsi alla regressione della cresta, la soluzione per una penalità segnalata è la soluzione per ridurre al minimo dove è la deviazione standard di . Qui, la penalità avrebbe dovuto essere segnalata come .xλ

12ni=1n(yiβ0xiTβ)2+λj=1p|βj|.
glmnet_2.0-13glmnet(x, y, alpha=0)λ
12ni=1n(yiβ0xiTβ)2+λ12syj=1pβj2.
syyλ/sy

Ciò che potrebbe accadere è che la funzione standardizza dapprima a e quindi riduce a icona che di fatto è minimizzare o equivalentemente, per ridurre al minimo yy0

(2)12ni=1n(y0ixiTγ)2+ηj=1p(α|γj|+(1α)γj2/2),
12nsy2i=1n(yiβ0xiTβ)2+ηαsyj=1p|βj|+η1α2sy2j=1pβj2,
12ni=1n(yiβ0xiTβ)2+ηsyαj=1p|βj|+η(1α)j=1pβj2/2.

Per il lazo ( ), ridimensionare per riportare la penalità come ha senso. Quindi per tutti , deve essere segnalato come penalità per mantenere la continuità dei risultati su . Questa è probabilmente la causa del problema sopra. Ciò è in parte dovuto all'utilizzo di (2) per risolvere (1). Solo quando o c'è una certa equivalenza tra i problemi (1) e (2) (cioè una corrispondenza tra in (1) e in (2)). Per qualsiasi altroη η s y α η s y α α = 0 α = 1 λ η α ( 0 , 1 ) λ ηα=1ηηsyαηsyαα=0α=1ληα(0,1), i problemi (1) e (2) sono due diversi problemi di ottimizzazione e non esiste una corrispondenza uno a uno tra in (1) e in (2).λη


1
Non riesco a vedere dove differisce la tua risposta dalla precedente. Potresti spiegare, per favore?
Firebug,

1
@Firebug Volevo far luce sul perché la funzione riporta la lambda in questo modo, che appare innaturale se vista solo dal punto di vista della regressione della cresta, ma ha senso (o deve essere così) se vista dalla prospettiva dell'intero spettro tra cui sia la cresta che il lazo.
Chun Li,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.