我搜索了一个参考,以了解R中的替换函数,但我还没有找到。我试图理解R中替换函数的概念。我有下面的代码,但我不明白:
"cutoff<-" <- function(x, value){
x[x > value] <- Inf
x
}
然后我们用:
调用cutoff cutoff(x) <- 65
有人可以解释一下R中的替代功能吗?
答案 0 :(得分:46)
致电时
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<-"()
并安排{{1>}的结果来设置调用1}}被分配回"FUN<-"()
,因此它调用:
obj
此信息的有用参考是R Language Definition Section 3.4.4: Subset assignment ;讨论有点倾斜,但似乎是最官方的参考(替换函数在R FAQ(R和S-PLUS之间的差异)中提及,并且在R语言参考(各种技术问题)中,但我没有在官方文件中找到任何进一步的讨论。)
答案 1 :(得分:10)
Gavin对替换函数的解释提供了很好的讨论。我想提供一个参考,因为您还要求:R Language Definition Section 3.4.4: Subset assignment。
答案 2 :(得分:4)
作为已接受答案的补充,我想指出,替换函数也可以为非标准函数定义,即运算符(请参见?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"
这些在实践中很少遇到(实际上,我负责为我的软件包pbfor定义for<-
的唯一实际用途),但是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
答案 3 :(得分:2)
请记住,在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 base包中的所有替换函数find it here。