S3和班级顺序

时间:2011-06-23 22:16:05

标签: r glmnet

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

我添加了一条评论来解释我的推理。现在,当我使用新的数据矩阵myfitmydata调用此type="response"上的预测时,就像这样:

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

,根据文档,我不会得到预测的概率,而是线性组合,这正是立即调用predict.glmnet的结果。

我尝试过颠倒类的顺序,如下所示:

orgclass<-class(myfit)
class(myfit)<-rev(orgclass)

然后再次做预测电话:瞧瞧:它有效!我获得概率。

所以,这里有一些问题:

  1. 我是否正确'学会'了 按顺序分派S3方法 课程的外观?
  2. 我是否正确地承担了代码 glmnet会导致错误的订单 正确派遣 predict
  3. 在我的代码中没有任何内容 操纵类 明确地/明显地知道我的知识。 什么可能导致订单 改变?
  4. 为了完整起见:这里有一些示例代码(正如我现在自己做的那样):

    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)
    

    根据生成的数据,差异或多或少是显而易见的(在我的真实数据集中,我注意到所谓的概率中的负值,这就是我解决问题的方式),但你确实应该看到差异。 / p>

    感谢您的任何意见。

    修改

    我刚刚发现了一个可怕的事实:无论是在glmnet 1.5.2中运行的命令(在我运行实际代码的服务器上都存在,导致与类顺序相反),但1.6中的代码需要命令为“lognet”,“glmnet”。我还没有检查1.7中会发生什么。

    感谢@Aaron提醒我信息学的基础知识(除了'如果所有其他方法都失败了,重启':'检查你的版本')。我错误地认为统计学习之神的包装将受到保护,免受此类错误的影响),并且@Gavin确认我重建S3的工作方式。

1 个答案:

答案 0 :(得分:6)

是的,调度顺序是类属性中列出的顺序。在简单的,每天的情况下,是的,第一个声明的类是首先通过方法调度选择的类,并且只有当它找不到该类的方法(或者NextMethod被调用)时才会继续到第二课,或者没有找到default方法。

不,我认为你的代码顺序错误是正确的。文档显示错误。目的显然是首先调用predict.lognet(),使用主力predict.glmnet()对由 glmnet 拟合的所有类型的套索/弹性网模型进行基本计算,最后做一些后处理那些一般预测。从 glmnet NAMESPACE导出的predict.glmnet() ,而其他方法也许也是如此。

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

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

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

班级顺序没有变化。我认为你误解了代码应该如何工作。文档中有一个错误,因为那里的排序错误。但是代码正在按照我的想法运作。