I love do.call
. I love being able to store function arguments in a list and then splatting them to a given function.
For example, I often find myself using this pattern to fit a list of different predictive models, with some shared and some unique parameters for each model:
library(caret)
global_args <- list(
x=iris[,1:3],
y=iris[,4],
trControl=trainControl(
method='cv',
number=2,
returnResamp='final',
)
)
global_args$trControl$index <- createFolds(
global_args$y,
global_args$trControl$number
)
model_specific_args <- list(
'lm' = list(method='lm', tuneLength=1),
'nn' = list(method='nnet', tuneLength=3, trace=FALSE),
'gbm' = list(
method='gbm',
verbose=FALSE,
tuneGrid=expand.grid(
n.trees=1:100,
interaction.depth=c(2, 3),
shrinkage=c(.1, .01)
)
)
)
list_of_models <- lapply(model_specific_args, function(args){
return(do.call(train, c(global_args, args), quote=TRUE))
})
resamps <- resamples(list_of_models)
dotplot(resamps, metric='RMSE')
global_args
contains arguments that are the same for all of the models, and model_specific_args
contains lists of model-specific arguments. I loop over model_specific_args
, concatenate each element with global_args
, and then use do.call
to pass the final argument list to the model fitting function.
While this code is visually elegant, its performance is terrible: do.call
literally serializes the entire x dataset as text and then passes it to the model fitting function. If x is a few GB of data this uses an insane amount of RAM and usually fails.
print(list_of_models[[1]]$call)
Is there anyone way to pass a list of arguments to a function in R, without using do.call
or call
?
rbind.fill
orReduce
are appropriate here. I'm not trying to combinedata.frames
, I'm trying to pass lists of arguments to a function. – Whitquote=TRUE
helps a little, butdo.call
is still serializing the entire data set before passing it totrain
. – Whit