当前位置: 首页>>代码示例 >>用法及示例精选 >>正文


R setMethod 创建并保存方法


R语言 setMethod 位于 methods 包(package)。

说明

为泛型函数创建一个方法,对应于参数的类签名。标准用法将采用以下形式:

setMethod(f, signature, definition)

其中f 是函数的名称,signature 指定该方法适用的参数类,definition 是该方法的函数定义。

用法

setMethod(f, signature=character(), definition,
          where = topenv(parent.frame()),
          valueClass = NULL, sealed = FALSE)

参数

f

通用函数的字符串名称。不带引号的名称通常也可以使用(评估通用函数),但基础包中的一些函数除外。

signature

某些参数所需的类。大多数应用程序只需要一个或两个与签名中的第一个参数匹配的字符串。更复杂的情况遵循 R 的参数匹配规则。请参阅下面的详细信息;但是,如果签名不简单,您应该使用 method.skeleton 生成对 setMethod 的有效调用。

definition

函数定义,当 f 调用中的参数直接或通过继承与 signature 中的类匹配时,它将成为调用的方法。定义必须是一个与泛型具有相同形式参数的函数;但是,如果 ... 是泛型的形式参数,则 setMethod() 将处理添加参数的方法。请参阅详细信息部分。

where, valueClass, sealed

这些论点是允许的,但或者过时,或者很少合适。

where :存储定义的位置;应该是默认的,包的命名空间。

valueClass:已过时。

sealed :防止重新定义方法,但在包的源代码中定义方法时永远不需要。

该函数的存在是因为它的副作用。该定义将存储在特殊的元数据对象中,并在相应的包加载到 R 会话中时合并到通用函数中。

方法选择:避免歧义

定义方法时,确保正确选择方法非常重要;特别是,包的设计应避免方法选择不明确。

为了说明方法选择,首先考虑主动签名中只有一个形式参数的情况;也就是说,只有一个参数,例如x,已为其定义了方法。通用函数有一个方法表,按 setMethod 调用中参数的类进行索引。如果表中存在调用中的x类的方法,则选择该方法。

如果不是,下一个最佳方法将对应于 class(x) 的直接超类 - 定义该类时出现在 contains= 参数中的方法。如果其中任何一个都没有方法,则下一个最佳方法将对应于第一组超类的直接超类,依此类推。

如果该类有多个直接超类并且已为其中多个直接超类定义了方法,则出现第一个可能的歧义来源;R将认为这些同样有效并报告不明确的选择。如果你的包有类定义class(x),那么您需要为泛型函数和类的组合显式定义一个方法。

当方法签名中出现多个形式参数时,R要求为每个参数明确选择“best”方法。当一种方法特定于一个论点而另一种方法特定于不同的论点时,就会出现歧义。满足这两个要求的调用是不明确的:这两个方法看起来同样有效,应该选择哪个?在这种情况下,包需要添加第三个方法,要求两个参数匹配。

最常见的例子是二元运算符。可以为单个运算符、特殊运算符组(例如 Arith 或组 Ops )定义方法。

导出方法

如果一个包定义了泛型函数的方法,那么当导出任何涉及的类时,这些方法也应该被导出;换句话说,如果使用该包的人可能期望调用这些方法。通过在包的 NAMESPACE 文件中包含 exportMethods() 指令来导出方法,该指令的参数是已为其定义方法的通用函数的名称。

从声明你想要发生的事情的意义上来说,导出方法总是可取的,因为你确实希望用户找到这样的方法。如果该方法是为某个函数定义的,而该函数原本不是其自己的包中的通用函数(例如,plot()在里面graphics包)。在这种情况下,可能是函数中的版本R会话不是通用的,并且您的方法不会被调用。

导出函数的方法也会导出该函数的通用版本。请记住,这确实不是与该函数冲突,因为它最初是在另一个包中定义的;相反,它的目的是确保函数Rsession 为您的类正确分派方法,并在没有应用特定方法时继续按预期运行。看Methods_Details对于实际的机制。

细节

setMethod 的调用将提供的方法定义存储在环境(通常是全局环境或包的命名空间)中此通用函数的元数据表中。对于包,表对象成为包的命名空间或环境的一部分。当包加载到稍后的会话中时,这些方法将合并到相应通用函数对象的方法表中。

泛型函数通过函数名和包名的组合来引用;例如,包 "methods" 中的函数 "show" 。方法的元数据由两个字符串标识;特别是,通用函数对象本身具有包含其名称和包名称的槽。泛型的包名是根据它最初来自的包来设置的;特别是,并且经常是该函数的非通用版本起源的包。例如,包 base 中所有函数的通用函数将以 "base" 作为包名称,尽管它们都不是该包上的 S4 通用函数。其中包括大多数基元函数,而不是真正的函数;有关详细信息,请参阅 setGeneric 文档中有关原始函数的部分。

多个包可以具有相同通用函数的方法;也就是说,对于通用函数名称和包名称的相同组合。即使这些方法存储在不同环境中的单独表中,加载相应的包也会在会话期间将这些方法添加到通用函数本身的表中。

签名中的类名可以是任何正式类,包括 "numeric""character""matrix" 等基本类。可以出现两个额外的特殊类名: "ANY" ,这意味着该参数可以有任何类;和 "missing" ,这意味着此参数不得出现在调用中才能匹配此签名。不要混淆这两者:如果签名中未提及参数,则它隐式对应于类 "ANY" ,而不是 "missing" 。请参阅下面的示例。如果您需要与这些类兼容,也可以使用 Old-style (‘S3’) 类,但如果您希望 S3 样式继承起作用,则绝对应该通过调用 setOldClass 来声明这些类。

方法定义可以具有参数的默认表达式,但前提是泛型函数必须具有一些相同参数的默认表达式。 (此限制是通过以下方式施加的R管理形式参数。)如果是这样,并且在对泛型函数的调用中缺少相应的参数,则使用方法中的默认表达式。如果方法定义没有参数的默认值,则使用泛型函数本身的定义中提供的表达式,但请注意,将使用方法的封闭环境而不是泛型函数的封闭环境来计算该表达式。方法选择不会评估默认表达式。当选择方法时,将评估泛型函数签名中的所有实际(非缺失)参数 - 当调用standardGeneric(f)发生。注意指定类"missing"签名中不需要任何默认表达式。

提供给 setMethod 的方法的形式参数与泛型的形式参数之间可能存在一些差异。粗略地说,如果泛型将 ... 作为其参数之一,则该方法可能具有额外的形式参数,这些参数将从调用 f 中匹配 ... 的参数进行匹配。 (实际发生的情况是,在方法内部创建了一个本地函数,并使用修改后的形式参数,并且重新定义了该方法以调用该本地函数。)

方法调度尝试匹配为 f 收集的可用方法调用中的实际参数的类。如果为与此调用中完全相同的类定义了一个方法,则使用该方法。否则,所有可能的签名都被视为对应于实际类或实际类的超类(包括 "ANY" )。选择与实际类别距离最小的方法;如果多个方法具有最小距离,则选择一个方法(就超类而言,按字典顺序排列的第一个),但会发出警告。所有选择的继承方法都存储在另一个表中,以便每个会话每个实际类序列只需执行一次继承计算。有关更多详细信息,请参阅Methods_Details 和参考文献的第 10.7 节。

例子


## examples for a simple class with two numeric slots.
## (Run example(setMethod) to see the class and function definitions)


## methods for plotting track objects 
##
## First, with only one object as argument, plot the two slots
##  y must be included in the signature, it would default to "ANY"
setMethod("plot", signature(x="track", y="missing"),
  function(x,  y, ...) plot(x@x, x@y, ...)
)

## plot numeric data on either axis against a track object
## (reducing the track object to the cumulative distance along the track)
## Using a short form for the signature, which matches like formal arguments
setMethod("plot", c("track", "numeric"),
 function(x, y, ...) plot(cumdist(x@x, x@y), y,  xlab = "Distance",...)
)

## and similarly for the other axis
setMethod("plot", c("numeric", "track"),
 function(x, y, ...) plot(x, cumdist(y@x, y@y),  ylab = "Distance",...)
)

t1 <- new("track", x=1:20, y=(1:20)^2)
plot(t1)
plot(qnorm(ppoints(20)), t1)

## Now a class that inherits from "track", with a vector for data at
## the points 
  setClass("trackData", contains = c("numeric", "track"))


tc1 <- new("trackData", t1, rnorm(20))


## a method for plotting the object
## This method has an extra argument, allowed because ... is an
## argument to the generic function.
setMethod("plot", c("trackData", "missing"),
function(x, y, maxRadius = max(par("cin")), ...) {
  plot(x@x, x@y, type = "n", ...)
  symbols(x@x, x@y, circles = abs(x), inches = maxRadius)
  }
)
plot(tc1)

## Without other methods for "trackData", methods for "track"
## will be selected by inheritance

plot(qnorm(ppoints(20)), tc1)

## defining methods for primitive function.
## Although "[" and "length" are not ordinary functions
## methods can be defined for them.
setMethod("[", "track",
  function(x, i, j, ..., drop) {
    x@x <- x@x[i]; x@y <- x@y[i]
    x
  })
plot(t1[1:15])

setMethod("length", "track", function(x)length(x@y))
length(t1)

## Methods for binary operators
## A method for the group generic "Ops" will apply to all operators
## unless a method for a more specific operator has been defined.

## For one trackData argument, go on with just the data part
setMethod("Ops", signature(e1 = "trackData"),
    function(e1, e2) callGeneric(e1@.Data, e2))

setMethod("Ops", signature(e2 = "trackData"),
    function(e1, e2) callGeneric(e1, e2@.Data))

## At this point, the choice of a method for a call with BOTH
## arguments from "trackData" is ambiguous.  We must define a method.

setMethod("Ops", signature(e1 = "trackData", e2 = "trackData"),
    function(e1, e2) callGeneric(e1@.Data, e2@.Data))
## (well, really we should only do this if the "track" part
## of the two arguments matched)

tc1 +1

1/tc1

all(tc1 == tc1)


参考

Chambers, John M. (2016) Extending R, Chapman & Hall. (Chapters 9 and 10.)

也可以看看

Methods_for_Nongenerics 讨论原始包中非泛型函数的函数的方法定义; Methods_for_S3 讨论形式方法与旧 S3 方法的集成。

method.skeleton ,这是生成 setMethod 调用框架的推荐方法,其中包含正确的形式参数和其他详细信息。

Methods_Details 以及用于一般讨论的链接,dotsMethods 用于在 “...” 上分派的方法,setGeneric 用于通用函数。

相关用法


注:本文由纯净天空筛选整理自R-devel大神的英文原创作品 Create and Save a Method。非经特殊声明,原始代码版权归原作者所有,本译文未经允许或授权,请勿转载或复制。