【问题标题】:Using get() with replacement functions使用带有替换函数的 get()
【发布时间】:2013-01-06 00:44:22
【问题描述】:

谁能解释一下为什么会出现下面的例子?

#Create simple dataframe
assign( "df" , data.frame( P = runif(5) , Q = runif(5) , R = runif(5) ) ) 

#Return the dataframe from the given character vector
get( "df" ) 
            P          Q          R
1  0.17396222 0.90994676 0.90590685
2  0.33860092 0.98078739 0.38058921
3  0.80751402 0.93229290 0.82853094
4  0.05460417 0.55448507 0.01605027
5  0.04250316 0.03808318 0.40678270

#Return the column names of df
colnames( get( "df" ) )
[1] "P" "Q" "R"

#But using a replacement function...
colnames( get( "df" ) ) <- c( "S" , "T" , "U" ) 
    Error in colnames(get("df")) <- c("S", "T", "U") : 
    target of assignment expands to non-language object

我愿意 A)想知道为什么替换函数不能以这种方式使用get()

b) 如果有一些方法可以解决这个问题,考虑到我在下面概述的问题;

我的问题是我有很多对象,在循环中创建(使用玩具示例),如下所示:assign( paste( "Object" , i , sep = "." ) , rnorm(1000 , i) ),其中i 是一个向量,比如i &lt;- 1:1000,然后我想成为能够为循环中的每个对象分配名称(例如来自不同的向量),但 names( get( paste( "Object" , i , sep = "." ) ) &lt;- someNewName 不像上面的示例那样工作。

get( paste( "Object" , i , sep = "." ) ) 确实返回了这些对象的名称(或NULL)。

谢谢!

【问题讨论】:

  • 对于您的具体问题,请尝试setNames。一般来说,我不知道为什么它不起作用:我期待阅读一个有启发性的答案。
  • 不要使用assign。而是将循环中创建的所有对象放入列表中。很有可能您甚至不需要 for 循环。
  • 我知道我可能不需要for 循环,这只是为了方便。老实说,调用循环来创建对象的开销很小,
  • :挥手:评估,等等等等,:更多的挥手:尝试'colnames&lt;-'(get('df'),c('A','B','C'))colnames(data.frame( P = runif(5) , Q = runif(5) , R = runif(5) )) &lt;- c('A','B','C')
  • @SimonO101 我把你的观点指向 Roland,但在我看来,使用 assignget 而不是更类似于 R 的范式 lapply 必须有一个非常令人信服的理由并使用列表。我很想知道您为什么要避免使用列表。

标签: r function syntax base replace


【解决方案1】:

以您在问题中演示的方式使用 assign 在 R 中至少不常见。通常您只需将所有对象放在一个列表中。

所以,而不是

for (i in 1:10) {
assign( paste( "Object" , i , sep = "." ) , rnorm(1000 , i) )}

你会的

objects <- list()
for (i in 1:10) {
objects[[i]] <- rnorm(1000 , i) }

事实上,这种结构非常普遍,以至于有一个(优化的)函数 (lapply),它做了类似的事情:

objects <- lapply(1:10, function(x) rnorm(1000,x))

然后您可以访问,例如,作为objects[[1]] 的第一个对象,并且有几个用于处理列表的函数。

【讨论】:

  • 几乎 +1,如果你也添加 lapply 版本,我会投赞成票。
  • +1 lapply() 是去这里的方式。它将简化代码,甚至可能比 for 循环更快,因为&lt;- 是一个相对较慢的操作。
  • @Andrie &lt;- 不算慢:重复修改复杂的数据结构很慢。 (而且我认为您不会在这里看到太大的不同,因为 IIRC [[&lt;- 是特殊情况,因此不会复制)
  • @hadley 对不起,你是对的。我应该写[&lt;- 很慢。前段时间,我通过将[&lt;- 替换为lapply,能够创建一个更快的read.fwf() 版本。我的分析可能有误,但当时这是我对rprof() 结果的解释。
  • @Andrie 如果你想更精确一点,那真的是[&lt;-.data.frame 这很慢。此外,read.fwf 是一场灾难,任何改变都可以变得更好;)
【解决方案2】:

要了解为什么这不起作用,您需要了解 colnames&lt;- 的作用。就像其中的每个函数看起来都在修改一个对象,它实际上是在修改一个副本,所以概念上 colnames(x) &lt;- y 被扩展为:

copy <- x
colnames(copy) <- y
x <- copy

如果您以通常的方式调用替换运算符,则可以写得更紧凑:

x <- `colnames<-`(x, y)

所以你的例子变成了

get("x") <- `colnames<-`(get("x"), y)

右边是有效的 R,但整个命令不是,因为你不能为函数的结果赋值:

x <- 1
get("x") <- 2
# Error in get("x") <- 2 : 
#  target of assignment expands to non-language object

【讨论】:

  • 非常感谢您对我的问题做出清晰简洁的解释。这正是我所希望的。
  • @SimonO101 稍作调整以使其更准确。 github.com/hadley/devtools/wiki/Functions 有更多详细信息(搜索“替换函数”)
  • 谢谢 hadley - 我现在要去开发工具了!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-29
  • 1970-01-01
  • 2017-06-11
相关资源
最近更新 更多