如何测试R包中的函数是否通用

时间:2018-06-01 16:22:22

标签: r generics methods package

我可以列出包含'auc'功能的所有包:

library(sos)
library(dplyr)

auc.search = findFn("auc") 
auc.search %>%
    filter(Function == "auc", Package != "pROC") %>%
    select(Package, Function, Description) %>% head

          Package Function                                                  Description
1         longROC      auc                                                          AUC
2             AUC      auc   Compute the area under the curve of a given performance...
3              PK      auc Estimation of confidence intervals for the area under the...
4 PresenceAbsence      auc                                         Area Under the Curve
5            aucm      auc                                                          AUC
6         precrec      auc                          Retrieve a data frame of AUC scores

现在我想测试这些包中的函数是否是泛型函数。我怎么能这样做?

例如我想要这样的东西:

library(AUC)
is.generic(AUC::auc)
FALSE

library(pROC)
is.generic(pROC::auc)
TRUE

关于我这样做的原因的一些背景:当我加载任何这些包时,搜索路径上的包中的auc函数将被新附加的包中的一个掩盖。如果加载的函数是泛型函数(除非类名冲突,但这是另一个问题),这不是问题。但是,如果该函数不是通用函数,则加载包将是一个问题,我想要检测它。

1 个答案:

答案 0 :(得分:1)

以下功能基本上完成了这项工作。它使用@Gregor指出的utils::isS3stdGeneric来测试S3泛型,并使用methods::isGeneric来测试S4。主要问题是它必须搞乱搜索空间,因此大部分功能实际上是加载包并确保它之后被依赖项正确删除。

is.function.in.package.generic <- function(pkg, fun) {
    old.search.pos <- search()[2]
    on.exit({
        while (attr(parent.env(.GlobalEnv), "name") != old.search.pos) {
            detach()
        }
    })
    suppressPackageStartupMessages(library(pkg, character.only = TRUE))
    # Does the package actually have a roc function
    t <- try(get(fun), silent=TRUE)
    if (methods::is(t, "try-error")) {
        warning(sprintf("Package %s doesn't seem to contain function %s", pkg, fun))
        return(NA)
    }
    if (isS3stdGeneric(fun)) {
        return(TRUE)
    }
    if (isGeneric(fun)) {
        return(TRUE)
    }
    return(FALSE)
}

似乎工作正常:

> is.function.in.package.generic("graphics", "plot") #S4
[1] TRUE
> is.function.in.package.generic("analogue", "roc") #S3
[1] TRUE
> is.function.in.package.generic("longROC", "roc") # Not generic
[1] TRUE
> is.function.in.package.generic("aucm", "roc") # No such function
[1] NA
Warning message:
In is.function.in.package.generic("aucm", "roc") :
  Package aucm doesn't seem to contain function roc