Full Subsets Multiple Regression Using GAMs
Overview
Full-subsets information-theoretic approaches are increasingly used to explore predictive power and variable importance when a wide range of candidate predictors are being considered. This package provides functions that can be used to construct, fit, and compare a complete model set of possible ecological or environmental predictors for a given response variable of interest. Models are based on Generalized Additive Models (GAMs) and build on the 'MuMIn' package. Advantages include the capacity to fit more predictors than there are replicates, automatic removal of models with correlated predictors, and support for model sets that include interactions between factors and smooth predictors, as well as smooth-by-smooth interactions via te(). Methods are described in Fisher et al. (2018) doi:10.1002/ece3.4134.
generate_model_set()gainsnull.cov.cutoff, defaulting to 0.8, and returnsnull.term.correlations. **Behaviour change:** a predictor correlated with a variable named innull.termsabove that cutoff is now dropped from the model set, and a warning names it, what it correlates with, and how strongly (FSSgam_package#23).null.termsforces a term into every candidate, and those terms were outside thecov.cutoffscreen, which coverspred.vars.cont,pred.vars.factandlinear.varsonly. So a candidate could be arbitrarily strongly correlated with a forced term and appear in every model in the set. That inflates the variance of the forced term's estimate, which is frequently the term the analysis exists to estimate, and nothing in the output indicated it. A separate cutoff, with a much looser default thancov.cutoff's 0.28, because the two screens answer different questions.cov.cutoffdecides which predictors may appear together; this decides which predictor is so nearly a restatement of a forced term that fitting both is not informative. Set it to 1 to admit every predictor whatever its correlation with a forced term. **A variable inside abs='re'smooth is excluded from the screen.** A random-effect grouping factor is correlated with the predictors measured within it by construction: in the companion repository's case study 2,null.termsiss(Location,Site,bs='re')andStatusis nested inLocation, so their correlation is 1. That is the design of the study rather than collinearity to screen out, and droppingStatusthere would be wrong. The screen is for a forced term that competes with a candidate for the same variation. Correlations among thenull.termsvariables themselves are neither computed nor screened. Those terms are forced in by the user's decision, and dropping one is what must not happen.null.term.correlationsis returned whether or not anything is dropped, so the correlations can be inspected where no warning is raised; it isNULLwhere there is nothing to report. A suppliedcor.matrixis used for any forced term it names in either dimension, overriding the computed estimate for that term; the rest of the block is computed fromuse.dat, which is the ordinary case, a supplied matrix being indexed by predictor and a forced term not being one. Requiring the matrix to name the term would disable this screen for every caller who supplies one. Where the computation fails -- which is what a predictor of a classcheck_correlations()cannot classify causes -- the screen is skipped with a warning rather than the call stopping, so a caller relying on FSSgam_package#13 still gets their model set and is told their forced terms were not screened. **A pair a suppliedcor.matrixgives no value for is treated as not supplied, and computed fromuse.dat.** That isNAin both directions, orNAin the one direction a matrix naming the forced term in a single dimension has. Read as a correlation of zero, such a pair admitted the predictor to every candidate alongside the forced term -- the outcome this screen exists to prevent -- decided by a cell the user left empty rather than by a correlation, while the sameNAbetween two predictors stops the call (FSSgam_package#27). Where one direction gives a value, that value is used, unchanged. A forced term can be part supplied and part computed, the two being merged cell by cell rather than row by row (FSSgam_package#41). Where the correlation estimate is asymmetric, ascheck_non_linear_correlations()returns it, both directions are read and the larger is used -- what thecov.cutoffscreen already does. Reading one direction admitted a candidate that is a deterministic function of a forced term: measured on a squared forced term in the committed test,[forced, candidate]is 0.280 -- below the default cutoff -- while[candidate, forced]is 0.991. The smaller figure depends on the random draw and the test asserts only that it is below the cutoff, which is the property that matters. Each cell ofnull.term.correlationsis the value screened on rather than one direction of it; on the symmetric default path the two are equal.null.cov.cutoffis validated: it must be a single non-negative number. Unvalidated, anNAgave an internal "missing value where TRUE/FALSE needed" and a length-2 value was accepted silently. Where dropping predictors leaves fewer thanmax.predictors, the error says so and names them, rather than reporting only thatmax.predictorsexceeds the number of predictors.
Show all changes in 1.2.0Hide the rest of the changes in 1.2.0
- **Behaviour change:** a
test.fitproduced bymgcv::gamm()directly is rejected, with a message naming the remedy. Such a fit records no call, sostats::update()has nothing to re-evaluate and every candidate refit fails. The error it produced instead -- "need an object with call component" -- named neither the argument nor the remedy, and the message that followed advised the user to stop usinguGamm, which is what they would have had to use to succeed (FSSgam_package#34). The documentation is corrected with it.generate_model_set()'snull.termstext directed the user togammfor a correlation structure, its@detailscontrastsgamandgammat length, andfit_model_set()'sr2.typenamesgammamong the classes it reports for. All three now say that agammfit reaches this package only throughMuMIn::uGamm, which supplies the call that a baremgcv::gamm()fit lacks. - **Behaviour change:**
generate_model_set()rejects a predictor named twice withinpred.vars.cont,pred.vars.factorlinear.vars, naming it. Such a name produced a candidate holding it twice,ZONE+ZONE, together with two "no non-missing arguments to max; returning -Inf" warnings naming nothing:enumerate_candidate_models()deduplicates a candidate's terms before indexing the correlation matrix, so a candidate holding one term twice gives a 1x1 sub-matrix whose triangles are empty, andmax()of an empty vector returns-Inf, which is below anycov.cutoff(FSSgam_package#28). The warnings had a second cause, which rejecting the repeated name does not address: naming a predictor in bothpred.vars.contandlinear.vars, the documented idiom below, puts the name in the candidate pool twice and reaches the same empty triangle at anymax.predictorsof 2 or more. Both screens now test the sub-matrix through a helper that returnsFALSEfor an empty triangle rather than callingmax()on it, so no candidate set emits the warning. Which combinations survive is unchanged,-Infhaving been below every cutoff. A name appearing in bothpred.vars.factandpred.vars.contorlinear.varsis rejected too, as is a name repeated within the character form offactor.factor.interactionsorsmooth.smooth.interactions. That last is a third route to the same defect and the one the others miss:factor.factor.interactions = c("fa", "fa", "fb")built the interaction columnfa.I.fbtwice, souse.datgained two columns of that name and the candidate set gainedfa.I.fb+fa.I.fb. A name appearing in bothpred.vars.contandlinear.varsis **not** rejected: that is the documented way to fit a continuous predictor linearly,setdiff(pred.vars.cont, linear.vars)deciding which predictors get a smooth. - **Behaviour change:** a variable named in the character form of
factor.factor.interactionsorsmooth.smooth.interactionsmust be a predictor of the model set. Each argument was checked against the wrong set -- the first againstcolnames(use.dat), so any column was accepted, and the second againstrownames(cor.matrix), so what was accepted depended on whether acor.matrixwas supplied and what names it carried. A non-predictor named in either was screened againstcov.cutoffand contributed interaction terms, while appearing in no other candidate, inincluded.vars, or in the variable-inclusion columnsfit_model_set()returns (FSSgam_package#37). - **Behaviour change:** a factor predictor with fewer than two observed levels is rejected, naming it and its level count. Such a factor explains nothing, cannot be screened for collinearity, and produces an interaction column that is a copy of the other factor, so the model set holds the same model under two names. Levels declared but taken by no row are counted as absent (FSSgam_package#33).
- Bug fix:
check_correlations()andcheck_non_linear_correlations()now wrap theirlm()call intry(), as every other fit in both already was. It was the one unguarded fit in each, so a single-level factor stopped the whole call with "contrasts can be applied only to factors with 2 or more levels" instead of leaving that cellNA. Both are exported and callable directly, so the guard matters beyond thegenerate_model_set()path the check above covers (FSSgam_package#33). - **Behaviour change:** a hard coded factor interaction column whose generated name is already a column of
use.datis not created, and a warning names it.cbind()accepted the duplicate, and every later stage selects predictors by name:use.dat[, "a.I.b"]returned the first of the two, which is the user's own column, while the model formulas and the correlation matrix were built for the generated one. Nothing reported the collision. Declining rather than overwriting, because overwriting silently changes a predictor the user named (FSSgam_package#22). This is reached without contrivance: passing theused.dataof one call as theuse.datof the next presents every generated name as an existing column. Two generated names can also collide with each other, which is the same defect reached from inside rather than outside:(a, b.I.c)and(a.I.b, c)both paste toa.I.b.I.c, and the two columns are different variables. That is declined and warned about as well, though it is no longer reachable through the public API, the predictor name it requires being rejected by the check below. - **Behaviour change:** a predictor whose name contains
.by.,.te.,.t.,.I.,+or*is rejected, as is one namednull. Those strings separate the parts of a generated term name and are found withgrep(fixed = TRUE)over every term, so a predictor namedcatch.by.effort-- an ordinary variable name -- was parsed as an interaction. The candidate became~s(catch.by.effort) + s(catch, by = effort), which cannot be fitted, so the predictor vanished from the model set. The only indication was the-Infwarnings, which this release removes for unrelated reasons (FSSgam_package#39).+joins the terms of a candidate name and*writes a linear interaction, so either is parsed as more than one term in the same way.nullis the name given to the null model's own candidate, so a predictor of that name produced two candidates callednull:mod.formula[["null"]]returned the first, and the variable importance table matched the wrong row.factor.smooth.interactionsin its character form is validated alongside the other two interaction arguments, which it was not. This rejects the failure rather than fixing the parse. Making a term's structure explicit instead of recovering it from its name is a larger change, and the issue records what it would involve. One consequence is worth knowing: passing theused.dataof one call as theuse.datof the next presents generated names, which contain.I.by construction, so those columns must be dropped or renamed before they can be named as predictors. - Bug fix: a user-supplied
cor.matrixwith exactly one cell was silently discarded and recomputed fromuse.dat. A model set with a single predictor is the only case in which a supplied matrix is 1x1, andlength(cor.matrix) == 1was the test for "nothing supplied", which a 1x1 matrix also satisfies. The supplied value governed no screen and did not appear inpredictor.correlations, which is the opposite of the documented contract that a supplied matrix replaces the automatic estimate (FSSgam_package#26). The test is now on the default value rather than on length, in both places it was made --build_predictor_correlation_matrix()and thefactor_correlations()helper insideresolve_factor_interactions(), which had its own copy. It tests dimensionality rather than a list of accepted classes, so the S4 matrixMatrix::Matrix()returns is accepted, as it was before this argument was validated at all. Note thatMatrix::nearPD()is not such a case: it returns a list whosematcomponent is the matrix, and only that component was ever accepted. **Behaviour change:**cor.matrixis now validated, and a value that is neither a matrix, a data.frame, norNAis rejected naming its class. What happened to such a value before depended on its length, and neither outcome was right. A length-one value of any class -- a string, or a list holding a matrix -- satisfied the sentinel and was silently treated as nothing supplied, so the model set was built from a computed matrix as though the argument had not been given. A value of any other length fell through to the supplied branch and failed against the missing-predictor check, reporting predictors rather than the argument. Calls of the first kind used to run and now error. - **Behaviour change:** an
NAbetween two terms of a suppliedcor.matrixis now reported bygenerate_model_set(), naming the pairs, where it previously stopped the call withmissing value where TRUE/FALSE needed— naming neither the matrix, the argument, nor the pair (FSSgam_package#27). The report is made where each sub-matrix is formed, immediately before the screen takesmax(abs(.))of it, rather than at a single earlier point. Two earlier placements were tried and both were wrong, in opposite directions. Checking only inbuild_predictor_correlation_matrix()missed every pair screened before it,resolve_factor_interactions()running first. Checking a union of every name that might be screened then reported pairs that are not: a name given in the character form offactor.factor.interactionsis screened against the others in that argument and never againstpred.vars.cont. Reporting at the screening site covers exactly the pairs that are screened. **A consequence, and a departure from what the issue asked for.** The report covers exactly the pairs some screen compares, so it depends onmax.predictorsand on the interaction arguments. The issue asked for the report not to depend onmax.predictors; that would mean rejecting a matrix over a cell nothing reads, which is a false failure. AnNAis reported whenever it is read and not otherwise. Note that "read" is not the same as "in a candidate together". A.by.term is one term of a candidate but splits into two for the screen, so atmax.predictors = 1a continuous predictor and a factor are still compared; two continuous predictors are not. - Bug fix: the correlation matrix
resolve_factor_interactions()computes when nocor.matrixis supplied is now zero-filled, as the onebuild_predictor_correlation_matrix()computes already was. Without it a computed matrix reached the factor-factor screen withNAin it --check_correlations()returnsNAfor a pair involving a single-level factor (FSSgam_package#33) -- and the call stopped withmissing value where TRUE/FALSE needed(FSSgam_package#27). **Behaviour change, and a poor outcome that is better than the error it replaces.** AnNAbecoming zero means "uncorrelated", so a factor-factor pair that previously stopped the call is now admitted. Where theNAcame from a single-level factor the interaction column is a copy of the other factor:fa.I.constispaste(fa, "a"), sofaandfa.I.constare the same model under two names, and both enter the AICc table and the variable importance scores. That is not a good model set, and the real defect is that a single
The NEWS section is longer than shown here.
From NEWS.md in the release
Install
Health
ERRORtestsr-oldrel-macos-arm64, r-oldrel-macos-x86_64, r-release-macos-x86_64
r-oldrel-macos-arm64
Running ‘testthat.R’ [17s/18s]
Running the tests in ‘tests/testthat.R’ failed.
Complete output:
> # This file is part of the standard setup for testthat.
> # It is recommended that you do not modify it.
> #
> # Where should you do additional test configuration?
> # Learn more about the roles of various files in:
> # * https://r-pkgs.org/testing-design.html#sec-tests-files-overview
> # * https://testthat.r-lib.org/articles/special-files.html
>
> library(testthat)
> library(FSSgam)
>
> test_check("FSSgam")
Loading required package: nlme
This is mgcv 1.9-4. For overview type '?mgcv'.
Loading required package: gamm4
Loading required package: Matrix
Loading required package: lme4
Attaching package: 'lme4'
The following object is masked from 'package:nlme':
lmList
This is gamm4 0.3-0
Saving _problems/test-generate_model_set-658.R
[ FAIL 1 | WARN 0 | SKIP 13 | PASS 909 ]
══ Skipped tests (13) ═════════════════════════════
...[truncated]...
═══════════════════════════
• On CRAN (12): 'test-check_correlations.R:83:3',
'test-fit_model_set_parallel.R:16:3', 'test-fit_model_set_parallel.R:34:3',
'test-fit_model_set_parallel.R:54:3', 'test-fit_model_set_parallel.R:77:3',
'test-fit_model_set_parallel.R:110:3', 'test-fit_model_set_parallel.R:130:3',
'test-numerical-regression.R:81:1', 'test-numerical-regression.R:89:1',
'test-numerical-regression.R:102:1', 'test-numerical-regression.R:114:1',
'test-numerical-regression.R:136:1'
• set FSSGAM_TEST_PARALLEL=true to run the parallel tests (1):
'test-criterion.R:574:3'
══ Failed tests ════════════════════════════════════════════════════════════════
── Failure ('test-generate_model_set.R:657:3'): candidate model names do not depend on the collation locale ──
Expected `identical(...)` to be FALSE.
Differences:
`actual`: TRUE
`expected`: FALSE
[ FAIL 1 | WARN 0 | SKIP 13 | PASS 909 ]
Error:
! Test failures.
Execution haltedr-oldrel-macos-x86_64
Running ‘testthat.R’ [49s/67s]
Running the tests in ‘tests/testthat.R’ failed.
Complete output:
> # This file is part of the standard setup for testthat.
> # It is recommended that you do not modify it.
> #
> # Where should you do additional test configuration?
> # Learn more about the roles of various files in:
> # * https://r-pkgs.org/testing-design.html#sec-tests-files-overview
> # * https://testthat.r-lib.org/articles/special-files.html
>
> library(testthat)
> library(FSSgam)
>
> test_check("FSSgam")
Loading required package: nlme
This is mgcv 1.9-4. For overview type '?mgcv'.
Loading required package: gamm4
Loading required package: Matrix
Loading required package: lme4
Attaching package: 'lme4'
The following object is masked from 'package:nlme':
lmList
This is gamm4 0.3-0
Saving _problems/test-generate_model_set-658.R
[ FAIL 1 | WARN 0 | SKIP 13 | PASS 909 ]
══ Skipped tests (13) ═════════════════════════════
...[truncated]...
═══════════════════════════
• On CRAN (12): 'test-check_correlations.R:83:3',
'test-fit_model_set_parallel.R:16:3', 'test-fit_model_set_parallel.R:34:3',
'test-fit_model_set_parallel.R:54:3', 'test-fit_model_set_parallel.R:77:3',
'test-fit_model_set_parallel.R:110:3', 'test-fit_model_set_parallel.R:130:3',
'test-numerical-regression.R:81:1', 'test-numerical-regression.R:89:1',
'test-numerical-regression.R:102:1', 'test-numerical-regression.R:114:1',
'test-numerical-regression.R:136:1'
• set FSSGAM_TEST_PARALLEL=true to run the parallel tests (1):
'test-criterion.R:574:3'
══ Failed tests ════════════════════════════════════════════════════════════════
── Failure ('test-generate_model_set.R:657:3'): candidate model names do not depend on the collation locale ──
Expected `identical(...)` to be FALSE.
Differences:
`actual`: TRUE
`expected`: FALSE
[ FAIL 1 | WARN 0 | SKIP 13 | PASS 909 ]
Error:
! Test failures.
Execution haltedr-release-macos-x86_64
Running ‘testthat.R’ [49s/69s]
Running the tests in ‘tests/testthat.R’ failed.
Complete output:
> # This file is part of the standard setup for testthat.
> # It is recommended that you do not modify it.
> #
> # Where should you do additional test configuration?
> # Learn more about the roles of various files in:
> # * https://r-pkgs.org/testing-design.html#sec-tests-files-overview
> # * https://testthat.r-lib.org/articles/special-files.html
>
> library(testthat)
> library(FSSgam)
>
> test_check("FSSgam")
Loading required package: nlme
This is mgcv 1.9-4. For overview type '?mgcv'.
Loading required package: gamm4
Loading required package: Matrix
Loading required package: lme4
Attaching package: 'lme4'
The following object is masked from 'package:nlme':
lmList
This is gamm4 0.3-0
Saving _problems/test-generate_model_set-658.R
[ FAIL 1 | WARN 0 | SKIP 13 | PASS 909 ]
══ Skipped tests (13) ═════════════════════════════
...[truncated]...
═══════════════════════════
• On CRAN (12): 'test-check_correlations.R:83:3',
'test-fit_model_set_parallel.R:16:3', 'test-fit_model_set_parallel.R:34:3',
'test-fit_model_set_parallel.R:54:3', 'test-fit_model_set_parallel.R:77:3',
'test-fit_model_set_parallel.R:110:3', 'test-fit_model_set_parallel.R:130:3',
'test-numerical-regression.R:81:1', 'test-numerical-regression.R:89:1',
'test-numerical-regression.R:102:1', 'test-numerical-regression.R:114:1',
'test-numerical-regression.R:136:1'
• set FSSGAM_TEST_PARALLEL=true to run the parallel tests (1):
'test-criterion.R:574:3'
══ Failed tests ════════════════════════════════════════════════════════════════
── Failure ('test-generate_model_set.R:657:3'): candidate model names do not depend on the collation locale ──
Expected `identical(...)` to be FALSE.
Differences:
`actual`: TRUE
`expected`: FALSE
[ FAIL 1 | WARN 0 | SKIP 13 | PASS 909 ]
Error:
! Test failures.
Execution halted- ERROR10 OK, 3 ERRORNow
- ERROR2 OK, 1 ERROR2026-09-28
Documentation
- Help pages
- 17 (1 internal)includes a package overview page
- Examples that run
- 100%12 run in a plain check
- Exported functions with examples
- 100%
- Documented parameters
- 100%
- Return-value docs
- 100%
- Help pages citing references
- 6%
Downloads
Repository
- PRs merged (all time)
- 100%
- Median days to close, 50 most recently updated closed issues
- 4
- Median days to close, 50 most recently updated closed PRs
- 0
Releases over time
8 development-tooling and community-health practices detected across 5 families in the upstream repository
Checks run against github.com/beckyfisher/fssgam_package on 2026-10-21.
The R CMD check workflow runs on Linux, macOS and Windows, and on R-devel
GitHub Pages site last deployed 2026-09-29 · The repository has a site deploy workflow
pkgdown site last built 2026-09-29
Show all practicesHide 1 practice
This repository shows signs of AI coding tools.
- Claude Codefirst seen 2026-06-20Seen in the repository: CLAUDE.mdNamed in .Rbuildignore: CLAUDE.mdPull request it wrote: opened by a project memberCommits: at least 164 crediting it in the message
- Claude Opus 5117 commits · Aug to Sep 2026
- Claude Sonnet 4.627 commits · Jun 2026
- Claude Opus 4.82 commits · Jul 2026
Some of these counts are a minimum, because the search stopped before the oldest commits.
Dependencies
Code & Tests
Datasets
People & History
- 1.2.0Latest2026-09-28 · current release
- RR 4.6.0 released · 2026-04-24
Package metadata
- First published
- 2026-09-28
- Total releases
- 1 / 1 yrs
- License
- Apache License (== 2.0)
- Minimum R
- ≥ 4.4.0
- Bundled data
- 46 KB / 4 files
- Download size
- 208 KB
Cite
Cite this package
Run in R for the authors' preferred citation:
citation("FSSgam")This package has no citation file, so citation() returns this entry built from DESCRIPTION.
Cite the R Observatory
For a number measured here: a download total, a coverage figure, an archival date.
From data release v2026-10-23, which the citation names so these numbers can be found later. More on citing and the projects behind them.