Utilizzo di LASSO dal pacchetto lars (o glmnet) in R per la selezione delle variabili


39

Scusate se questa domanda si presenta un po 'di base.

Sto cercando di utilizzare la selezione delle variabili LASSO per un modello di regressione lineare multipla in R. Ho 15 predittori, uno dei quali è categorico (ciò causerà un problema?). Dopo aver impostato la mia ed io uso i seguenti comandi:Xy

model = lars(x, y)
coef(model)

Il mio problema è quando uso coef(model). Ciò restituisce una matrice con 15 righe, con un predittore aggiuntivo aggiunto ogni volta. Tuttavia, non vi è alcun suggerimento su quale modello scegliere. Ho perso qualcosa? C'è un modo in cui posso ottenere il pacchetto Lars per restituire solo un modello " migliore "?

Ci sono altri post che suggeriscono di utilizzare glmnetinvece, ma questo sembra più complicato. Un tentativo è come segue, utilizzando lo stesso e . Mi sono perso qualcosa qui ?: yXy

cv = cv.glmnet(x, y)
model = glmnet(x, y, type.gaussian="covariance", lambda=cv$lambda.min)
predict(model, type="coefficients")

Il comando finale restituisce un elenco delle mie variabili, la maggior parte con un coefficiente sebbene alcune siano = 0. È questa la scelta corretta del modello " migliore " selezionato da LASSO? Se poi inserisco un modello lineare con tutte le mie variabili che avevano coefficienti not=0ottengo stime di coefficienti molto simili, ma leggermente diverse. C'è una ragione per questa differenza? Sarebbe accettabile rimontare il modello lineare con queste variabili scelte da LASSO e prenderlo come mio modello finale? Altrimenti non riesco a vedere alcun valore p per significato. Ho perso qualcosa?

fa

type.gaussian="covariance" 

assicurarti che glmnetutilizzi la regressione lineare multipla?

La normalizzazione automatica delle variabili influisce sui coefficienti? Esiste un modo per includere termini di interazione in una procedura LASSO?

Sto cercando di utilizzare questa procedura più come una dimostrazione di come LASSO può essere utilizzato che per qualsiasi modello che verrà effettivamente utilizzato per qualsiasi inferenza / previsione importante se ciò cambia qualcosa.

Grazie per aver dedicato del tempo a leggere questo. Qualsiasi commento generale su LASSO / lars / glmnet sarebbe anche molto apprezzato.


4
Come commento laterale, se vuoi interpretare il risultato assicurati di dimostrare che l'insieme di variabili selezionate dal lazo è stabile. Questo può essere fatto usando la simulazione Monte Carlo o eseguendo il bootstrap del proprio set di dati.
Frank Harrell,

Risposte:


28

L'utilizzo glmnetè davvero semplice una volta che ne hai la conoscenza grazie alla sua eccellente vignetta in http://web.stanford.edu/~hastie/glmnet/glmnet_alpha.html (puoi anche controllare la pagina del pacchetto CRAN). Per quanto riguarda il miglior lambda per glmnet, la regola empirica è di usare

cvfit <- glmnet::cv.glmnet(x, y)
coef(cvfit, s = "lambda.1se")

invece di lambda.min.

Per fare lo stesso per larste devi farlo a mano. Ecco la mia soluzione

cv <- lars::cv.lars(x, y, plot.it = FALSE, mode = "step")
idx <- which.max(cv$cv - cv$cv.error <= min(cv$cv))
coef(lars::lars(x, y))[idx,]

Tieni presente che non è esattamente lo stesso, perché si ferma in un nodo di lazo (quando entra una variabile) anziché in qualsiasi punto.

Si noti che ora glmnetè il pacchetto preferito, è attivamente gestito, più di così lars, e che ci sono state domande su glmnetvs larsrisposte prima (gli algoritmi utilizzati differiscono).

Per quanto riguarda la tua domanda sull'uso del lazo per scegliere le variabili e adattarle a OLS, è in corso un dibattito. Google per OLS pubblica Lasso e ci sono alcuni articoli che trattano l'argomento. Anche gli autori di Elements of Statistical Learning ammettono che è possibile.

Modifica : ecco il codice per riprodurre più accuratamente ciò che glmnetfalars

  cv <- lars::cv.lars(x, y, plot.it = FALSE)
  ideal_l1_ratio <- cv$index[which.max(cv$cv - cv$cv.error <= min(cv$cv))]
  obj <- lars::lars(x, y)
  scaled_coefs <- scale(obj$beta, FALSE, 1 / obj$normx)
  l1 <- apply(X = scaled_coefs, MARGIN = 1, FUN = function(x) sum(abs(x)))
  coef(obj)[which.max(l1 / tail(l1, 1) > ideal_l1_ratio),]

+1 Ottima risposta! Potresti tu o qualcuno forse approfondire il motivo per cui lambda.1se è la regola empirica, invece di lambda.min?
Erosennin,

Dopo 4 anni di scrittura di questo (e non aver usato il lazo per un po ') la mia memoria è svanita. Scusate!
Juancentro,

9

Sto tornando a questa domanda da un po 'di tempo poiché penso di aver risolto la soluzione corretta.

Ecco una replica usando il set di dati mtcars:

library(glmnet)
`%ni%`<-Negate(`%in%')
data(mtcars)

x<-model.matrix(mpg~.,data=mtcars)
x=x[,-1]

glmnet1<-cv.glmnet(x=x,y=mtcars$mpg,type.measure='mse',nfolds=5,alpha=.5)

c<-coef(glmnet1,s='lambda.min',exact=TRUE)
inds<-which(c!=0)
variables<-row.names(c)[inds]
variables<-variables[variables %ni% '(Intercept)']

'variabili' ti dà l'elenco delle variabili che risolvono la soluzione migliore.


1
Stavo cercando il codice e trovo che "testing" non è stato ancora definito e quindi il codice: "final.list <-testing [-removed] #removing variabili" dà l'errore: oggetto non trovato Quindi guardando al codice I supponiamo che invece di usare "testing" dovrebbe essere usato "cp.list" in modo che il codice sia: final.list <-cp.list [-removed] #removing variabili final.list <-c (final.list, duplicati) #adding in quei var che sono stati entrambi rimossi e poi aggiunti in seguito Fammi sapere se questo è corretto Cordiali saluti

3
`%% ni` <-Negate ( `%% ni`); ## sembra sbagliato. Mentre `% ni%` <-Negate (`% in%`); ## sembra giusto. Penso che il formattatore di StackExchange lo abbia incasinato ...
Chris

Puoi elaborare come hai scelto i parametri nfolds=5e alpha=0.5?
colin,

7

Forse il confronto con la regressione graduale della selezione diretta aiuterà (vedere il seguente collegamento a un sito di uno degli autori http://www-stat.stanford.edu/~tibs/lasso/simple.html). Questo è l'approccio utilizzato nel capitolo 3.4.4 di The Elements of Statistical Learning (disponibile online gratuitamente). Pensavo che il capitolo 3.6 di quel libro aiutasse a comprendere la relazione tra minimi quadrati, miglior sottoinsieme e lazo (più un paio di altre procedure). Trovo anche utile prendere la trasposizione del coefficiente, t (coef (modello)) e write.csv, in modo da poterlo aprire in Excel insieme a una copia della trama (modello) sul lato. È possibile ordinare in base all'ultima colonna, che contiene la stima dei minimi quadrati. Quindi puoi vedere chiaramente come ogni variabile viene aggiunta ad ogni passaggio a tratti e come i coefficienti cambiano di conseguenza. Naturalmente questa non è tutta la storia, ma speriamo che sia un inizio.


3

larse glmnetoperare su matrici grezze. Per includere i termini di interazione, dovrai costruire tu stesso le matrici. Ciò significa una colonna per interazione (che è per livello per fattore se si hanno fattori). Guarda lm()per vedere come funziona (attenzione: ci sono draghi).

Per farlo adesso, fare qualcosa di simile: Per fare manualmente un termine di interazione, si potrebbe (ma forse non dovrebbe , perché è lento) fare:

int = D["x1"]*D["x2"]
names(int) = c("x1*x2")
D = cbind(D, int)

Quindi per usare questo in Lars (supponendo che tu abbia un ycalcio in giro):

lars(as.matrix(D), as.matrix(y))

Vorrei poterti aiutare di più con le altre domande. Ho trovato questo perché Lars mi sta dando dolore e la documentazione in esso e sul web è molto sottile.


2
"Attenzione: ci sono draghi" Questo è abbastanza facile con model.matrix().
Gregor,

2

LARS risolve TUTTO il percorso della soluzione. Il percorso della soluzione è lineare a tratti - esiste un numero finito di punti di "tacca" (ovvero valori del parametro di regolarizzazione) in cui la soluzione cambia.

Quindi la matrice di soluzioni che stai ricevendo sono tutte le possibili soluzioni. Nell'elenco che restituisce, dovrebbe anche fornire i valori del parametro di regolarizzazione.


La ringrazio per la risposta. C'è un modo per visualizzare i valori del parametro di regolarizzazione? Inoltre c'è un modo per scegliere tra le soluzioni basate su questo parametro? (Anche il parametro lambda?)
James,

Si noti che la linearità a tratti non significa che le linee siano orizzontali, e quindi la soluzione cambia continuamente con lambda. Ad esempio, per scopi predittivi si avrebbe una griglia di valori lambda non solo a ma anche tra i nodi. È del tutto possibile che un punto tra i nodi produca le migliori prestazioni predittive.
Richard Hardy,
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.