Biến thể trong kết quả cv.glmnet


18

Tôi đang sử dụng cv.glmnetđể tìm dự đoán. Thiết lập tôi sử dụng như sau:

lassoResults<-cv.glmnet(x=countDiffs,y=responseDiffs,alpha=1,nfolds=cvfold)
bestlambda<-lassoResults$lambda.min

results<-predict(lassoResults,s=bestlambda,type="coefficients")

choicePred<-rownames(results)[which(results !=0)]

Để đảm bảo kết quả là tái sản xuất tôi set.seed(1). Các kết quả rất khác nhau. Tôi đã chạy chính xác mã 100 để xem kết quả biến như thế nào. Trong 98/100 lượt chạy, có một yếu tố dự đoán cụ thể luôn được chọn (đôi khi chỉ riêng nó); các yếu tố dự đoán khác đã được chọn (đồng hiệu quả là khác không) thường là 50/100 lần.

Vì vậy, nó nói với tôi rằng mỗi lần xác thực chéo đang chạy, nó có thể sẽ chọn một lambda tốt nhất khác nhau, bởi vì sự ngẫu nhiên ban đầu của các nếp gấp là vấn đề. Những người khác đã thấy vấn đề này ( kết quả CV.glmnet ) nhưng không có giải pháp được đề xuất.

Tôi đang nghĩ rằng có lẽ cái nào xuất hiện 98/100 có lẽ tương quan cao với tất cả những cái khác? Các kết quả sẽ ổn định nếu tôi chỉ chạy LOOCV ( Fold ), nhưng tôi tò mò tại sao chúng lại biến đổi như vậy khi .fold-size=nnfold<n


1
Để rõ ràng, bạn có nghĩa là bạn set.seed(1)một lần sau đó chạy cv.glmnet()100 lần? Đó không phải là phương pháp tuyệt vời cho khả năng tái sản xuất; tốt hơn là set.seed()phải trước mỗi lần chạy, hoặc nếu không thì giữ cho các nếp gấp không đổi trong các lần chạy. Mỗi cuộc gọi của bạn đến cv.glmnet()được gọi sample()N lần. Vì vậy, nếu độ dài dữ liệu của bạn thay đổi, độ lặp lại sẽ thay đổi.
smci

Câu trả lời:


14

Điểm ở đây là trong cv.glmnetcác nếp gấp K ("phần") được chọn ngẫu nhiên.

Trong xác thực chéo K-lần, bộ dữ liệu được chia thành các phần và phần K - 1 được sử dụng để dự đoán phần K (điều này được thực hiện K lần, sử dụng một phần K khác nhau mỗi lần). Điều này được thực hiện cho tất cả các lambdas, và là cái đưa ra lỗi xác nhận chéo nhỏ nhất.KK1KKlambda.min

Đây là lý do tại sao khi bạn sử dụng thì kết quả không thay đổi: mỗi nhóm được tạo thành một, vì vậy không có nhiều sự lựa chọn cho các nhóm K.nfolds=nK

Từ cv.glmnet()tài liệu tham khảo:

Cũng lưu ý rằng kết quả của cv.glmnet là ngẫu nhiên, vì các nếp gấp được chọn ngẫu nhiên. Người dùng có thể giảm tính ngẫu nhiên này bằng cách chạy cv.glmnet nhiều lần và lấy trung bình các đường cong lỗi.

### cycle for doing 100 cross validations
### and take the average of the mean error curves
### initialize vector for final data.frame with Mean Standard Errors
MSEs <- NULL
for (i in 1:100){
                 cv <- cv.glmnet(y, x, alpha=alpha, nfolds=k)  
                 MSEs <- cbind(MSEs, cv$cvm)
             }
  rownames(MSEs) <- cv$lambda
  lambda.min <- as.numeric(names(which.min(rowMeans(MSEs))))

MSE là khung dữ liệu chứa tất cả các lỗi cho tất cả lambdas (trong 100 lần chạy), lambda.minlà lambda của bạn có lỗi trung bình tối thiểu.


Điều tôi quan tâm nhất là việc lựa chọn n thực sự đôi khi có vẻ quan trọng. Tôi có nên tin tưởng vào kết quả có thể thay đổi như vậy? Hay tôi nên vẽ nó lên như sơ sài ngay cả khi tôi chạy nó nhiều lần?
dùng4673

1
Tùy thuộc vào cỡ mẫu, bạn nên chọn n để bạn có ít nhất 10 quan sát cho mỗi nhóm. Vì vậy, tốt hơn là giảm n (= 10) mặc định nếu bạn có cỡ mẫu nhỏ hơn 100. Điều này cho biết, hãy xem câu trả lời được chỉnh sửa với đoạn mã: với vòng lặp này, bạn có thể lặp lại cv.glmnet 100 lần và tính trung bình đường cong lỗi. Hãy thử một vài lần và bạn sẽ thấy lambda.min sẽ không thay đổi.
Alice

2
Tôi thích cách bạn đã làm nó. Tôi có cùng một vòng lặp nhưng có một ngoại lệ ở cuối: Tôi xem tần suất các tính năng khác nhau xuất hiện trái ngược với MSE thấp nhất trong tất cả các lần lặp. Tôi chọn một điểm cắt tùy ý (nghĩa là hiển thị 50/100 lần lặp) và sử dụng các tính năng đó. Tò mò tương phản hai cách tiếp cận.
dùng4673

1
tôimộtmbdmộterror,STôincecv

Như user4581 đã lưu ý, chức năng này có thể thất bại do sự thay đổi về độ dài của cv.glmnet(...)$lambda. Giải pháp thay thế của tôi khắc phục điều này: stats.stackexchange.com/a/173895/19676
Max Ghenis

9

λααλα

αλ

Sau đó, với mỗi người dự đoán tôi nhận được:

  • hệ số trung bình
  • độ lệch chuẩn
  • Tóm tắt 5 số (trung vị, tứ phân vị, tối thiểu và tối đa)
  • phần trăm số lần khác với số không (nghĩa là có ảnh hưởng)

Bằng cách này tôi có được một mô tả khá chắc chắn về tác dụng của yếu tố dự đoán. Khi bạn có các bản phân phối cho các hệ số, hơn bạn có thể chạy bất kỳ công cụ thống kê nào bạn nghĩ là có giá trị để nhận CI, giá trị p, v.v ... nhưng tôi chưa điều tra điều này.

Phương pháp này có thể được sử dụng với ít nhiều bất kỳ phương pháp lựa chọn nào tôi có thể nghĩ ra.


4
Bạn có thể gửi mã của bạn ở đây xin vui lòng?
rbm

Vâng, bạn có thể vui lòng gửi mã của bạn ở đây?
smci

4

Tôi sẽ thêm một giải pháp khác, xử lý lỗi trong @ Alice do thiếu lambdas, nhưng không yêu cầu các gói bổ sung như @Max Ghenis. Cảm ơn được nợ tất cả các câu trả lời khác - tất cả mọi người làm cho điểm hữu ích!

lambdas = NULL
for (i in 1:n)
{
    fit <- cv.glmnet(xs,ys)
    errors = data.frame(fit$lambda,fit$cvm)
    lambdas <- rbind(lambdas,errors)
}
# take mean cvm for each lambda
lambdas <- aggregate(lambdas[, 2], list(lambdas$fit.lambda), mean)

# select the best one
bestindex = which(lambdas[2]==min(lambdas[2]))
bestlambda = lambdas[bestindex,1]

# and now run glmnet once more with it
fit <- glmnet(xy,ys,lambda=bestlambda)

3

Câu trả lời của Alice hoạt động tốt trong hầu hết các trường hợp, nhưng đôi khi lỗi do cv.glmnet$lambdađôi khi trả về kết quả có độ dài khác nhau, ví dụ:

Lỗi trong rownames <- (tmp, value = c (0.135739830284452, 0.12368107787663 ,: độ dài của 'dimnames' [1] không bằng phạm vi mảng.

OptimLambdabên dưới nên hoạt động trong trường hợp chung và cũng nhanh hơn bằng cách tận dụng mclapplyđể xử lý song song và tránh các vòng lặp.

Lambdas <- function(...) {
  cv <- cv.glmnet(...)
  return(data.table(cvm=cv$cvm, lambda=cv$lambda))
}

OptimLambda <- function(k, ...) {
  # Returns optimal lambda for glmnet.
  #
  # Args:
  #   k: # times to loop through cv.glmnet.
  #   ...: Other args passed to cv.glmnet.
  #
  # Returns:
  #   Lambda associated with minimum average CV error over runs.
  #
  # Example:
  #   OptimLambda(k=100, y=y, x=x, alpha=alpha, nfolds=k)
  #
  require(parallel)
  require(data.table)
  MSEs <- data.table(rbind.fill(mclapply(seq(k), function(dummy) Lambdas(...))))
  return(MSEs[, list(mean.cvm=mean(cvm)), lambda][order(mean.cvm)][1]$lambda)
}

1

Bạn có thể kiểm soát tính ngẫu nhiên nếu bạn đặt rõ ràng Foldid. Dưới đây là một ví dụ cho CV 5 lần

library(caret)
set.seed(284)
flds <- createFolds(responseDiffs, k = cvfold, list = TRUE, returnTrain = FALSE)
foldids = rep(1,length(responseDiffs))
foldids[flds$Fold2] = 2
foldids[flds$Fold3] = 3
foldids[flds$Fold4] = 4
foldids[flds$Fold5] = 5

Bây giờ hãy chạy cv.glmnet với các nếp gấp này.

lassoResults<-cv.glmnet(x=countDiffs,y=responseDiffs,alpha=1,foldid = foldids)

Bạn sẽ nhận được kết quả tương tự mỗi lần.

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.