Repository navigation
13/ Penalised GLM: lambda by 5-fold cross-validation; lambda filter considers every class (changes results) - #139
Draft
ellispatrick wants to merge 1 commit into
Draft
ellispatrick wants to merge 1 commit into
ellispatrick wants to merge 1 commit into
Conversation
This was referenced Oct 10, 2026
ellispatrick
force-pushed
the
review/9-coxnet-path
branch
from
October 10, 2026 22:47
9bff739 to
c712639
Compare
ellispatrick
force-pushed
the
review/13-glm-cv-lambda
branch
from
October 10, 2026 22:47
9c4a21a to
0cdebca
Compare
…bdas at which any class has a coefficient (changes results) Why: resubstitution chooses lambdas close to the unpenalised end of the path (10-30x smaller than cross-validation on the protocol data), which overfits larger cohorts: PROMAD GSE48581 (262 samples) kept 53 features with balanced accuracy 0.638, against 18 features and 0.713 with cross-validation. Over 11 data sets and views (asthma, Procedures 1, 3 and 4; 20 x 5 CV) the mean balanced accuracy changes by +0.002 and the AUC by -0.006, models keep about 40% fewer features, and runs take 1.0-1.7x as long (seconds). The inner folds are stratified by class, use the same path and class weights as the fit, and measure the class-weighted misclassification, which is the balanced error. extraParams = list(train = list(lambdaTuning = "resubstitution")) gives the previous choice exactly; nFoldsLambda sets the number of folds. With a class of fewer than three training samples, lambda is chosen by resubstitution with a warning. The lambda filter used the signed sum of the first class's coefficients, so for three or more classes it dropped lambdas at which only that class's coefficients were zero, and the choice depended on the order of the factor levels; a path made only of such lambdas was an error. Every class is now considered. Two-class results are unchanged by this part. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TfsjwkbDbHkX4kJZNe4ER4
ellispatrick
force-pushed
the
review/13-glm-cv-lambda
branch
from
October 14, 2026 00:20
0cdebca to
5529a8e
Compare
ellispatrick
force-pushed
the
review/9-coxnet-path
branch
from
October 14, 2026 00:20
c712639 to
333aa6c
Compare
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Changes results (Ellis Patrick's decision, on the evidence below). The penalised GLM classifiers (
ridgeGLM,elasticNetGLM,LASSOGLM) choose lambda by 5-fold cross-validation of the balanced error within each training set, instead of by the balanced error of the training samples themselves (resubstitution).extraParams = list(train = list(lambdaTuning = "resubstitution")).Why
cv.glmnet.Evidence
20 × 5 CV, seed 1, 4 cores; the penalised GLM is the classifier in every run.
resubstitutionis this PR withlambdaTuning = "resubstitution", and it is identical to #134 on every data set.Times are on a shared server; repeat runs of the same setting varied by up to 35%.
Caveat: the average gain is within noise. The case rests on resubstitution being a biased choice of lambda, sparser models, the fix on larger cohorts, and consistency with CoxNet, all for seconds of extra time.
What changes
penalisedGLMtrainInterfacehas new argumentslambdaTuning = c("CV", "resubstitution")andnFoldsLambda = 5:cv.glmnetuses the same lambda path and class weights as the fit, with folds stratified by class andtype.measure = "class". Weighted by inverse class size, misclassification is the balanced error.The inner folds use the random stream, so results change for any seed. This includes
precisionPathwaysTrain, whose default classifier for clinical data iselasticNetGLM(Procedure 3).?crossValidatedescribes the tuning and the option.Tests:
552 expectations pass (
test_branch.sh).Scripts and results: ProjectClassifyR
scripts/glm_cv_benchmark/.🤖 Generated with Claude Code
https://claude.ai/code/session_01TfsjwkbDbHkX4kJZNe4ER4