Caret glmnet vs cv.glmnet


14

Dường như có rất nhiều nhầm lẫn trong việc so sánh sử dụng glmnetbên trong caretđể tìm kiếm một lambda tối ưu và sử dụng cv.glmnetđể thực hiện cùng một nhiệm vụ.

Nhiều câu hỏi đã được đặt ra, ví dụ:

Mô hình phân loại train.glmnet so với cv.glmnet?

Cách thích hợp để sử dụng glmnet với caret là gì?

Xác thực chéo `glmnet` bằng cách sử dụng` caret`

nhưng không có câu trả lời nào được đưa ra, điều này có thể là do độ lặp lại của câu hỏi. Sau câu hỏi đầu tiên, tôi đưa ra một ví dụ khá giống nhau nhưng lại có cùng một câu hỏi: Tại sao các lambdas ước tính lại khác nhau như vậy?

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)

Tóm lại, lambdas tối ưu được đưa ra là:

  • 0,055 bằng cách sử dụng cv.glmnet()

  • 0,001 bằng cách sử dụng train()

Tôi biết rằng không nên sử dụng standardize=FALSEin cv.glmnet(), nhưng tôi thực sự muốn so sánh cả hai phương pháp sử dụng cùng một điều kiện tiên quyết. Là khám phá chính, tôi nghĩ rằng phương pháp lấy mẫu cho mỗi lần gấp có thể là một vấn đề - nhưng tôi sử dụng cùng một hạt giống và kết quả khá khác nhau.

Vì vậy, tôi thực sự bế tắc về lý do tại sao hai cách tiếp cận rất khác nhau, trong khi chúng nên khá giống nhau? - Tôi hy vọng cộng đồng có một số ý tưởng vấn đề ở đây

Câu trả lời:


16

Tôi thấy hai vấn đề ở đây. Đầu tiên, tập huấn luyện của bạn quá nhỏ so với tập kiểm tra của bạn. Thông thường, chúng tôi muốn có một bộ huấn luyện có kích thước tối thiểu tương đương với bộ thử nghiệm. Một lưu ý khác là đối với Xác thực chéo, bạn hoàn toàn không sử dụng bộ kiểm tra, vì về cơ bản thuật toán sẽ tạo các bộ kiểm tra cho bạn bằng cách sử dụng "tập huấn luyện". Vì vậy, bạn nên sử dụng nhiều dữ liệu hơn như tập huấn luyện ban đầu của mình.

Thứ hai, 3 lần là quá nhỏ để CV của bạn đáng tin cậy. Thông thường, nên gấp 5-10 lần ( nfolds = 5cho cv.glmnetnumber=5cho caret). Với những thay đổi này, tôi đã nhận được các giá trị lambda giống nhau qua hai phương pháp và ước tính gần như giống hệt nhau:

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)

Kết quả:

> 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

Cảm ơn rất nhiều cho câu trả lời của bạn - nó có ý nghĩa hoàn hảo với tôi. Vì tôi là người mới đến CV nên tôi không tính đến a) kích thước của mẫu và b) nếp gấp.
Jogi

Cảm ơn vì bài đăng! Vì vậy, nếu tôi hiểu đúng, thường người ta chia bộ dữ liệu thành một tập huấn luyện lớn và một tập kiểm tra nhỏ hơn (= giữ) và thực hiện CV gấp k trên tập huấn luyện. Cuối cùng một cái xác nhận trên tập kiểm tra, sử dụng kết quả của CV phải không?
Jogi

@Jogi Đó sẽ là cách để làm điều đó. Bạn cũng có thể chỉ sử dụng toàn bộ tập dữ liệu cho CV nếu bạn không cần xác thực thêm, vì CV đã chọn các tham số tốt nhất dựa trên hiệu suất trung bình của mô hình trên mỗi lần lặp của các bộ kiểm tra.
StAtS
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.