【问题标题】:How to use acast (reshape2) within a function in R?如何在 R 的函数中使用 acast (reshape2)?
【发布时间】:2011-04-15 16:02:15
【问题描述】:

我尝试在自己编写的函数中使用reshape2 中的acast,但遇到了问题,即 acast 没有找到我发送给它的数据。

这是我的数据:

library("reshape2")
x <- data.frame(1:3, rnorm(3), rnorm(3), rnorm(3))    
colnames(x) <- c("id", "var1", "var2", "var3")
y <-melt(x, id = "id", measure = c("var1", "var2", "var3"))

y 然后看起来像这样:

  id variable      value
1  1     var1  0.1560812
2  2     var1  1.0343844
3  3     var1 -1.4157728
4  1     var2  0.8808935
5  2     var2  0.1719239
6  3     var2  0.6723758
7  1     var3 -0.7589631
8  2     var3  1.1325995
9  3     var3 -1.5744876

现在我可以通过acast 将其回退:

> acast(y,y[,1] ~ y[,2])
        var1      var2       var3
1  0.1560812 0.8808935 -0.7589631
2  1.0343844 0.1719239  1.1325995
3 -1.4157728 0.6723758 -1.5744876

但是,当为 acast 编写一个应该做同样事情的小包装器时,我收到一条愚蠢的错误消息:

wrap.acast <- function(dat, v1 = 1, v2 = 2) {
    out <- acast(dat, dat[,v1] ~ dat[,v2])
    return(out)
}

wrap.acast(y)

Error in eval(expr, envir, enclos) : object 'dat' not found

问题显然与环境和全局/局部变量等有关。因为它在全局环境中声明 dat 后会给出其他错误消息(即,只要它们不是全局的,就找不到 v1v2)。

我想在函数内使用 resahpe(尤其是 acast),而无需在函数外声明变量。有什么诀窍?

谢谢。

【问题讨论】:

  • 这是最近比较常见的问题。我最初发现它是 S4 方法的问题,但显然它也可能与其他功能一起出现。这应该是 R 中的一个错误,另请参阅此问题的答案:stackoverflow.com/questions/3574858/…
  • 谢谢乔里斯。但现在我的印象是,我的问题没有简单的解决方案。不太好...
  • 刚刚发现实际上有一个。这是正确类型转换的问题。

标签: r function global-variables local-variables reshape


【解决方案1】:

更正:问题不是没有找到 dat,而是在指定的公式中没有找到 dat[,v1] 和 dat[,v2]。 Acast 采用类型公式的参数,并在围绕数据框创建的临时环境中对其进行评估。在该环境中,当函数被包装在另一个对象中时,它找不到“dat”对象。

我并没有完全理解它在全局中是如何工作的,并且在包装时不会,但是如果你提供一个公式,它也确实在一个函数中工作。

wrap.acast <- function(dat, v1 = 1, v2 = 2) {
    x1 <- names(dat)[v1]
    x2 <- names(dat)[v2]
    form <- as.formula(paste(x1,"~",x2))
    out <- acast(dat,form)
    return(out)
}

使用您的玩具数据:

> wrap.acast(y)
        var1      var2       var3
1 0.04095337 0.4044572 -0.4532233
2 1.23905358 1.2493187  0.7083557
3 0.72798307 0.7868746  1.7144811

【讨论】:

  • 这就是我想要的。非常感谢。
【解决方案2】:

我发现了一种使用超级赋值 (&lt;&lt;-) 来解决问题的非常不优雅的方法。
将功能更改为以下功能即可完成工作。但是,它非常难看,因为它会创建保留的全局变量。

wrap.acast <- function(dat, v1 = 1, v2 = 2) {
    dat <<- dat
    v1 <<- v1
    v2 <<- v2
    out <- acast(dat, dat[,v1] ~ dat[,v2])
    return(out)
}

我仍然对其他(较少堵塞的)解决方案非常感兴趣。

在运行函数之前:

> ls()
[1] "wrap.acast" "x"          "y"     

运行函数后:

> ls()
[1] "dat"        "v1"         "v2"         "wrap.acast" "x"         
[6] "y" 

【讨论】:

  • 正如您自己所注意到的,应该始终避免使用超级赋值,除非您真的想创建一个全局变量。即便如此,您可能还想重新考虑这个问题......
【解决方案3】:

不要使用公式规范,而是使用字符规范:

acast(y, list(names(y)[1], names(y)[2]))

【讨论】:

  • 那就更简单了。非常感谢。更感谢你提供 reshape2 和你所有的好包!
【解决方案4】:

一个问题是您滥用 R 中的公式表示法。您不应该这样做

> acast(y, y[,1] ~ y[,2])
        var1       var2         var3
1  2.1726117  0.6107264  0.291446236
2  0.4755095 -0.9340976 -0.443291873
3 -0.7099464 -1.2536334  0.001105352

因为如果提供了数据对象,'y' 位是冗余的。如果你直接在公式中按名称引用 y 的变量,事情就很好了

> acast(y, id ~ variable)
        var1       var2         var3
1  2.1726117  0.6107264  0.291446236
2  0.4755095 -0.9340976 -0.443291873
3 -0.7099464 -1.2536334  0.001105352

第二个版本的代码可读性更高。

正如 Joris 所指出的,要使用 acast 包装器执行您想要的操作,需要使用 names 生成正确的公式,而 Hadley 的解决方案要简单得多。所以我的意思是要注意你如何在 R 中使用公式规范。如果你正确使用公式,从长远来看,你会为自己省去很多麻烦(尽管不是专门针对这个特定问题)。

【讨论】:

    猜你喜欢
    • 2015-02-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-04
    • 1970-01-01
    • 2011-06-17
    • 1970-01-01
    相关资源
    最近更新 更多