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.