Wie interpretiere ich glmnet?

36

Ich versuche, ein multivariates lineares Regressionsmodell mit ungefähr 60 Prädiktorvariablen und 30 Beobachtungen anzupassen , daher verwende ich das glmnet- Paket für die regulierte Regression, da p> n.

Ich habe Dokumentationen und andere Fragen durchgearbeitet, kann die Ergebnisse aber immer noch nicht interpretieren. Hier ist ein Beispielcode (mit 20 Prädiktoren und 10 Beobachtungen zur Vereinfachung):

Ich erstelle eine Matrix x mit num rows = num observations und num cols = num predictors und einem Vektor y, der die Antwortvariable darstellt

> x=matrix(rnorm(10*20),10,20)
> y=rnorm(10)

Ich passe ein Glmnet-Modell an und lasse Alpha als Standard (= 1 für Lasso-Strafe)

> fit1=glmnet(x,y)
> print(fit1)

Ich verstehe, dass ich mit abnehmenden Lambda-Werten (dh Strafe) unterschiedliche Vorhersagen erhalte.

Call:  glmnet(x = x, y = y) 

        Df    %Dev   Lambda
  [1,]  0 0.00000 0.890700
  [2,]  1 0.06159 0.850200
  [3,]  1 0.11770 0.811500
  [4,]  1 0.16880 0.774600
   .
   .
   .
  [96,] 10 0.99740 0.010730
  [97,] 10 0.99760 0.010240
  [98,] 10 0.99780 0.009775
  [99,] 10 0.99800 0.009331
 [100,] 10 0.99820 0.008907

Jetzt sage ich meine Beta-Werte voraus und wähle zum Beispiel den kleinsten Lambda-Wert aus glmnet

> predict(fit1,type="coef", s = 0.008907)

21 x 1 sparse Matrix of class "dgCMatrix"
                  1
(Intercept) -0.08872364
V1           0.23734885
V2          -0.35472137
V3          -0.08088463
V4           .         
V5           .         
V6           .         
V7           0.31127123
V8           .         
V9           .         
V10          .         
V11          0.10636867
V12          .         
V13         -0.20328200
V14         -0.77717745
V15          .         
V16         -0.25924281
V17          .         
V18          .         
V19         -0.57989929
V20         -0.22522859

Wenn ich stattdessen Lambda mit wähle

cv <- cv.glmnet(x,y)
model=glmnet(x,y,lambda=cv$lambda.min)

Alle Variablen wären (.).

Zweifel und Fragen:

  1. Ich bin mir nicht sicher, wie ich Lambda wählen soll.
  2. Sollte ich die nicht (.) Variablen verwenden, um ein anderes Modell anzupassen? In meinem Fall möchte ich so viele Variablen wie möglich behalten.
  3. Woher kenne ich den p-Wert, dh welche Variablen sagen die Reaktion signifikant voraus?

Ich entschuldige mich für meine schlechten statistischen Kenntnisse! Und danke für jede Hilfe.

Alice
quelle
Vielleicht werfen Sie einen Blick auf das CRAN-Paket hdi , das Rückschlüsse auf hochdimensionale Modelle
zulässt
Für die vollständige Erklärung der verwendeten Methoden verweise ich auf dieses Papier: projecteuclid.org/euclid.ss/1449670857
Tom Wenseleers

Antworten:

40

Hier ist eine nicht intuitive Tatsache - Sie sollten glmnet eigentlich keinen einzigen Wert von Lambda geben. Aus der Dokumentation hier :

Geben Sie keinen einzigen Wert für Lambda an (für Vorhersagen nach dem Lebenslauf verwenden Sie predict ()). Liefern Sie stattdessen eine abnehmende Folge von Lambdawerten. glmnet ist darauf angewiesen, dass seine Warme-Starts schnell sind und dass es oft schneller ist, einen ganzen Pfad zu finden, als eine einzelne Anpassung zu berechnen.

cv.glmnetwird Ihnen helfen, Lambda zu wählen, wie Sie in Ihren Beispielen angedeutet haben. Die Autoren des glmnet-Pakets schlagen cv$lambda.1sevor cv$lambda.min, aber in der Praxis hatte ich Erfolg mit letzterem.

Nachdem Sie cv.glmnet ausgeführt haben, müssen Sie glmnet nicht erneut ausführen! Jedes Lambda in der Tabelle ( cv$lambda) wurde bereits ausgeführt. Diese Technik wird als „Warmstart“ bezeichnet und Sie können mehr darüber lesen Sie hier . Ausgehend von der Einführung reduziert die Warmstart-Technik die Laufzeit iterativer Methoden, indem die Lösung eines anderen Optimierungsproblems (z. B. glmnet mit einem größeren Lambda) als Startwert für ein späteres Optimierungsproblem (z. B. glmnet mit einem kleineren Lambda) verwendet wird ).

cv.glmnet.fitVersuchen Sie Folgendes, um den gewünschten Lauf zu extrahieren :

small.lambda.index <- which(cv$lambda == cv$lambda.min)
small.lambda.betas <- cv$glmnet.fit$beta[, small.lambda.index]

Revision (28.01.2017)

Keine Notwendigkeit, sich an das glmnet-Objekt zu hacken, wie ich es oben getan habe; nehmen @ alex23lemm Rat unten und übergeben Sie die s = "lambda.min", s = "lambda.1se"oder eine andere Nummer (zB s = .007) auf beide coefund predict. Beachten Sie, dass Ihre Koeffizienten und Vorhersagen von diesem Wert abhängen, der durch Kreuzvalidierung festgelegt wird. Verwenden Sie einen Samen für die Reproduzierbarkeit! Und vergessen Sie nicht, dass Sie die Standardeinstellung von verwenden , wenn Sie kein "s"in coefund predictangeben s = "lambda.1se". Ich habe mich auf diese Standardeinstellung erwärmt, nachdem ich festgestellt habe, dass sie in einer Situation mit kleinen Datenmengen besser funktioniert.s = "lambda.1se"Wenn Sie also mit Alpha> 0 arbeiten, tendieren Sie auch zu einem sparsameren Modell. Sie können auch einen numerischen Wert von s mit Hilfe von plot.glmnet auswählen, um irgendwo dazwischen zu gelangen (vergessen Sie nur nicht, die Werte von der x-Achse aus zu potenzieren!).

Ben Ogorek
quelle
1
Vielen Dank! Das hilft ... haben Sie vielleicht eine Antwort auf die Fragen 2 und 3?
Alice
3
Ha, keine Sorge. Die (.) S stehen für Nullen. Seit Sie sich für Lasso entschieden haben, haben Sie angegeben, dass Sie eine "spärliche" Lösung (dh viele Nullen) wünschen. Wenn Sie möchten, dass alle Werte enthalten, setzen Sie alpha = 0. Jetzt sind Sie von der Lasso-Regression zur Ridge-Regression übergegangen. p-Werte für glmnet sind konzeptionell schwierig. Wenn Sie zum Beispiel in Google nach "p-Werten für Lasso" suchen, werden Sie eine Menge aktueller Forschungen und Debatten sehen. Ich habe sogar einen Bericht gelesen (Quelle Amnesie), in dem der Autor argumentierte, dass p-Werte für voreingenommene Regressionen wie Lasso und Gratregression keinen Sinn machen.
Ben Ogorek
6
Eine alternative Methode zum Extrahieren der Koeffizienten, die mit dem Lambda-Wert verknüpft sind, der den minimalen cvm ergibt, ist die folgende:small.lambda.betas <- coef(cv, s = "lambda.min")
alex23lemm
1
@BenOgorek, exzellentes Update! Eine weitere nützliche Referenz ist Friedman J., Hastie T., Hoefling H., Tibshirani R. Pathwise-Koordinatenoptimierung. Annalen der angewandten Statistik. 2007; 2 (1): 302–332. ( arxiv.org/pdf/0708.1485.pdf )
dv_bn
1
@erosennin, überprüfen Sie das Lambda-Argument von cv.glmnet: "Optionale vom Benutzer bereitgestellte Lambda-Sequenz; Standard ist NULL, und glmnet wählt seine eigene Sequenz." Sie sollten das Warmstart-Prinzip verwenden und die Sequenz mit einigen größeren Lambda-Werten beginnen, bevor Sie auf den gewünschten Bereich abnehmen.
Ben Ogorek,
2

Q1) Ich bin mir nicht sicher, wie ich Lambda wählen soll. F2) Soll ich die Nicht-Variablen (.) Verwenden, um ein anderes Modell anzupassen? In meinem Fall möchte ich so viele Variablen wie möglich behalten.

Gemäß der großartigen Antwort von @ BenOgorek lässt man die Anpassung normalerweise eine ganze Lambda-Sequenz verwenden, und verwendet dann beim Extrahieren der optimalen Koeffizienten den Lambda.1se-Wert (im Gegensatz zu dem, was Sie getan haben).

Solange Sie die folgenden drei Punkte einhalten, sollten Sie weder gegen die Regularisierung kämpfen noch das Modell optimieren: Wenn eine Variable weggelassen wurde, lag dies daran, dass die Gesamtstrafe geringer ausfiel. Die Vorsichtsmaßnahmen sind:

  1. Damit die regulierten Coeffts sinnvoll sind, müssen Sie zuvor den Mittelwert und die Standardabweichung der Variablen explizit mit normalisieren scale(). Verlasse dich nicht auf glmnet(standardize=T). Zur Begründung siehe Ist eine Normung vor Lasso wirklich notwendig? ; Grundsätzlich kann eine Variable mit großen Werten bei der Regularisierung ungerechtfertigt bestraft werden.

  2. Um reproduzierbar zu sein, laufen Sie mit set.seedmehreren Zufallskeimen und überprüfen Sie die regulierten Koeffizienten auf Stabilität.

  3. Wenn Sie eine weniger harte Regularisierung wünschen, dh mehr Variablen enthalten, verwenden Sie Alpha <1 (dh das richtige elastische Netz) anstelle eines einfachen Kamms. Ich schlage vor , Sie Alpha von 0 auf 1 fegen Wenn Sie das tun werden, dann Überanpassung des Hyper alpha und die Regressionsfehler zu vermeiden, Sie verwenden müssen , Kreuzvalidierung, dh verwenden , cv.glmnet()anstatt einfach glmnet():

.

for (alpha in c(0,.1,.3,.5,.7,.9,1)) {
  fit <- cv.glmnet(..., alpha=alpha, nfolds=...)
  # Look at the CVE at lambda.1se to find the minimum for this alpha value...
}

Wenn Sie eine solche Gittersuche mit CV automatisieren möchten, können Sie sie entweder selbst codieren oder das Caret-Paket über glmnet verwenden. Caret macht das gut. Zumcv.glmnet nfolds Parameterwert 3 (Minimum), wenn Ihr Datensatz klein ist, oder 5 oder 10, wenn er groß ist.

F3) Woher kenne ich den p-Wert, dh welche Variablen sagen die Reaktion signifikant voraus?

Tun Sie nicht, sie sind nicht sinnvoll . Wie ausführlich in Warum ist es nicht ratsam, statistische Zusammenfassungsinformationen für Regressionskoeffizienten aus dem GLMNET-Modell abzurufen?

Lassen Sie cv.glmnet()einfach die Variablenauswahl automatisch machen. Mit den oben genannten Einschränkungen. Und natürlich sollte die Verteilung der Antwortvariablen normal sein (vorausgesetzt, Sie verwenden family='gaussian').

smci
quelle
Danke für den sehr hilfreichen Kommentar! Ich habe auch erlebt, dass die Standardisierung der Variablen anscheinend funktioniert, anstatt das glmnet zu verwenden (standardize = T).
Michelle
Ich habe @smci eine Frage zu den von cvglmnet zurückgegebenen Beta-Werten. Ich verstehe, dass es sich um Beta-Werte an jedem Gitterpunkt der versuchten Lambda-Werte handelt. Werden jedoch die Beta-Werte für jeden Lambda-Wert zurückgegeben (1) die durchschnittlichen Koeffizientenwerte aus den 10-fachen (unter der Annahme, dass ich 10-fache CV verwendet habe), (2) die Beta-Werte aus der Falte, die die beste Genauigkeit ergab, oder (3) die Koeffizienten aus Modell für den gesamten Datensatz erneut ausführen?
Michelle