在R中,具有与基本R函数同名的变量究竟是什么问题?

And*_*rie 46 variables r function

使用具有相同名称的基本R中的函数的变量名称似乎通常被认为是不良的编程习惯.

例如,写作很有诱惑力:

data <- data.frame(...)
df   <- data.frame(...)
Run Code Online (Sandbox Code Playgroud)

现在,该函数data在函数df计算f密度函数时加载数据集.

同样,写作很有诱惑力:

a <- 1
b <- 2
c <- 3
Run Code Online (Sandbox Code Playgroud)

这被认为是不好的形式,因为该函数c将组合其参数.

但是:在R函数的主力中lm,计算线性模型data用作参数.换句话说,data成为lm函数内部的显式变量.

那么:如果R核心团队可以对变量和函数使用相同的名称,那么什么阻止了我们凡人呢?

答案不是R会混淆.请尝试以下示例,其中我明确指定了具有名称的变量c.R根本不会对变量和函数之间的区别感到困惑:

c("A", "B")
[1] "A" "B"

c <- c("Some text", "Second", "Third")
c(1, 3, 5)
[1] 1 3 5

c[3]
[1] "Third"
Run Code Online (Sandbox Code Playgroud)

问题:具有与基本R函数同名的变量究竟是什么问题?

Rei*_*son 23

真的没有.在查找函数时,R通常不会搜索对象(非函数对象):

> mean(1:10)
[1] 5.5
> mean <- 1
> mean(1:10)
[1] 5.5
> rm(mean)
> mean(1:10)
[1] 5.5
Run Code Online (Sandbox Code Playgroud)

@Joris和@Sacha所展示的例子是糟糕的编码让你感动的地方.一种更好的写作方式foo是:

foo <- function(x, fun) {
    fun <- match.fun(fun)
    fun(x)
}
Run Code Online (Sandbox Code Playgroud)

使用时给出:

> foo(1:10, mean)
[1] 5.5
> mean <- 1
> foo(1:10, mean)
[1] 5.5
Run Code Online (Sandbox Code Playgroud)

在某些情况下,这会让你na.omit感到困惑,@ Joris的例子是IIRC,因为使用了标准的,非标准的评估,正在发生这种情况lm().

几个答案也将Tvs TRUE问题与功能问题的掩盖混为一谈.作为TTRUE不是函数有点超出@Andrie的问题的范围.


Jor*_*eys 18

问题不在于计算机,而在于用户.通常,代码可能变得更难调试.错字很容易制作,所以如果你这样做:

c <- c("Some text", "Second", "Third")
c[3]
c(3)
Run Code Online (Sandbox Code Playgroud)

你得到了正确的结果.但是,如果你在代码某处怀念和类型c(3)来代替c[3],发现错误就不会那么容易.

范围界定还可能导致非常混乱的错误报告.采取以下有缺陷的功能:

my.foo <- function(x){
    if(x) c <- 1
    c + 1
}

> my.foo(TRUE)
[1] 2
> my.foo(FALSE)
Error in c + 1 : non-numeric argument to binary operator
Run Code Online (Sandbox Code Playgroud)

通过更复杂的功能,这可以引导您进行无处调试.如果您替换cx上述功能,该错误会读" object 'x' not found".这将使您的编码错误更快.

接下来,它可能导致相当混乱的代码.代码c(c+c(a,b,c))比大脑要求更多c(d+c(a,b,d)).同样,这是一个微不足道的例子,但它可以有所作为.

显然,你也可以得到错误.当你期望一个函数,你将无法得到它,这可能会产生另一组恼人的错误:

my.foo <- function(x,fun) fun(x)
my.foo(1,sum)
[1] 1
my.foo(1,c)
Error in my.foo(1, c) : could not find function "fun"
Run Code Online (Sandbox Code Playgroud)

一个更现实(和现实)的例子,说明这会导致什么问题:

x <- c(1:10,NA)
y <- c(NA,1:10)
lm(x~y,na.action=na.omit)
# ... correct output ...
na.omit <- TRUE
lm(x~y,na.action=na.omit)
Error in model.frame.default(formula = x ~ y, na.action = na.omit, 
drop.unused.levels = TRUE) : attempt to apply non-function
Run Code Online (Sandbox Code Playgroud)

如果na.omit <- TRUE代码中出现50行,请尝试弄清楚这里有什么问题...

在@Andrie评论后编辑的答案包括混淆错误报告的示例


Sac*_*amp 11

R对此非常强大,但你可以想办法打破它.例如,考虑这个函数:

foo <- function(x,fun) fun(x)
Run Code Online (Sandbox Code Playgroud)

这仅仅适用funx.这不是最漂亮的方式,但你可能会从某人脚本中遇到这种情况.这适用于mean():

> foo(1:10,mean)
[1] 5.5
Run Code Online (Sandbox Code Playgroud)

但是,如果我指定一个新值来表示它中断:

mean <- 1
foo(1:10,mean)

Error in foo(1:10, mean) : could not find function "fun"
Run Code Online (Sandbox Code Playgroud)

这种情况很少发生,但可能会发生.如果同样的事情意味着两件事,那对人们来说也很困惑:

mean(mean)
Run Code Online (Sandbox Code Playgroud)

既然是微不足道使用任何你想要的其他名字,为什么不使用不同的名字,那么基础R的功能呢?此外,对于某些R变量,这变得更加重要.想想重新分配'+'功能!另一个很好的例子是重新分配,T并且F可以打破这么多脚本.

  • 关于使用`T`和`F`的非常好的评论.我的观点是,使用这些快捷方式表示T​​RUE或FALSE是不好的做法.始终在代码中使用TRUE和FALSE - 这些是R中的保留字,无法重新分配. (3认同)