我搜索了参考以了解 R 中的替换函数,但我还没有找到任何内容。我试图理解 R 中替换函数的概念。我有下面的代码,但我不明白:
"cutoff<-" <- function(x, value){
x[x > value] <- Inf
x
}
然后我们调用 cutoff :
cutoff(x) <- 65
谁能解释一下R中的替换函数是什么?
我搜索了参考以了解 R 中的替换函数,但我还没有找到任何内容。我试图理解 R 中替换函数的概念。我有下面的代码,但我不明白:
"cutoff<-" <- function(x, value){
x[x > value] <- Inf
x
}
然后我们调用 cutoff :
cutoff(x) <- 65
谁能解释一下R中的替换函数是什么?
你打电话时
cutoff(x) <- 65
你实际上是在打电话
x <- "cutoff<-"(x = x, value = 65)
必须引用函数的名称,因为它是语法上有效但非标准的名称,<-
如果未引用,解析器将解释为运算符而不是函数名称的一部分。
"cutoff<-"()
就像任何其他功能一样(尽管名称很奇怪);它基于value
(在这种情况下,它将任何值设置为大于x
(无限))对其输入参数进行更改。65
Inf
当你像这样调用函数时,魔法真的完成了
cutoff(x) <- 65
因为 R 正在解析它并提取各种位以进行如上所示的真正调用。
更一般地说,我们有
FUN(obj) <- value
R 找到函数并通过传递和来"FUN<-"()
设置调用,并安排将结果分配回,因此它调用:obj
value
"FUN<-"()
"FUN<-"()
obj
obj <- "FUN<-"(obj, value)
此信息的有用参考是R 语言定义第 3.4.4 节:子集分配;讨论有点倾斜,但似乎是最官方的参考资料(在 R FAQ(R 和 S-PLUS 之间的差异)和 R 语言参考资料(各种技术问题)中提到了替换函数,但我没有在官方文档中找到任何进一步的讨论)。
Gavin 对替换函数的解释进行了很好的讨论。我想提供一个参考,因为您也要求提供:R Language Definition Section 3.4.4: Subset assignment。
作为已接受答案的补充,我想指出,替换函数也可以为非标准函数定义,即运算符(请参阅 参考资料?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
请记住,在 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 基础包中的所有替换函数,在这里找到它。