我一直无法理解有关如何调用 S3 方法的文档,这一次它让我反感。
我会为提出多个问题而预先道歉,但它们都是密切相关的。在一组复杂函数的核心深处,我创造了很多glmnet
拟合,尤其是逻辑拟合。现在,glmnet
文档将其返回值指定为具有“glmnet”和(用于逻辑回归)“lognet”两个类。实际上,这些都是按此顺序指定的。
但是,查看 的实现结束glmnet
,就在调用(内部函数)lognet
之后,将类设置fit
为“lognet”,我在返回(变量)之前看到这行代码fit
:
class(fit) = c(class(fit), "glmnet")
由此,我得出结论,类的顺序实际上是“lognet”、“glmnet”。
不幸的是,我的健康状况(就像医生建议的那样):
> class(myfit)
[1] "glmnet" "lognet"
问题在于为它分派 S3 方法的方式,特别是predict
. 这是代码predict.lognet
:
function (object, newx, s = NULL, type = c("link", "response",
"coefficients", "class", "nonzero"), exact = FALSE, offset,
...)
{
type = match.arg(type)
nfit = NextMethod("predict") #<- supposed to call predict.glmnet, I think
switch(type, response = {
pp = exp(-nfit)
1/(1 + pp)
}, class = ifelse(nfit > 0, 2, 1), nfit)
}
我添加了一条评论来解释我的推理。现在,当我myfit
使用新的数据矩阵mydata
和对此进行预测时type="response"
,就像这样:
predict(myfit, newx=mydata, type="response")
,根据文档,我没有得到预测的概率,而是得到线性组合,这正是predict.glmnet
立即调用的结果。
我试过颠倒类的顺序,如下所示:
orgclass<-class(myfit)
class(myfit)<-rev(orgclass)
然后再次进行预测调用:你瞧:它起作用了!我确实得到了概率。
所以,这里有几个问题:
- 我是否“了解到”S3 方法是按类的出现顺序调度的?
- 我是否正确假设中的代码
glmnet
会导致正确调度的错误顺序predict
? - 据我所知,在我的代码中,没有任何东西可以显式/可见地操作类。什么可能导致订单发生变化?
为了完整起见:这里有一些示例代码可以使用(就像我现在自己做的那样):
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)
根据生成的数据,差异或多或少是明显的(在我的真实数据集中,我注意到所谓的概率中有负值,这就是我发现问题的方式),但你确实应该看到差异。
感谢您的任何意见。
编辑:
我刚刚发现了一个可怕的事实:任何一个顺序都在 glmnet 1.5.2 中工作(它存在于我运行实际代码的服务器上,导致与类顺序相反),但是 1.6 中的代码需要顺序是“lognet”,“glmnet”。我还没有检查 1.7 中发生了什么。
感谢@Aaron 提醒我信息学的基础知识(除了“如果一切都失败了,重新启动”:“检查你的版本”)。我错误地认为统计学习之神提供的软件包可以免受此类错误的影响),并感谢@Gavin 确认我重建了 S3 的工作原理。