8

我一直无法理解有关如何调用 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)

然后再次进行预测调用:你瞧:它起作用了!我确实得到了概率。

所以,这里有几个问题:

  1. 我是否“了解到”S3 方法是按类的出现顺序调度的?
  2. 我是否正确假设中的代码 glmnet会导致正确调度的错误顺序 predict
  3. 据我所知,在我的代码中,没有任何东西可以显式/可见地操作类。什么可能导致订单发生变化?

为了完整起见:这里有一些示例代码可以使用(就像我现在自己做的那样):

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 的工作原理。

4

1 回答 1

6

是的,分派的顺序是类在类属性中列出的顺序。在简单的日常案例中,是的,第一个声明的类是方法调度首先选择的类,只有当它未能找到该类的方法(或被NextMethod调用)时,它才会转到第二个类,或未能搜索default方法。

不,我认为代码中类的顺序错误是不对的。文档显示错误。目的显然是predict.lognet()首先调用,使用主力对glmnetpredict.glmnet()拟合的所有类型的套索/弹性网络模型进行基本计算,最后对这些一般预测进行一些后处理。这不是从 glmnet NAMESPACE 导出的,其他方法可能也在说明问题。predict.glmnet()

我不确定你为什么认为这个输出:

predict(myfit, newx=mydata, type="response")

是错的?我得到一个由 10 行和 21 列组成的矩阵,其中的列与仅截距模型预测相关,加上 20 个 lambda 值的预测,在该 lambda 值处,已经计算了沿套索/弹性网络路径的模型系数。这些似乎不是线性组合,是您要求的响应量表之一。

类的顺序没有改变。我认为您误解了代码应该如何工作。文档中有一个错误,因为那里的顺序是错误的。但是代码正在按我认为的那样工作。

于 2011-06-23T23:15:22.797 回答