【问题标题】:What is setReplaceMethod() and how does it work?什么是 setReplaceMethod() 以及它是如何工作的?
【发布时间】:2018-03-06 13:50:55
【问题描述】:

我对@9​​87654322@ 的用法感到困惑。查看?setReplaceMethod 并没有提供解释,谷歌搜索也没有什么帮助。

问题:请解释setReplaceMethod(),它的用法和它是如何工作的(最好有一个例子)。

【问题讨论】:

标签: r s4


【解决方案1】:

这是我发现的。正如@Hong Ooi 在cmets 中指出的那样setReplaceMethod("fun")setMethod("fun<-") 相同,因此setReplaceMethod 用于在R 的S4 对象系统中创建通用替换函数的方法。

what-are-replacement-functions-in-r 中解释了什么是替换函数。非常粗略,如果你有一个名为fun<- 的函数,因为它的名字以<- 结尾,你可以写fun(x)<-a,而R 将读为x <- "fun<-"(x,a)

S4 - Advanced R 中描述了 S4 对象系统。

举个例子,从为 S4 泛型函数创建一个方法开始可能会更容易,这不是替代函数:

## Define an S4 class 'Polygon' and an object of this class
setClass("Polygon", representation(sides = "integer"))
p1 <- new("Polygon", sides = 33L)
## Define a generic S4 function 'sides'
sides <- function(object){ NA }
setGeneric("sides")
## sides returns NA
sides( p1 )
## Define a method for 'sides' for the class 'Polygon'
setMethod("sides", signature(object = "Polygon"), function(object) {
  object@sides
})
## Now sides returns the sides of p1
sides( p1 )

为泛型替换函数创建方法类似:

## Define a generic replacement function 'sides<-'
"sides<-" <- function(object, value){ object }
setGeneric( "sides<-" )
## The generic 'sides<-' doesn't change the object
sides( p1 ) <- 12L
sides( p1 )
## Define a method for 'sides<-' for the class 'Polygon',
## setting the value of the 'sides' slot
setMethod( "sides<-", signature(object = "Polygon"), function(object, value) {
  object@sides <- value
  object
})
## Now 'sides<-' change the sides of p1
sides( p1 ) <- 12L
sides( p1 )

您还询问了$&lt;-。我的猜测是:x$name&lt;-value 被解释为"$"(x,name)&lt;-value,然后被解释为x &lt;- "$&lt;-"(x,name,value)。请注意,泛型函数$&lt;- 已经定义(isGeneric("$&lt;-")),所以我们只为我们的多边形类定义一个方法:

setMethod( "$<-", signature(x = "Polygon"), function(x, name, value) {
  if( name=="sides" ){
    x@sides <- value
  }
  x
})
## Nothing changes if we try to set 'faces'
p1$faces <- 3L
p1
## but we can set the 'sides'
p1$sides <- 3L
p1

请注意,参数 xnamevalue 由泛型决定。

【讨论】:

  • 所以运行p1 &lt;- "$&lt;-"(p1,sides,777)"$"(x,sides)&lt;-777 会返回错误。我认为您对答案后半部分的解释不正确
  • @irritable_phd_syndrom 那是因为sides 被定义为整数,而777R 中不是整数!你必须写777L:比较class(777)class(777L)。事实上p1 &lt;- "$&lt;-"(p1,sides,777L)"$"(p1,sides)&lt;-777L 工作。
  • 那怎么样...这是令人困惑的 b/c 4+5 产生 9。我想我不明白它什么时候决定一个数字是数字还是其他东西
  • 另外,isGeneric("$&lt;-") 是在哪里定义的?
  • @irritable_phd_syndrom 看看burns-stat.com/pages/Tutor/R_inferno.pdf, pg. 91 和?isGeneric
【解决方案2】:

对于$[names() 等提取方法,$&lt;-[&lt;-names&lt;-替换 方法替换会被提取出来。

以列表为例:

example_object <- list(a = 1, b = 2)
# the extract method $, when called with arguments example_object and a,
# extracts and returns the value 1
example_object$a
# [1] 1
# the replace method $<-, when called with arguments example_object, a, and 42,
# replaces the value 1 (at example_object$a) with the value 42
example_object$a <- 42
example_object
# $a
# [1] 42
# 
# $b
# [1] 2

因此,对于 S4 类,setMethod("$", ...) 将定义提取方法 $ 的行为,而 setMethod("$&lt;-", ...) 或等效的 setReplaceMethod("$", ...) 将定义替换方法 $&lt;- 的行为。 setReplaceMethod("$") 只是为了比setMethod("$&lt;-") 更具表现力,以明确您正在为$ 定义替换方法。

使用 S4 类的示例:

setClass("MyClass", representation(a = "numeric", b = "numeric"))

setMethod("$", signature = "MyClass",
          function (x, name) {
              if ( name == "a" ) {
                  return(x@a)
              }
              else if ( name == "b" ) {
                  return(x@b)
              }
              else {
                  stop(paste("No slot", name, "for MyClass"), call. = FALSE)
              }
          }
)
# [1] "$"

my_object <- new("MyClass", a = 1, b = 2)
my_object@a
# [1] 1
my_object$a
# [1] 1

my_object@a <- 42
my_object@a
# [1] 42
my_object$a <- 3.14 # will not work because we have not set the method for $<-
# Error in `$<-`(`*tmp*`, a, value = 3.14) : 
#   no method for assigning subsets of this S4 class
my_object@a
# [1] 42

setReplaceMethod("$", signature = "MyClass",
                 function(x, name, value) {
                     if ( name == "a" ) {
                         x@a <- value
                         return(x)
                     }
                     else if ( name == "b" ) {
                         x@b <- value
                         return(x)
                     }
                     else {
                         stop(paste("No slot", name, "for MyClass"),
                              call. = FALSE)
                     }
                 }
)
# [1] "$<-"

my_object$a <- 3.14
my_object@a
# [1] 3.14

【讨论】:

  • 所以这可以用来创建奇怪的(至少从 C/Python 程序员的角度来看)左手函数调用和赋值?例如。 df&lt;-as.data.frame(cbind(c(1,2,3), c(4,5,6))) 然后colnames(df) &lt;- c("name1", "name2")。这叫什么?
  • @irritable_phd_syndrom 是的;我通常看到它称为替换方法。例如,help("colnames&lt;-") 显示行和列名称的帮助文件,用法部分显示提取方法colnames(x, ...) 和替换方法colnames(x) &lt;- value
  • 这是一个很好的答案,但是,您能否解决在一般功能上使用setReplaceMethod() 的一般情况?您的回答似乎解决了提取方法的特殊情况。
猜你喜欢
  • 2020-08-06
  • 2013-01-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-14
  • 2014-11-15
  • 2014-01-09
  • 1970-01-01
相关资源
最近更新 更多