Create a multimodel object
multimodel.RdA multimodel combines several models with identical response in one object.
There are two ways to create a multimodel:
multimodel(x, ...)takes an object of class “model” or a fitted model as its inputxand generates a number of variations of this model, with one or several parameters varying according to the specification in “...”.c.model(...)andc.multimodel(...)take a number ofmodels ormultimodels as their “...” arguments and combine them in an object of class “multimodel”.
Usage
multimodel(x, ...)
# S3 method for model
multimodel(
x,
...,
prefix = label(x),
expand = TRUE,
max_n_model = getOption("expand_max_model"),
param = TRUE,
simplify = TRUE
)
# S3 method for default
multimodel(
x,
...,
prefix = "model",
expand = TRUE,
param = TRUE,
simplify = TRUE
)
# S3 method for multimodel
multimodel(x, ...)
# S3 method for multimodel
print(
x,
what = c("class", "formula", "data", "weights", "call", "cv_info"),
abbreviate = TRUE,
n = getOption("print_max_model"),
param = TRUE,
width = getOption("width"),
...
)
# S3 method for model
c(..., param = TRUE, simplify = TRUE)
# S3 method for multimodel
c(..., param = TRUE, simplify = TRUE)Arguments
- x
An object of class “model” or a fitted model.
- ...
In
multimodel(): named parameters to be expanded; inc.(multi)model: one or several arguments of class “model” or “multimodel”.- prefix
Prefix to use for the model
label.- expand
Logical: Expand the “...” arguments (default) or join them element-wise? If
expand=TRUE, the vectors in “...” will be expanded, the number of models will equal the product of the lengths of the “...” arguments; otherwise, all “...” arguments must have equal lengths, and the number of models will be equal to their common length.- max_n_model
Maximal number of models that will be included. If the number of specified models is greater than
max_n_model, a subset will be selected at random.- param
Logical: Keep or print parameter table?
- simplify
Logical: Simplify a
multimodelcomprising only one model to amodel?- what
Which elements of the multimodel should be printed? See
print.model.- abbreviate
Logical. If
TRUE(the default), long formulas and calls are printed in abbreviated mode, such that they usually fit on 4 or fewer output lines; otherwise they are printed entirely, no matter how long they are.- n
Integer: Model details are printed for first
nmodels.- width
Integer: Width of printed output.
Value
multimodel() and c.(multi)model() both return an object of class “multimodel”, this is
a list with the following elements:
models: A list of the
modelobjects.param: The table of the parameter values resulting from
multimodel(). Only included if there are any varying parameters and ifparam = TRUE
Details
multimodel() is a (S3-)generic function.
The core method is multimodel.model(), other methods are essentially wrappers to the core method and are described in the section “Methods” below.
The vectors in “...” are expanded or joined, according to the argument expand.
Extraction of values for the single calls is done with “[[” rather than “[”.
multimodel() executes update.model() repeatedly, such that the helper functions absent(),
unchanged() and null() can be used in a call to multimodel() exactly as within update.model().
If formula is one of the arguments in the “...” and some formula has a dot, it will be used to update the original model formula.
Enclose a formula in I() in order to replace the original formula instead.
See the example below and update.model.
The output of multimodel(...) by default includes a parameter table as its element param, containing the values
of the parameters specified in the “...”.
This is a data.frame having an additional class “param_table”.
c.(multi)model: A call to c(...) can include both “model” and “multimodel” objects
(but no fitted models) in its “...”.
Using models() instead of these c-methods is more flexible in that it also accepts fitted models.
“model”s specified as named arguments in the call will have their argument name taken as their label.
Argument names for multimodels are ignored -- the labels already present in the multimodel will be used instead.
Duplicate labels in the output will be adjusted using make.unique().
Methods
multimodel.model()is described in the “Details” section.The default method expects a fitted model as its
xand executesx %>% model %>% multimodel(...).multimodel.multimodel()returns its inputxunchanged.
See also
label, extract_model, subset, sort_models,
update.model, expand_formula.
models() is a more general version of c.(multi)model also accepting fitted models.
Examples
m1 <- model(lm(Sepal.Length ~ 1 , iris), label = "intercept")
m2 <- model(lm(Sepal.Length ~ . , iris), label = "linear")
m3 <- model(lm(Sepal.Length ~ .^2 , iris), label = "order2") # without Species on rhs
# Combine models with c(...)
mm1 <- c(m1, m2, m3)
mm1
#> --- A “multimodel” object containing 3 models ---
#>
#> ‘intercept’:
#> model class: lm
#> formula: Sepal.Length ~ 1
#> data: data.frame [150 x 5],
#> input as: ‘data = iris’
#> call: lm(formula = Sepal.Length ~ 1, data = data)
#>
#> ‘linear’:
#> model class: lm
#> formula: Sepal.Length ~ Sepal.Width + Petal.Length + Petal.Width +
#> Species
#> data: data.frame [150 x 5],
#> input as: ‘data = iris’
#> call: lm(formula = Sepal.Length ~ ., data = data)
#>
#> ‘order2’:
#> model class: lm
#> formula: Sepal.Length ~ Sepal.Width + Petal.Length + Petal.Width +
#> Species + Sepal.Width:Petal.Length + Sepal.Width:Petal.Width +
#> Sepal.Width:Species + Petal.Length:Petal.Width +
#> Petal.Length:Species + Petal.Width:Species
#> data: data.frame [150 x 5],
#> input as: ‘data = iris’
#> call: lm(formula = Sepal.Length ~ .^2, data = data)
# Specify elements to print:
print(mm1, what = c("class", "data"))
#> --- A “multimodel” object containing 3 models ---
#>
#> ‘intercept’:
#> model class: lm
#> data: data.frame [150 x 5],
#> input as: ‘data = iris’
#>
#> ‘linear’:
#> model class: lm
#> data: data.frame [150 x 5],
#> input as: ‘data = iris’
#>
#> ‘order2’:
#> model class: lm
#> data: data.frame [150 x 5],
#> input as: ‘data = iris’
print(mm1, what = TRUE)
#> --- A “multimodel” object containing 3 models ---
#>
#> ‘intercept’:
#> label: intercept
#> model class: lm
#> formula: Sepal.Length ~ 1
#> data: data.frame [150 x 5],
#> input as: ‘data = iris’
#> response_type: continuous
#> response: Sepal.Length
#> call: lm(formula = Sepal.Length ~ 1, data = data)
#> predict_function: function (object, ...)
#> fit: Object of class ‘lm’
#>
#> ‘linear’:
#> label: linear
#> model class: lm
#> formula: Sepal.Length ~ Sepal.Width + Petal.Length +
#> Petal.Width + Species
#> data: data.frame [150 x 5],
#> input as: ‘data = iris’
#> response_type: continuous
#> response: Sepal.Length
#> call: lm(formula = Sepal.Length ~ ., data = data)
#> predict_function: function (object, ...)
#> fit: Object of class ‘lm’
#>
#> ‘order2’:
#> label: order2
#> model class: lm
#> formula: Sepal.Length ~ Sepal.Width + Petal.Length +
#> Petal.Width + Species + Sepal.Width:Petal.Length +
#> Sepal.Width:Petal.Width + Sepal.Width:Species +
#> ... [formula cut off - 10 terms on rhs]
#> data: data.frame [150 x 5],
#> input as: ‘data = iris’
#> response_type: continuous
#> response: Sepal.Length
#> call: lm(formula = Sepal.Length ~ .^2, data = data)
#> predict_function: function (object, ...)
#> fit: Object of class ‘lm’
# Expand a model with multimodel(): random forests with different max.depth:
if (require(ranger)){
mod_ranger <- model(ranger(Sepal.Length ~ ., iris), label = "ranger")
multimodel(mod_ranger, max.depth = 1:10)
}
#> --- A “multimodel” object containing 10 models ---
#>
#> ‘ranger1’:
#> model class: ranger
#> formula: Sepal.Length ~ Sepal.Width + Petal.Length + Petal.Width +
#> Species
#> data: data.frame [150 x 5],
#> input as: ‘data = iris’
#> call: ranger(formula = Sepal.Length ~ ., data = data,
#> max.depth = 1L)
#>
#> ‘ranger2’:
#> model class: ranger
#> formula: Sepal.Length ~ Sepal.Width + Petal.Length + Petal.Width +
#> Species
#> data: data.frame [150 x 5],
#> input as: ‘data = iris’
#> call: ranger(formula = Sepal.Length ~ ., data = data,
#> max.depth = 2L)
#>
#> ‘ranger3’:
#> model class: ranger
#> formula: Sepal.Length ~ Sepal.Width + Petal.Length + Petal.Width +
#> Species
#> data: data.frame [150 x 5],
#> input as: ‘data = iris’
#> call: ranger(formula = Sepal.Length ~ ., data = data,
#> max.depth = 3L)
#>
#> and 7 models more, labelled:
#> ‘ranger4’, ‘ranger5’, ‘ranger6’, ‘ranger7’, ‘ranger8’,
#> ‘ranger9’, ‘ranger10’
#>
#>
#> Parameter table:
#> max.depth
#> ranger1 1
#> ranger2 2
#> ranger3 3
#> ... 7 rows omitted (nrow=10)
#' # Expand a model with multimodel(...)
# Joining models with three formulas may not give the expected result:
mm2 <- multimodel(m1, formula = list(Sepal.Length ~ 1, Sepal.Length ~ ., Sepal.Length ~ .^2))
mm2
#> --- A “multimodel” object containing 3 models ---
#>
#> ‘intercept1’:
#> model class: lm
#> formula: Sepal.Length ~ 1
#> data: data.frame [150 x 5],
#> input as: ‘data = iris’
#> call: lm(formula = Sepal.Length ~ 1, data = data)
#>
#> ‘intercept2’:
#> model class: lm
#> formula: Sepal.Length ~ 1
#> data: data.frame [150 x 5],
#> input as: ‘data = iris’
#> call: lm(formula = Sepal.Length ~ 1, data = data)
#>
#> ‘intercept3’:
#> model class: lm
#> formula: Sepal.Length ~ 1
#> data: data.frame [150 x 5],
#> input as: ‘data = iris’
#> call: lm(formula = Sepal.Length ~ 1, data = data)
#>
#> Parameter table:
#> formula
#> intercept1 Sepal.Length ~ 1
#> intercept2 Sepal.Length ~ .
#> intercept3 Sepal.Length ~ .^2
# The reason is that the formulas in the call above are used to *update* the existing one.
# To *replace* the formula, use `I()` as in the call below:
mm3 <- multimodel(m1, formula = list(Sepal.Length ~ 1, I(Sepal.Length ~ .), I(Sepal.Length ~ .^2)))
mm3
#> --- A “multimodel” object containing 3 models ---
#>
#> ‘intercept1’:
#> model class: lm
#> formula: Sepal.Length ~ 1
#> data: data.frame [150 x 5],
#> input as: ‘data = iris’
#> call: lm(formula = Sepal.Length ~ 1, data = data)
#>
#> ‘intercept2’:
#> model class: lm
#> formula: Sepal.Length ~ Sepal.Width + Petal.Length + Petal.Width +
#> Species
#> data: data.frame [150 x 5],
#> input as: ‘data = iris’
#> call: lm(formula = Sepal.Length ~ ., data = data)
#>
#> ‘intercept3’:
#> model class: lm
#> formula: Sepal.Length ~ Sepal.Width + Petal.Length + Petal.Width +
#> Species + Sepal.Width:Petal.Length + Sepal.Width:Petal.Width +
#> Sepal.Width:Species + Petal.Length:Petal.Width +
#> Petal.Length:Species + Petal.Width:Species
#> data: data.frame [150 x 5],
#> input as: ‘data = iris’
#> call: lm(formula = Sepal.Length ~ .^2, data = data)
#>
#> Parameter table:
#> formula
#> intercept1 Sepal.Length ~ 1
#> intercept2 Sepal.Length ~ .
#> intercept3 Sepal.Length ~ .^2
# Also note the difference in the printed outputs of mm1 and mm2:
# The parameter table only contains parameters that were passed as '...' in multimodel().
# Three ways to attribute labels to models:
# 1) Use named arguments in c.model():
c(constant = m1, linear = m2, order2 = m3)
#> --- A “multimodel” object containing 3 models ---
#>
#> ‘constant’:
#> model class: lm
#> formula: Sepal.Length ~ 1
#> data: data.frame [150 x 5],
#> input as: ‘data = iris’
#> call: lm(formula = Sepal.Length ~ 1, data = data)
#>
#> ‘linear’:
#> model class: lm
#> formula: Sepal.Length ~ Sepal.Width + Petal.Length + Petal.Width +
#> Species
#> data: data.frame [150 x 5],
#> input as: ‘data = iris’
#> call: lm(formula = Sepal.Length ~ ., data = data)
#>
#> ‘order2’:
#> model class: lm
#> formula: Sepal.Length ~ Sepal.Width + Petal.Length + Petal.Width +
#> Species + Sepal.Width:Petal.Length + Sepal.Width:Petal.Width +
#> Sepal.Width:Species + Petal.Length:Petal.Width +
#> Petal.Length:Species + Petal.Width:Species
#> data: data.frame [150 x 5],
#> input as: ‘data = iris’
#> call: lm(formula = Sepal.Length ~ .^2, data = data)
# 2) replacement function label<-
mm1_lbls <- mm1
label(mm1_lbls) <- c("m1", "m2", "m3")
mm1_lbls
#> --- A “multimodel” object containing 3 models ---
#>
#> ‘m1’:
#> model class: lm
#> formula: Sepal.Length ~ 1
#> data: data.frame [150 x 5],
#> input as: ‘data = iris’
#> call: lm(formula = Sepal.Length ~ 1, data = data)
#>
#> ‘m2’:
#> model class: lm
#> formula: Sepal.Length ~ Sepal.Width + Petal.Length + Petal.Width +
#> Species
#> data: data.frame [150 x 5],
#> input as: ‘data = iris’
#> call: lm(formula = Sepal.Length ~ ., data = data)
#>
#> ‘m3’:
#> model class: lm
#> formula: Sepal.Length ~ Sepal.Width + Petal.Length + Petal.Width +
#> Species + Sepal.Width:Petal.Length + Sepal.Width:Petal.Width +
#> Sepal.Width:Species + Petal.Length:Petal.Width +
#> Petal.Length:Species + Petal.Width:Species
#> data: data.frame [150 x 5],
#> input as: ‘data = iris’
#> call: lm(formula = Sepal.Length ~ .^2, data = data)
# 3) set_labels()
set_label(mm1, c("m1", "m2", "m3"))
#> --- A “multimodel” object containing 3 models ---
#>
#> ‘m1’:
#> model class: lm
#> formula: Sepal.Length ~ 1
#> data: data.frame [150 x 5],
#> input as: ‘data = iris’
#> call: lm(formula = Sepal.Length ~ 1, data = data)
#>
#> ‘m2’:
#> model class: lm
#> formula: Sepal.Length ~ Sepal.Width + Petal.Length + Petal.Width +
#> Species
#> data: data.frame [150 x 5],
#> input as: ‘data = iris’
#> call: lm(formula = Sepal.Length ~ ., data = data)
#>
#> ‘m3’:
#> model class: lm
#> formula: Sepal.Length ~ Sepal.Width + Petal.Length + Petal.Width +
#> Species + Sepal.Width:Petal.Length + Sepal.Width:Petal.Width +
#> Sepal.Width:Species + Petal.Length:Petal.Width +
#> Petal.Length:Species + Petal.Width:Species
#> data: data.frame [150 x 5],
#> input as: ‘data = iris’
#> call: lm(formula = Sepal.Length ~ .^2, data = data)
# Combine mm1 and mm3:
print(c(mm1, mm3), what = "formula", n = 6)
#> --- A “multimodel” object containing 6 models ---
#>
#> ‘intercept’:
#> formula: Sepal.Length ~ 1
#>
#> ‘linear’:
#> formula: Sepal.Length ~ Sepal.Width + Petal.Length + Petal.Width +
#> Species
#>
#> ‘order2’:
#> formula: Sepal.Length ~ Sepal.Width + Petal.Length + Petal.Width +
#> Species + Sepal.Width:Petal.Length + Sepal.Width:Petal.Width +
#> Sepal.Width:Species + Petal.Length:Petal.Width +
#> Petal.Length:Species + Petal.Width:Species
#>
#> ‘intercept1’:
#> formula: Sepal.Length ~ 1
#>
#> ‘intercept2’:
#> formula: Sepal.Length ~ Sepal.Width + Petal.Length + Petal.Width +
#> Species
#>
#> ‘intercept3’:
#> formula: Sepal.Length ~ Sepal.Width + Petal.Length + Petal.Width +
#> Species + Sepal.Width:Petal.Length + Sepal.Width:Petal.Width +
#> Sepal.Width:Species + Petal.Length:Petal.Width +
#> Petal.Length:Species + Petal.Width:Species
#>
#> Parameter table:
#> formula
#> intercept <unknown>
#> linear <unknown>
#> order2 <unknown>
#> intercept1 Sepal.Length ~ 1
#> intercept2 Sepal.Length ~ .
#> intercept3 Sepal.Length ~ .^2
# Unweighted and weighted model:
w <- runif(150)
mm3 <- multimodel(m1, weights = list(absent(), w))
label(mm3) <- c("unweighted", "weighted")
mm3
#> --- A “multimodel” object containing 2 models ---
#>
#> ‘unweighted’:
#> model class: lm
#> formula: Sepal.Length ~ 1
#> data: data.frame [150 x 5],
#> input as: ‘data = iris’
#> call: lm(formula = Sepal.Length ~ 1, data = data)
#>
#> ‘weighted’:
#> model class: lm
#> formula: Sepal.Length ~ 1
#> data: data.frame [150 x 5],
#> input as: ‘data = iris’
#> weights: numeric [150], input as: ‘weights = w’
#> call: lm(formula = Sepal.Length ~ 1, data = data, weights = weights)
#>
#> Parameter table:
#> weights
#> unweighted <absent>
#> weighted <num>[150]