51

我搜索了参考以了解 R 中的替换函数,但我还没有找到任何内容。我试图理解 R 中替换函数的概念。我有下面的代码,但我不明白:

"cutoff<-" <- function(x, value){
 x[x > value] <- Inf
 x
 }

然后我们调用 cutoff :

 cutoff(x) <- 65

谁能解释一下R中的替换函数是什么?

4

4 回答 4

54

你打电话时

cutoff(x) <- 65

你实际上是在打电话

x <- "cutoff<-"(x = x, value = 65)

必须引用函数的名称,因为它是语法上有效但非标准的名称,<-如果未引用,解析器将解释为运算符而不是函数名称的一部分。

"cutoff<-"()就像任何其他功能一样(尽管名称很奇怪);它基于value(在这种情况下,它将任何值设置为大于x(无限))对其输入参数进行更改。65Inf

当你像这样调用函数时,魔法真的完成了

cutoff(x) <- 65

因为 R 正在解析它并提取各种位以进行如上所示的真正调用。

更一般地说,我们有

FUN(obj) <- value

R 找到函数并通过传递和来"FUN<-"()设置调用,安排将结果分配回,因此它调用:objvalue"FUN<-"() "FUN<-"()obj

obj <- "FUN<-"(obj, value)

此信息的有用参考是R 语言定义第 3.4.4 节:子集分配;讨论有点倾斜,但似乎是最官方的参考资料(在 R FAQ(R 和 S-PLUS 之间的差异)和 R 语言参考资料(各种技术问题)中提到了替换函数,但我没有在官方文档中找到任何进一步的讨论)。

于 2012-07-19T14:46:11.650 回答
10

Gavin 对替换函数的解释进行了很好的讨论。我想提供一个参考,因为您也要求提供:R Language Definition Section 3.4.4: Subset assignment

于 2012-07-19T16:54:13.700 回答
7

作为已接受答案的补充,我想指出,替换函数也可以为非标准函数定义,即运算符(请参阅 参考资料?Syntax)和控制流构造。(见?Control)。

还要注意,为替换函数设计一个通用的和相关的方法是完全可以接受的。

运营商

定义新类时,通常会为 和 定义 S3 方法,$<-一些示例是、或。[[<-[<-data.table:::`$<-.data.table`data.table:::`[<-.data.table`tibble:::`$.tbl_df`

但是对于任何其他运算符,我们可以编写一个替换函数,一些示例:

`!<-` <- function(x, value) !value
x <- NULL # x needs to exist before replacement functions are used!
!x <- TRUE
x
#> [1] FALSE

`==<-` <- function(e1, e2, value) replace(e1, e1 == e2, value)
x <- 1:3
x == 2 <- 200
x
#> [1]   1 200   3

`(<-` <- function(x, value) sapply(x, value, USE.NAMES = FALSE)
x <- c("foo", "bar")
(x) <- toupper
x 
#> [1] "FOO" "BAR"

`%chrtr%<-` <- function(e1, e2, value) {
  chartr(e2, value, e1)
}

x <- "woot"
x %chrtr% "o" <- "a"
x
#> [1] "waat"

我们甚至可以定义<-<-,但是如果我们调用解析器会阻止它的使用x <- y <- z,所以我们需要使用从左到右的赋值符号

`<-<-` <- function(e1, e2, value){
  paste(e2, e1, value)
}
x <- "b"
"a" -> x <- "c"
x
#> [1] "a b c"

有趣的事实,<<-可以有双重作用

x <- 1:3
x < 2 <- NA # this fails but `<<-` was called!
#> Error in x < 2 <- NA: incorrect number of arguments to "<<-"

# ok let's define it then!
`<<-` <- function(x, y, value){
  if (missing(value)) {
    eval.parent(substitute(.Primitive("<<-")(x, y)))
  } else {
    replace(x, x < y, value)
  }
}
x < 2 <- NA
x
#> [1] NA  2  3
x <<- "still works"
x
#> [1] "still works"

控制流结构

这些在实践中很少遇到(事实上,我负责我所知道的唯一实际用途,在定义for<-我的包pbfor 时),但是 R 足够灵活,或者足够疯狂,可以让我们定义它们。但是要实际使用它们,由于解析控制流构造的方式,我们需要使用从左到右的赋值->

`repeat<-` <- function(x, value) replicate(value, x)
x <- "foo"
3 -> repeat x
x
#> [1] "foo" "foo" "foo"

function<-

function<-原则上可以定义,但据我所知,我们无能为力。

`function<-` <- function(x,value){NULL}

3 -> function(arg) {}
#> Error in function(arg) {: target of assignment expands to non-language object
于 2019-11-06T16:07:16.700 回答
3

请记住,在 R 中,所有操作都是函数调用(因此也是赋值操作),并且存在的所有内容都是对象。替换函数的行为就好像它们在适当的位置修改了它们的参数,例如

colnames(d) <- c("Input", "Output")

<-它们的名称末尾有标识符,并返回参数对象(非原始替换函数)或相同对象(原始替换函数)的修改副本

在 R 提示符下,以下内容将不起作用:

> `second` <- function(x, value) {
+   x[2] <- value
+   x
+ }
> x <- 1:10
> x
 [1]  1  2  3  4  5  6  7  8  9 10
> second(x) <- 9
Error in second(x) <- 9: couldn't find function "second<-"

如您所见,R 不是在搜索环境,second而是在搜索second<-. 所以让我们做同样的事情,但使用这样的函数标识符:

> `second<-` <- function(x, value) {
+   x[2] <- value
+   x
+ }

现在,向量第二个位置的赋值起作用了:

> second(x) <- 9
> x
 [1]  1  9  3  4  5  6  7  8  9 10

我还编写了一个简单的脚本来列出 R 基础包中的所有替换函数,在这里找到它

于 2016-05-07T19:45:41.607 回答