Perché Lars e Glmnet offrono soluzioni diverse per il problema del lazo?


22

Voglio capire meglio i pacchetti R Larse Glmnet, che sono usati per risolvere il problema Lazo: (per Variabili e campioni, vedi www.stanford.edu/~hastie/Papers/glmnet.pdf a pagina 3)pN

mion(β0β)Rp+1[12NΣio=1N(yio-β0-XioTβ)2+λ||β||l1]
pN

Pertanto, li ho applicati entrambi sullo stesso set di dati giocattolo. Sfortunatamente, i due metodi non forniscono le stesse soluzioni per lo stesso input di dati. Qualcuno ha idea da dove provenga la differenza?

Ho ottenuto i risultati come segue: Dopo aver generato alcuni dati (8 campioni, 12 funzioni, disegno di Toeplitz, tutto centrato), ho calcolato l'intero percorso del Lazo usando Lars. Quindi, ho eseguito Glmnet usando la sequenza di lambda calcolata da Lars (moltiplicata per 0,5) e speravo di ottenere la stessa soluzione, ma non l'ho fatto.

Si può vedere che le soluzioni sono simili. Ma come posso spiegare le differenze? Si prega di trovare il mio codice qui sotto. C'è una domanda correlata qui: GLMNET o LARS per il calcolo delle soluzioni LASSO? , ma non contiene la risposta alla mia domanda.

Impostare:

# Load packages.
library(lars)
library(glmnet)
library(MASS)

# Set parameters.
nb.features <- 12
nb.samples <- 8
nb.relevant.indices <- 3
snr <- 1
nb.lambdas <- 10

# Create data, not really important. 
sigma <- matrix(0, nb.features, nb.features)
for (i in (1:nb.features)) {
  for (j in (1:nb.features)) {
    sigma[i, j] <- 0.99 ^ (abs(i - j))
  }
}

x <- mvrnorm(n=nb.samples, rep(0, nb.features), sigma, tol=1e-6, empirical=FALSE)
relevant.indices <- sample(1:nb.features, nb.relevant.indices, replace=FALSE)
x <- scale(x)
beta <- rep(0, times=nb.features)
beta[relevant.indices] <- runif(nb.relevant.indices, 0, 1)
epsilon <- matrix(rnorm(nb.samples),nb.samples, 1)
simulated.snr <-(norm(x %*% beta, type="F")) / (norm(epsilon, type="F"))
epsilon <- epsilon * (simulated.snr / snr)
y <- x %*% beta + epsilon
y <- scale(y)

LARS:

la <- lars(x, y, intercept=TRUE, max.steps=1000, use.Gram=FALSE)
co.lars <- as.matrix(coef(la, mode="lambda"))
print(round(co.lars, 4))

#          [,1] [,2] [,3]   [,4]   [,5]   [,6]    [,7]   [,8]    [,9]   [,10]
#  [1,]  0.0000    0    0 0.0000 0.0000 0.0000  0.0000 0.0000  0.0000  0.0000
#  [2,]  0.0000    0    0 0.0000 0.0000 0.1735  0.0000 0.0000  0.0000  0.0000
#  [3,]  0.0000    0    0 0.2503 0.0000 0.4238  0.0000 0.0000  0.0000  0.0000
#  [4,]  0.0000    0    0 0.1383 0.0000 0.7578  0.0000 0.0000  0.0000  0.0000
#  [5,] -0.1175    0    0 0.2532 0.0000 0.8506  0.0000 0.0000  0.0000  0.0000
#  [6,] -0.3502    0    0 0.2676 0.3068 0.9935  0.0000 0.0000  0.0000  0.0000
#  [7,] -0.4579    0    0 0.6270 0.0000 0.9436  0.0000 0.0000  0.0000  0.0000
#  [8,] -0.7848    0    0 0.9970 0.0000 0.9856  0.0000 0.0000  0.0000  0.0000
#  [9,] -0.3175    0    0 0.0000 0.0000 3.4488  0.0000 0.0000 -2.1714  0.0000
# [10,] -0.4842    0    0 0.0000 0.0000 4.7731  0.0000 0.0000 -3.4102  0.0000
# [11,] -0.4685    0    0 0.0000 0.0000 4.7958  0.0000 0.1191 -3.6243  0.0000
# [12,] -0.4364    0    0 0.0000 0.0000 5.0424  0.0000 0.3007 -4.0694 -0.4903
# [13,] -0.4373    0    0 0.0000 0.0000 5.0535  0.0000 0.3213 -4.1012 -0.4996
# [14,] -0.4525    0    0 0.0000 0.0000 5.6876 -1.5467 1.5095 -4.7207  0.0000
# [15,] -0.4593    0    0 0.0000 0.0000 5.7355 -1.6242 1.5684 -4.7440  0.0000
# [16,] -0.4490    0    0 0.0000 0.0000 5.8601 -1.8485 1.7767 -4.9291  0.0000
#         [,11]  [,12]
#  [1,]  0.0000 0.0000
#  [2,]  0.0000 0.0000
#  [3,]  0.0000 0.0000
#  [4,] -0.2279 0.0000
#  [5,] -0.3266 0.0000
#  [6,] -0.5791 0.0000
#  [7,] -0.6724 0.2001
#  [8,] -1.0207 0.4462
#  [9,] -0.4912 0.1635
# [10,] -0.5562 0.2958
# [11,] -0.5267 0.3274
# [12,]  0.0000 0.2858
# [13,]  0.0000 0.2964
# [14,]  0.0000 0.1570
# [15,]  0.0000 0.1571

glmnet con lambda = (lambda_lars / 2):

glm2 <- glmnet(x, y, family="gaussian", lambda=(0.5 * la$lambda), thresh=1e-16)
co.glm2 <- as.matrix(t(coef(glm2, mode="lambda")))
print(round(co.glm2, 4))

#     (Intercept)      V1 V2 V3     V4     V5     V6      V7     V8      V9
# s0            0  0.0000  0  0 0.0000 0.0000 0.0000  0.0000 0.0000  0.0000
# s1            0  0.0000  0  0 0.0000 0.0000 0.0000  0.0000 0.0000  0.0000
# s2            0  0.0000  0  0 0.2385 0.0000 0.4120  0.0000 0.0000  0.0000
# s3            0  0.0000  0  0 0.2441 0.0000 0.4176  0.0000 0.0000  0.0000
# s4            0  0.0000  0  0 0.2466 0.0000 0.4200  0.0000 0.0000  0.0000
# s5            0  0.0000  0  0 0.2275 0.0000 0.4919  0.0000 0.0000  0.0000
# s6            0  0.0000  0  0 0.1868 0.0000 0.6132  0.0000 0.0000  0.0000
# s7            0 -0.2651  0  0 0.2623 0.1946 0.9413  0.0000 0.0000  0.0000
# s8            0 -0.6609  0  0 0.7328 0.0000 1.6384  0.0000 0.0000 -0.5755
# s9            0 -0.4633  0  0 0.0000 0.0000 4.6069  0.0000 0.0000 -3.2547
# s10           0 -0.4819  0  0 0.0000 0.0000 4.7546  0.0000 0.0000 -3.3929
# s11           0 -0.4767  0  0 0.0000 0.0000 4.7839  0.0000 0.0567 -3.5122
# s12           0 -0.4715  0  0 0.0000 0.0000 4.7915  0.0000 0.0965 -3.5836
# s13           0 -0.4510  0  0 0.0000 0.0000 5.6237 -1.3909 1.3898 -4.6583
# s14           0 -0.4552  0  0 0.0000 0.0000 5.7064 -1.5771 1.5326 -4.7298
#         V10     V11    V12
# s0   0.0000  0.0000 0.0000
# s1   0.0000  0.0000 0.0000
# s2   0.0000  0.0000 0.0000
# s3   0.0000  0.0000 0.0000
# s4   0.0000  0.0000 0.0000
# s5   0.0000 -0.0464 0.0000
# s6   0.0000 -0.1293 0.0000
# s7   0.0000 -0.4868 0.0000
# s8   0.0000 -0.8803 0.3712
# s9   0.0000 -0.5481 0.2792
# s10  0.0000 -0.5553 0.2939
# s11  0.0000 -0.5422 0.3108
# s12  0.0000 -0.5323 0.3214
# s13 -0.0503  0.0000 0.1711
# s14  0.0000  0.0000 0.1571

Risposte:


20

Finalmente siamo riusciti a produrre la stessa soluzione con entrambi i metodi! Il primo problema è che glmnet risolve il problema del lazo come indicato nella domanda, ma lars ha una normalizzazione leggermente diversa nella funzione obiettivo, sostituisce con . In secondo luogo, entrambi i metodi normalizzano i dati in modo diverso, quindi la normalizzazione deve essere disattivata quando si chiamano i metodi. 112N12

Per riprodurlo e vedere che le stesse soluzioni per il problema del lazo possono essere calcolate usando lars e glmnet, è necessario modificare le seguenti righe nel codice sopra:

la <- lars(X,Y,intercept=TRUE, max.steps=1000, use.Gram=FALSE)

a

la <- lars(X,Y,intercept=TRUE, normalize=FALSE, max.steps=1000, use.Gram=FALSE)

e

glm2 <- glmnet(X,Y,family="gaussian",lambda=0.5*la$lambda,thresh=1e-16)

a

glm2 <- glmnet(X,Y,family="gaussian",lambda=1/nbSamples*la$lambda,standardize=FALSE,thresh=1e-16)

1
Sono contento che tu l'abbia capito. Qualche idea su quale metodo di normalizzazione abbia più senso? In realtà ho ottenuto risultati peggiori usando la normalizzazione in glmnet (per il lazo) e non sono ancora sicuro del perché.
Ben Ogorek,

In realtà normalizzo i dati con disinvoltura e applico questi metodi e confronto se sono simili. Le variabili con effetti più piccoli di solito hanno coefficienti diversi
KarthikS

0

Ovviamente se i metodi utilizzano modelli diversi otterrai risposte diverse. La sottrazione dei termini di intercettazione non porta al modello senza l'intercettazione perché i coefficienti di adattamento migliori cambieranno e non li cambierete nel modo in cui vi state avvicinando. È necessario adattare lo stesso modello con entrambi i metodi se si desidera la stessa o quasi la stessa risposta.


1
Sì, hai ragione, i metodi usano modelli leggermente diversi, non ne ero a conoscenza. Grazie per il suggerimento. (Spiegherò le differenze in modo più dettagliato in una risposta separata)
Andre

-2

I risultati devono essere gli stessi. Il pacchetto lars usa di default type = "lar", cambia questo valore in type = "lasso". Abbassa semplicemente il parametro 'thresh = 1e-16' per glmnet poiché la discesa delle coordinate si basa sulla convergenza.


2
La ringrazio per la risposta. Forse sto leggendo male, ma sembra in contrasto con la risoluzione pubblicata nella risposta di Andre sei anni fa. Ti consigliamo di elaborare il tuo post per includere una spiegazione più completa di ciò che stai cercando di dire e mostrare perché dovremmo credere che sia corretto e l'altro no.
whuber
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.