I always had problems understanding the documentation of how the S3 method is called, and this time it bit me off.
I apologize for asking more than one question, but they are all closely related. Deep in the middle of a complex set of functions, I create many glmnet , particularly logistic ones. Now the glmnet documentation indicates its return value to have both the "glmnet" and (for logistic regression) "lognet" classes. In fact, they are listed in that order.
However, looking at the end of the glmnet implementation, coarser after calling (the internal function) lognet , which sets the fit class to "lognet", I see this line of code just before the return (of the fit variable):
class(fit) = c(class(fit), "glmnet")
From this I would conclude that the class order is actually "lognet", "glmnet".
Unfortunately, I had what was (for example, a document):
> class(myfit) [1] "glmnet" "lognet"
The problem with this is how S3 methods are sent for it, in particular predict . Here is the code for predict.lognet :
function (object, newx, s = NULL, type = c("link", "response", "coefficients", "class", "nonzero"), exact = FALSE, offset, ...) { type = match.arg(type) nfit = NextMethod("predict")
I added a comment to explain my reasoning. Now, when I call the forecast on this myfit with the new datamatrix mydata and type="response" , like this:
predict(myfit, newx=mydata, type="response")
I do not, according to the documentation, do predictable probabilities, but linear combinations that are the result of a direct call to predict.glmnet .
I tried to reorder the classes, for example:
orgclass<-class(myfit) class(myfit)<-rev(orgclass)
And then repeat the predictive call: thatโs it: it works! I get the probabilities.
So here are some questions:
- Am I right to โlearnโ that S3 Methods are sent in the order that classes appear?
- Do I correctly assume that the code in
glmnet will lead to the wrong order for dispatching predict correctly? - There is nothing in my code that manipulates classes explicitly, as far as I know. What could lead to change?
For completeness: here is an example of code to play with (as I am doing now):
library(glmnet) y<-factor(sample(2, 100, replace=TRUE)) xs<-matrix(runif(100), ncol=1) colnames(xs)<-"x" myfit<-glmnet(xs, y, family="binomial") mydata<-matrix(runif(10), ncol=1) colnames(mydata)<-"x" class(myfit) predict(myfit, newx=mydata, type="response") class(myfit)<-rev(class(myfit)) class(myfit) predict(myfit, newx=mydata, type="response") class(myfit)<-rev(class(myfit))#set it back class(myfit)
Depending on the data generated, the difference is more or less obvious (in my true data set, I noticed negative values โโin the so-called probabilities, this is how I took the problem), but you really should see the difference.
Thanks for any input.
Edit
I just found out the terrible truth: either the order worked in glmnet 1.5.2 (which is present on the server, where I ran the actual code, which led to the correction with the cancellation of the order), but the code from 1.6 requires the order to be "lognet", "glmnet" . I have yet to check what happens in 1.7.
Thanks to @Aaron for reminding me of the basics of computer science (besides, "if all else fails, restart": "check your versions"). I mistakenly assumed that the statistical training gods package would be protected from this type of error) and @Gavin to confirm my reconstruction of S3.