Caret glmnet vs cv.glmnet


14

Sembra esserci molta confusione nel confronto tra l'uso di glmnetinside caretper cercare un lambda ottimale e l'utilizzo cv.glmnetper fare lo stesso compito.

Sono state poste molte domande, ad esempio:

Modello di classificazione train.glmnet vs. cv.glmnet?

Qual è il modo corretto di usare glmnet con il cursore?

Convalida incrociata di `glmnet` usando` caret`

ma nessuna risposta è stata data, il che potrebbe essere dovuto alla riproducibilità della domanda. Seguendo la prima domanda, faccio un esempio abbastanza simile ma ho la stessa domanda: perché le lambda stimate sono così diverse?

library(caret)
library(glmnet)
set.seed(849)
training <- twoClassSim(50, linearVars = 2)
set.seed(849)
testing <- twoClassSim(500, linearVars = 2)
trainX <- training[, -ncol(training)]
testX <- testing[, -ncol(testing)]
trainY <- training$Class

# Using glmnet to directly perform CV
set.seed(849)
cvob1=cv.glmnet(x=as.matrix(trainX),y=trainY,family="binomial",alpha=1, type.measure="auc", nfolds = 3,lambda = seq(0.001,0.1,by = 0.001),standardize=FALSE)

cbind(cvob1$lambda,cvob1$cvm)

# best parameter
cvob1$lambda.mi

# best coefficient
coef(cvob1, s = "lambda.min")


# Using caret to perform CV
cctrl1 <- trainControl(method="cv", number=3, returnResamp="all",classProbs=TRUE,summaryFunction=twoClassSummary)
set.seed(849)
test_class_cv_model <- train(trainX, trainY, method = "glmnet", trControl = cctrl1,metric = "ROC",
                             tuneGrid = expand.grid(alpha = 1,lambda = seq(0.001,0.1,by = 0.001)))


test_class_cv_model 

# best parameter
test_class_cv_model$bestTune

# best coefficient
coef(test_class_cv_model$finalModel, test_class_cv_model$bestTune$lambda)

Riassumendo, le lambda ottimali sono date come:

  • 0.055 usando cv.glmnet()

  • 0,001 utilizzando train()

So che l'uso di standardize=FALSEin cv.glmnet()non è consigliabile, ma voglio davvero confrontare entrambi i metodi usando gli stessi prerequisiti. Come spiegazione principale, penso che l'approccio di campionamento per ogni piega possa essere un problema, ma uso gli stessi semi e i risultati sono abbastanza diversi.

Quindi sono davvero bloccato sul perché i due approcci sono così diversi, mentre dovrebbero essere abbastanza simili? - Spero che la comunità abbia qualche idea su quale sia il problema qui

Risposte:


16

Vedo due problemi qui. Innanzitutto, il set di allenamento è troppo piccolo rispetto al set di test. Normalmente, vorremmo un set di allenamento di dimensioni almeno paragonabili al set di test. Un'altra nota è che per la convalida incrociata non si utilizza affatto il set di test, in quanto l'algoritmo crea fondamentalmente set di test utilizzando il "set di training". Quindi faresti meglio a utilizzare più dati come set di allenamento iniziale.

In secondo luogo, 3 pieghe sono troppo piccole per essere affidabili. In genere, si consigliano 5-10 pieghe ( nfolds = 5per cv.glmnete number=5per caret). Con queste modifiche, ho ottenuto gli stessi valori lambda tra i due metodi e stime quasi identiche:

set.seed(849)
training <- twoClassSim(500, linearVars = 2)
set.seed(849)
testing <- twoClassSim(50, linearVars = 2)
trainX <- training[, -ncol(training)]
testX <- testing[, -ncol(testing)]
trainY <- training$Class

# Using glmnet to directly perform CV
set.seed(849)
cvob1=cv.glmnet(x=as.matrix(trainX), y=trainY,family="binomial",alpha=1, 
                type.measure="auc", nfolds = 5, lambda = seq(0.001,0.1,by = 0.001),
                standardize=FALSE)

cbind(cvob1$lambda,cvob1$cvm)

# best parameter
cvob1$lambda.min

# best coefficient
coef(cvob1, s = "lambda.min")


# Using caret to perform CV
cctrl1 <- trainControl(method="cv", number=5, returnResamp="all",
                       classProbs=TRUE, summaryFunction=twoClassSummary)
set.seed(849)
test_class_cv_model <- train(trainX, trainY, method = "glmnet", 
                             trControl = cctrl1,metric = "ROC",
                             tuneGrid = expand.grid(alpha = 1,
                                                    lambda = seq(0.001,0.1,by = 0.001)))

test_class_cv_model 

# best parameter
test_class_cv_model$bestTune

# best coefficient
coef(test_class_cv_model$finalModel, test_class_cv_model$bestTune$lambda)

Risultato:

> cvob1$lambda.min
[1] 0.001

> coef(cvob1, s = "lambda.min")
8 x 1 sparse Matrix of class "dgCMatrix"
1
(Intercept) -0.781015706
TwoFactor1  -1.793387005
TwoFactor2   1.850588656
Linear1      0.009341356
Linear2     -1.213777391
Nonlinear1   1.158009360
Nonlinear2   0.609911748
Nonlinear3   0.246029667

> test_class_cv_model$bestTune
alpha lambda
1     1  0.001

> coef(test_class_cv_model$finalModel, test_class_cv_model$bestTune$lambda)
8 x 1 sparse Matrix of class "dgCMatrix"
1
(Intercept) -0.845792624
TwoFactor1  -1.786976586
TwoFactor2   1.844767690
Linear1      0.008308165
Linear2     -1.212285068
Nonlinear1   1.159933335
Nonlinear2   0.676803555
Nonlinear3   0.309947442

Grazie mille per la tua risposta - ha perfettamente senso per me. Dato che sono un novellino del CV, non ho tenuto conto della a) dimensione del campione eb) delle pieghe.
Jogi,

Grazie per il post! Quindi, se ho capito bene, di solito si divide il set di dati in un set di allenamento di grandi dimensioni e in un set di test più piccolo (= holdout) ed eseguire il CV k-fold sul set di allenamento. Finalmente si convalida sul set di test, usando i risultati del CV giusto?
Jogi,

@Jogi Questo sarebbe il modo di farlo. Puoi anche utilizzare l'intero set di dati per CV se non hai bisogno di ulteriore convalida, poiché CV seleziona già i parametri migliori in base alle prestazioni medie del modello su ogni iterazione di set di test.
Atti
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.