如何从 R 应用函数访问全局/外部范围变量?
Posted
技术标签:
【中文标题】如何从 R 应用函数访问全局/外部范围变量?【英文标题】:how to access global/outer scope variable from R apply function? 【发布时间】: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
,然后传递给apply
:testme <- 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)) ...
。目前,我们只能猜测他/她试图解决的潜在问题。
这只是一个测试片段来证明我遇到的问题 :-) 结果我应该将结果返回给调用者,即将应用调用的结果分配给另一个变量。这是一种更好的功能风格。
【参考方案1】:
使用<<-
运算符,您可以写入外部范围内的变量:
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
请注意,<<-
的使用是危险的,因为您会破坏范围。仅在确实需要时才这样做,如果这样做,请清楚地记录该行为(至少在更大的脚本中)
【讨论】:
【参考方案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
上的条目。 ***.com/questions/11025031/…我想知道这个问题是否引发了@CarlWitthoft几分钟前提出的问题:***.com/questions/13647046/…
@RomanLuštrik,今天肯定有不少问题。我自己added one@DWin 提出了一个很好的论点。将以上内容改回assign()
@RicardoSaporta eval(parse(...))
也允许寻址列表的元素,而 assign
不支持,所以我实际上更喜欢前一个选项以上是关于如何从 R 应用函数访问全局/外部范围变量?的主要内容,如果未能解决你的问题,请参考以下文章