我正在测试是否可以支持使用 ememans 中的 cplm 软件包拟合的模型,并且遇到了terms
的一些非常奇怪的行为方法。这是一个示例:
library(emmeans)
library(cplm)
data(mtcars)
m <- cpglm(mpg ~ cyl + disp + hp, data = mtcars)
函数emmeans:::recover_data.lm
似乎可以正常工作。它只是在对象上调用terms
方法,并将其传递给其他函数。但是,它不起作用:
> emmeans:::recover_data.lm(m)
Error in slot(x, name) :
no slot of name "terms" for this object of class "cpglm"
进一步研究,我确认terms()
在全局环境中确实有效:
> terms(m)
mpg ~ cyl + disp + hp
... (remaining lines excluded) ...
但是,它在recover_data.lm
中不起作用:
> debug(emmeans:::recover_data.lm)
> emmeans:::recover_data.lm(m)
...
Browse[2]> terms(object)
Error in slot(x, name) :
no slot of name "terms" for this object of class "cpglm"
Browse[2]> getMethod("terms", "cpglm")
Error in getMethod("terms", "cpglm") :
no method found for function 'terms' and signature cpglm
但是...
Browse[2]> getMethod("terms", "cplm") ## cpglm inherits from cplm
Method Definition:
function (x, ...)
attr(x@model.frame, "terms")
... etc. ...
Browse[2]> methods("terms")
[1] terms,ANY-method terms,cplm-method terms.default* terms.formula* terms.gls*
[6] terms.merMod* terms.terms*
see '?methods' for accessing help and source code
Browse[2]> selectMethod("terms", "cpglm")
Method Definition:
function (x, ...)
attr(x@model.frame, "terms")
... etc. ...
因此,在 emmeans 的名称空间中,我可以验证我们“知道” terms
对象有一个cpglm
方法,并且可以通过以下方式找到它selectMethod()
,但不能通过getMethod()
或仅通过调用terms()
来实现。这很奇怪,尤其是因为selectMethod
的文档似乎承诺它应该可以工作:
函数
selectMethod()
返回将被选择的方法 如果参数具有由所指定的类,则调用函数f
signature
。
最后,我能够验证这似乎与调度S3方法时的冲突有关:
> stats::terms(m)
Error in slot(x, name) :
no slot of name "terms" for this object of class "cpglm"
当S3和S4方法混合使用时,有没有办法让我的软件包 emmeans 正常工作;特别是要在S3方法之前先寻找S4方法?
答案 0 :(得分:1)
来自Methods_for_S3
中的文档条目:
同时定义S3和S4方法的原因如下:
- 如果直接调用S3泛型函数,则将不会单独看到S4方法。例如,如果某些函数从不使该函数成为S4泛型的程序包中调用unique(),就会是这种情况。
cplm
软件包为terms
导出了S4方法,
但不是S3的一个
您可以看到here。
当您附加terms
时,这将自动使cplm
成为S4通用。
但是,emmeans
从stats
调用S3泛型,
这就是导致问题的原因。
您可以通过在调度到S4泛型的全局环境中定义一个S3泛型来解决此问题:
terms.cpglm <- function(x, ...) {
cplm::terms(x, ...)
}
但是您应该让cplm
维护人员知道,如果他要将S3泛型转换为S4,则应该定义S3和S4方法。