Skip to content

Commit 279b72c

Browse files
committed
added a proper control function
1 parent ed5c73a commit 279b72c

File tree

7 files changed

+321
-300
lines changed

7 files changed

+321
-300
lines changed

NAMESPACE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ S3method(translate,rand_forest)
99
S3method(update,logistic_reg)
1010
S3method(update,rand_forest)
1111
export(fit)
12+
export(fit_control)
1213
export(logistic_reg)
1314
export(rand_forest)
1415
export(translate)

R/fit.R

Lines changed: 40 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,8 @@
3030
#' @param engine A character string for the software that should
3131
#' be used to fit the model. This is highly dependent on the type
3232
#' of model (e.g. linear regression, random forest, etc.).
33-
#' @param .control A named list with elements `verbosity` and
34-
#' `catch`. `verbosity` should be an integer where a value of zero
35-
#' indicates that no messages or output should be shown when
36-
#' packages are loaded or when the model is fit. A value of 1 means
37-
#' that package loading is quiet but model fits can produce output
38-
#' to the screen (depending on if they contain their own
39-
#' `verbose`-type argument). A value of 2 or more indicates that
40-
#' any output should be seen. `catch` is a logical where a value of
41-
#' `TRUE` will evaluate the model inside of `try(, silent = TRUE)`.
42-
#' If the model fails, an object is still returned (without an
43-
#' error) that inherits the class "try-error".
33+
#' @param control A named list with elements `verbosity` and
34+
#' `catch`. See [fit_control()].
4435
#' @param ... Not currently used; values passed here will be
4536
#' ignored. Other options required to fit the model should be
4637
#' passed using the `others` argument in the original model
@@ -115,26 +106,26 @@ fit.model_spec <-
115106
y = NULL,
116107
data = NULL,
117108
engine = object$engine,
118-
.control = list(verbosity = 1, catch = FALSE),
109+
control = fit_control(),
119110
...
120111
) {
121112
call_interface <-
122113
check_interface(formula, recipe, x, y, data, match.call(expand.dots = TRUE))
123114
object$engine <- engine
124115
object <- check_engine(object)
125-
.control <- check_control(.control)
116+
126117

127118
# sub in arguments to actual syntax for corresponding engine
128119
object <- translate(object, engine = object$engine)
129120
check_installs(object) # TODO rewrite with pkgman
130121
# TODO Should probably just load the namespace
131-
load_libs(object, .control$verbosity < 2)
122+
load_libs(object, control$verbosity < 2)
132123

133124
res <- switch(
134125
call_interface,
135-
formula = fit_formula(object, formula, data, .control = .control, ...),
136-
recipe = fit_recipe(object, recipe, data, .control = .control, ...),
137-
xy = fit_xy(object, x, y, .control = .control, ...),
126+
formula = fit_formula(object, formula, data, control = control, ...),
127+
recipe = fit_recipe(object, recipe, data, control = control, ...),
128+
xy = fit_xy(object, x, y, control = control, ...),
138129
stop("Wrong interface type")
139130
)
140131

@@ -144,7 +135,7 @@ fit.model_spec <-
144135
###################################################################
145136

146137
#' @importFrom stats as.formula
147-
fit_formula <- function(object, formula, data, engine = engine, .control, ...) {
138+
fit_formula <- function(object, formula, data, engine = engine, control, ...) {
148139
opts <- quos(...)
149140
# Look up the model's interface (e.g. formula, recipes, etc)
150141
# and delagate to the connector functions (`formula_to_recipe` etc)
@@ -155,13 +146,13 @@ fit_formula <- function(object, formula, data, engine = engine, .control, ...) {
155146
res <-
156147
eval_mod(
157148
fit_expr,
158-
capture = .control$verbosity == 0,
159-
catch = .control$catch,
149+
capture = control$verbosity == 0,
150+
catch = control$catch,
160151
env = current_env()
161152
)
162153
} else {
163154
if(object$method$interface %in% c("data.frame", "matrix")) {
164-
res <- formula_to_xy(object = object, formula = formula, data = data, .control)
155+
res <- formula_to_xy(object = object, formula = formula, data = data, control)
165156
} else {
166157
stop("I don't know about the ",
167158
object$method$interface, " interface.",
@@ -171,13 +162,13 @@ fit_formula <- function(object, formula, data, engine = engine, .control, ...) {
171162
res
172163
}
173164

174-
fit_xy <- function(object, x, y, .control, ...) {
165+
fit_xy <- function(object, x, y, control, ...) {
175166
opts <- quos(...)
176167

177168
# Look up the model's interface (e.g. formula, recipes, etc)
178169
# and delegate to the connector functions (`xy_to_formula` etc)
179170
if(object$method$interface == "formula") {
180-
res <- xy_to_formula(object = object, x = x, y = y, .control)
171+
res <- xy_to_formula(object = object, x = x, y = y, control)
181172
} else {
182173
if(object$method$interface %in% c("data.frame", "matrix")) {
183174
fit_expr <- object$method$fit_call
@@ -186,9 +177,9 @@ fit_xy <- function(object, x, y, .control, ...) {
186177
res <-
187178
eval_mod(
188179
fit_expr,
189-
capture = .control$verbosity == 0,
190-
catch = .control$catch,
191-
env = current_enf()
180+
capture = control$verbosity == 0,
181+
catch = control$catch,
182+
env = current_env()
192183
)
193184
} else {
194185
stop("I don't know about the ",
@@ -199,16 +190,16 @@ fit_xy <- function(object, x, y, .control, ...) {
199190
res
200191
}
201192

202-
fit_recipe <- function(object, recipe, data, .control, ...) {
193+
fit_recipe <- function(object, recipe, data, control, ...) {
203194
opts <- quos(...)
204195

205196
# Look up the model's interface (e.g. formula, recipes, etc)
206197
# and delegate to the connector functions (`recipe_to_formula` etc)
207198
if(object$method$interface == "formula") {
208-
res <- recipe_to_formula(object = object, recipe = recipe, data = data, .control)
199+
res <- recipe_to_formula(object = object, recipe = recipe, data = data, control)
209200
} else {
210201
if(object$method$interface %in% c("data.frame", "matrix")) {
211-
res <- recipe_to_xy(object = object, recipe = recipe, data = data, .control)
202+
res <- recipe_to_xy(object = object, recipe = recipe, data = data, control)
212203
} else {
213204
stop("I don't know about the ",
214205
object$method$interface, " interface.",
@@ -221,7 +212,7 @@ fit_recipe <- function(object, recipe, data, .control, ...) {
221212

222213

223214
#placeholder
224-
fit_spark <- function(object, remote, engine = engine, .control, ...) {
215+
fit_spark <- function(object, remote, engine = engine, control, ...) {
225216
NULL
226217
}
227218

@@ -231,7 +222,7 @@ fit_spark <- function(object, remote, engine = engine, .control, ...) {
231222

232223
###################################################################
233224

234-
formula_to_recipe <- function(object, formula, data, .control) {
225+
formula_to_recipe <- function(object, formula, data, control) {
235226
# execute the formula
236227
# extract terms _and roles_
237228
# put into recipe
@@ -243,7 +234,7 @@ formula_to_recipe <- function(object, formula, data, .control) {
243234
# `requires_dummies`
244235

245236
#' @importFrom stats model.frame model.response terms
246-
formula_to_xy <- function(object, formula, data, .control) {
237+
formula_to_xy <- function(object, formula, data, control) {
247238
# Q: how do we fill in the other standard things here (subset, contrasts etc)?
248239
# Q: add a "matrix" option here and invoke model.matrix
249240
x <- stats::model.frame(formula, data)
@@ -260,19 +251,19 @@ formula_to_xy <- function(object, formula, data, .control) {
260251

261252
eval_mod(
262253
object$method$fit_call,
263-
capture = .control$verbosity == 0,
264-
catch = .control$catch,
254+
capture = control$verbosity == 0,
255+
catch = control$catch,
265256
env = current_env()
266257
)
267258
}
268259

269260
###################################################################
270261

271262
#' @importFrom recipes prep juice all_predictors all_outcomes
272-
recipe_to_formula <- function(object, recipe, data, .control) {
263+
recipe_to_formula <- function(object, recipe, data, control) {
273264
# TODO case weights
274265
recipe <-
275-
prep(recipe, training = data, retain = TRUE, verbose = .control$verbosity > 1)
266+
prep(recipe, training = data, retain = TRUE, verbose = control$verbosity > 1)
276267
dat <- juice(recipe, all_predictors(), all_outcomes())
277268
dat <- as.data.frame(dat)
278269

@@ -287,16 +278,16 @@ recipe_to_formula <- function(object, recipe, data, .control) {
287278
fit_expr$data <- quote(dat)
288279
eval_mod(
289280
fit_expr,
290-
capture = .control$verbosity == 0,
291-
catch = .control$catch,
281+
capture = control$verbosity == 0,
282+
catch = control$catch,
292283
env = current_env()
293284
)
294285
}
295286

296-
recipe_to_xy <- function(object, recipe, data, .control) {
287+
recipe_to_xy <- function(object, recipe, data, control) {
297288
# TODO case weights
298289
recipe <-
299-
prep(recipe, training = data, retain = TRUE, verbose = .control$verbosity > 1)
290+
prep(recipe, training = data, retain = TRUE, verbose = control$verbosity > 1)
300291

301292
x <- juice(recipe, all_predictors())
302293
x <- as.data.frame(x)
@@ -313,15 +304,15 @@ recipe_to_xy <- function(object, recipe, data, .control) {
313304

314305
eval_mod(
315306
fit_expr,
316-
capture = .control$verbosity == 0,
317-
catch = .control$catch,
307+
capture = control$verbosity == 0,
308+
catch = control$catch,
318309
env = current_env()
319310
)
320311
}
321312

322313
###################################################################
323314

324-
xy_to_formula <- function(object, x, y, .control) {
315+
xy_to_formula <- function(object, x, y, control) {
325316
if(!is.data.frame(x))
326317
x <- as.data.frame(x)
327318
x$.y <- y
@@ -331,7 +322,7 @@ xy_to_formula <- function(object, x, y, .control) {
331322
eval_tidy(fit_expr, env = current_env())
332323
}
333324

334-
xy_to_recipe <- function(object, x, y, .control) {
325+
xy_to_recipe <- function(object, x, y, control) {
335326

336327
}
337328

@@ -359,9 +350,9 @@ eval_mod <- function(e, capture = FALSE, catch = FALSE, ...) {
359350

360351
check_control <- function(x) {
361352
if (!is.list(x))
362-
stop(".control should be a named list.", call. = FALSE)
353+
stop("control should be a named list.", call. = FALSE)
363354
if (!isTRUE(all.equal(sort(names(x)), c("catch", "verbosity"))))
364-
stop(".control should be a named list with elements 'verbosity' and 'catch'.",
355+
stop("control should be a named list with elements 'verbosity' and 'catch'.",
365356
call. = FALSE)
366357
# based on ?is.integer
367358
int_check <- function(x, tol = .Machine$double.eps^0.5) abs(x - round(x)) < tol
@@ -404,9 +395,9 @@ check_interface <- function(formula, recipe, x, y, data, cl) {
404395
inher(formula, "formula", cl)
405396
inher(recipe, "recipe", cl)
406397
inher(x, c("data.frame", "matrix"), cl)
407-
# `y` can be a vector (which is not a class)
398+
# `y` can be a vector (which is not a class), or a factor (which is not a vector)
408399
if(!is.null(y) && !is.vector(y))
409-
inher(y, c("data.frame", "matrix"), cl)
400+
inher(y, c("data.frame", "matrix", "factor"), cl)
410401
inher(data, c("data.frame", "matrix"), cl)
411402

412403
x_interface <- !is.null(x) & !is.null(y)
@@ -424,24 +415,6 @@ check_interface <- function(formula, recipe, x, y, data, cl) {
424415
stop("Error in checking the interface")
425416
}
426417

427-
# some test cases
428-
# rec <- recipe(~ ., data = iris)
429-
# f <- y ~ x
430-
#
431-
# foo <-
432-
# function(object, formula = NULL recipe = NULL, x = NULL, y = NULL, data = NULL)
433-
# check_interface(formula, recipe, x, y, data, match.call(expand.dots = TRUE))
434-
#
435-
# foo(NULL, formula = f, data = iris)
436-
# foo(NULL, recipe = rec, data = iris)
437-
# foo(NULL, x = iris, y = iris)
438-
# foo(NULL, f, data = iris)
439-
# foo(NULL, formula = f, data = iris, y = iris)
440-
#
441-
# foo(NULL, rec, data = iris)
442-
# foo(NULL, iris, y = iris)
443-
# foo(NULL, data = iris)
444-
# foo(NULL, x = iris, data = iris)
445-
# foo(NULL, f, x = iris, y = iris, data = iris)
418+
446419

447420

R/fit_control.R

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#' Control the fit function
2+
#'
3+
#' Options can be passed to the [fit()] function that control the output and
4+
#' computations
5+
#'
6+
#' @param verbosity An integer where a value of zero indicates
7+
#' that no messages or output should be shown when packages are
8+
#' loaded or when the model is fit. A value of 1 means that package
9+
#' loading is quiet but model fits can produce output to the screen
10+
#' (depending on if they contain their own `verbose`-type
11+
#' argument). A value of 2 or more indicates that any output should
12+
#' be seen.
13+
#' @param catch A logical where a value of `TRUE` will evaluate
14+
#' the model inside of `try(, silent = TRUE)`. If the model fails,
15+
#' an object is still returned (without an error) that inherits the
16+
#' class "try-error".
17+
#' @return A named list with the results of the function call
18+
#' @export
19+
#'
20+
21+
fit_control <- function(verbosity = 1L, catch = FALSE) {
22+
res <- list(verbosity = verbosity, catch = catch)
23+
res <- check_control(res)
24+
res
25+
}

man/fit.Rd

Lines changed: 3 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/fit_control.Rd

Lines changed: 29 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)