Caret glmnet vs cv.glmnet

14

Tampaknya ada banyak kebingungan dalam perbandingan menggunakan di glmnetdalam caretuntuk mencari lambda yang optimal dan menggunakan cv.glmnetuntuk melakukan tugas yang sama.

Banyak pertanyaan diajukan, misalnya:

Klasifikasi model train.glmnet vs. cv.glmnet?

Apa cara yang tepat untuk menggunakan glmnet dengan caret?

Validasi silang `glmnet` menggunakan` caret`

tetapi tidak ada jawaban yang diberikan, yang mungkin disebabkan oleh kemampuan reproduksi pertanyaan itu. Mengikuti pertanyaan pertama, saya memberikan contoh yang sangat mirip tetapi memiliki pertanyaan yang sama: Mengapa perkiraan lambda begitu berbeda?

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)

Sebagai rangkuman, lambda optimal diberikan sebagai:

  • 0,055 dengan menggunakan cv.glmnet()

  • 0,001 dengan menggunakan train()

Saya tahu bahwa menggunakan standardize=FALSEdalam cv.glmnet()tidak disarankan, tetapi saya benar-benar ingin membandingkan kedua metode menggunakan prasyarat yang sama. Sebagai penjelasan utama, saya pikir pendekatan pengambilan sampel untuk setiap lipatan mungkin menjadi masalah - tetapi saya menggunakan benih yang sama dan hasilnya sangat berbeda.

Jadi saya benar-benar terjebak pada mengapa kedua pendekatan itu sangat berbeda, sementara mereka harus sangat mirip? - Saya harap masyarakat memiliki ide apa masalahnya di sini

Jogi
sumber

Jawaban:

16

Saya melihat dua masalah di sini. Pertama, set pelatihan Anda relatif kecil dibandingkan dengan set pengujian Anda. Biasanya, kami ingin satu set pelatihan yang setidaknya sebanding dalam ukuran dengan set pengujian. Catatan lain adalah bahwa untuk Validasi Silang, Anda tidak menggunakan set pengujian sama sekali, karena algoritma pada dasarnya membuat set pengujian untuk Anda menggunakan "set pelatihan". Jadi Anda akan lebih baik menggunakan lebih banyak data sebagai set pelatihan awal Anda.

Kedua, 3 lipatan terlalu kecil untuk dapat diandalkan oleh CV Anda. Biasanya, 5-10 lipatan direkomendasikan ( nfolds = 5untuk cv.glmnetdan number=5untuk caret). Dengan perubahan ini, saya mendapatkan nilai lambda yang sama di kedua metode dan perkiraan yang hampir sama:

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)

Hasil:

> 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
StAtS
sumber
Terima kasih banyak atas jawaban Anda - sangat masuk akal bagi saya. Karena saya seorang pemula untuk CV, saya tidak memperhitungkan a) ukuran sampel dan b) lipatan.
Jogi
Terima kasih untuk kirimannya! Jadi jika saya melakukannya dengan benar, biasanya satu membagi dataset menjadi set pelatihan besar dan set tes yang lebih kecil (= tahan) dan melakukan k-fold CV pada set pelatihan. Akhirnya seseorang memvalidasi pada set tes, menggunakan hasil CV kan?
Jogi
@Jogi Itu akan menjadi cara untuk melakukannya. Anda juga dapat menggunakan seluruh dataset untuk CV jika Anda tidak memerlukan validasi lebih lanjut, karena CV sudah memilih parameter terbaik berdasarkan kinerja rata-rata model pada setiap iterasi set pengujian.
StAtS