Reputation: 35240
I'd like to define a wrapper class that will encapsulate an actual model, and let the user call predict()
with either new data frames or a model matrix:
raw_model <- ...
model <- Model(raw_model)
X <- matrix(...)
predict(model, X)
df <- data.frame(...)
predict(model, df)
I thought it would simply be a matter of defining two methods for predict()
, dispatching on the types of the first two arguments:
library(methods)
Model <- setClass("Model", slots = "model")
setMethod("predict", signature("Model", "matrix"),
function(object, newdata, ...) {
stats::predict(object@model, newdata)
})
setMethod("predict", signature("Model", "data.frame"),
function(object, newdata, ...) {
matrix <- model.matrix(newdata) # or something like that
stats::predict(object@model, matrix)
})
However, both calls to setMethod
fail with
Error in matchSignature(signature, fdef) :
more elements in the method signature (2) than in the generic signature (1) for function ‘predict’
I understand that an S4 generic is created from the S3 generic predict
, whose signature takes just one named argument object
, but is there a way to have the S4 methods dispatch on more than just that first argument?
Upvotes: 0
Views: 283
Reputation: 1654
You can make S4 generics dispatch on more than one argument, but you cannot (currently) dispatch on a named argument and ...
. This is the problem with predict — the only named argument is object
.
You can still achieve what you want though, by defining your own generic "one level down" along the lines of
predict2 <- function(model,newdata){stats::predict(model,newdata)}
setGeneric("predict2",signature=c("model","newdata"))
setMethod(
"predict2",
signature=c("Model","data.frame"),
definition=function(model,newdata){
matrix <- model.matrix(newdata) # or something like that
stats::predict(object@model, matrix)
}
)
Now you modify predict.Model
(and the S4 method for predict
with the signature model="Model"
) to call predict2(model,newdata)
.
Upvotes: 1