【问题标题】:how to access global/outer scope variable from R apply function?如何从 R 应用函数访问全局/外部范围变量?
【发布时间】:2012-11-18 09:00:09
【问题描述】:

我似乎无法让应用函数访问/修改在外部声明的变量...什么给出?

    x = data.frame(age=c(11,12,13), weight=c(100,105,110))
    x

    testme <- function(df) {
        i <- 0
        apply(df, 1, function(x) {
            age <- x[1]
            weight <- x[2]
            cat(sprintf("age=%d, weight=%d\n", age, weight))
            i <- i+1   #this could not access the i variable in outer scope
            z <- z+1   #this could not access the global variable
        })
        cat(sprintf("i=%d\n", i))
        i
    }

    z <- 0
    y <- testme(x)
    cat(sprintf("y=%d, z=%d\n", y, z))

结果:

    age=11, weight=100
    age=12, weight=105
    age=13, weight=110
    i=0
    y=0, z=0

【问题讨论】:

  • 你需要将变量传递给testme,然后传递给applytestme &lt;- function(x, z) {apply(df, 1, function(x, i, z) {}, i, z)
  • @bdemarest:这不起作用,因为i 的值将在apply 的迭代中重置(即,对于df 的每一行)。我认为 OP 想要跟踪他们在哪一行
  • @RicardoSaporta,你说的很对。可能 OP 最好不要使用apply,而是使用标准的for 循环:for (i in 1:nrow(df)) {...}。目前,我们只能猜测他/她试图解决的潜在问题。
  • 这只是一个测试片段来证明我遇到的问题 :-) 结果我应该将结果返回给调用者,即将应用调用的结果分配给另一个变量。这是一种更好的功能风格。

标签: r scope apply


【解决方案1】:

使用&lt;&lt;- 运算符,您可以写入外部范围内的变量:

x = data.frame(age=c(11,12,13), weight=c(100,105,110))
x

testme <- function(df) {
    i <- 0
    apply(df, 1, function(x) {
        age <- x[1]
        weight <- x[2]
        cat(sprintf("age=%d, weight=%d\n", age, weight))
        i <<- i+1   #this could not access the i variable in outer scope
        z <<- z+1   #this could not access the global variable
    })
    cat(sprintf("i=%d\n", i))
    i
}

z <- 0
y <- testme(x)
cat(sprintf("y=%d, z=%d\n", y, z))

这里的结果:

age=11, weight=100
age=12, weight=105
age=13, weight=110
i=3
y=3, z=3

请注意,&lt;&lt;- 的使用是危险的,因为您会破坏范围。仅在确实需要时才这样做,如果这样做,请清楚地记录该行为(至少在更大的脚本中)

【讨论】:

    【解决方案2】:

    在您的申请中尝试以下内容。试验 n 的值。我相信i 应该比z 少一。

             assign("i", i+1, envir=parent.frame(n=2))
             assign("z", z+1, envir=parent.frame(n=3))
    



    testme <- function(df) {
        i <- 0
        apply(df, 1, function(x) {
            age <- x[1]
            weight <- x[2]
            cat(sprintf("age=%d, weight=%d\n", age, weight))
    
            ## ADDED THESE LINES
             assign("i", i+1, envir=parent.frame(2))
             assign("z", z+1, envir=parent.frame(3))
    
        })
        cat(sprintf("i=%d\n", i))
        i
    }
    

    输出

    > z <- 0
    > y <- testme(x)
    age=11, weight=100
    age=12, weight=105
    age=13, weight=110
    i=3
    > cat(sprintf("y=%d, z=%d\n", y, z))
    y=3, z=3     
    

    【讨论】:

    • 我会使用assign 而不是eval(parse(...))
    • @RomanLuštrik,我最初将assign 放在答案中,然后将其编辑为eval(parse((.))。为什么你的偏好?
    • 我猜是宗教原因。请参阅fortune 上的条目。 stackoverflow.com/questions/11025031/…我想知道这个问题是否引发了@CarlWitthoft几分钟前提出的问题:stackoverflow.com/questions/13647046/…
    • @RomanLuštrik,今天肯定有不少问题。我自己added one@DWin 提出了一个很好的论点。将以上内容改回assign()
    • @RicardoSaporta eval(parse(...)) 也允许寻址列表的元素,而 assign 不支持,所以我实际上更喜欢前一个选项
    猜你喜欢
    • 2021-05-17
    • 2013-12-25
    • 1970-01-01
    • 1970-01-01
    • 2011-04-15
    • 1970-01-01
    • 2013-07-13
    • 2018-10-09
    • 1970-01-01
    相关资源
    最近更新 更多