我对以下问题感到头疼:
我在for循环中创建了两个函数,其参数依赖于某些数据帧。然后将每个函数放在一个列表中。
打印for循环内的参数表明每个函数都已明确定义。然而,当我使用循环外的那些时,只有最后一个参数用于这两个函数。以下示例应该更清楚。
dt <- data.frame(color = c("red", "blue"),
a = c(3,9),
b = c(1.3, 1.8))
function_list <- list()
for (col in dt$color) {
a <- dt$a[dt$color == col]
b <- dt$b[dt$color == col]
foo <- function(x) {
a*x^b
}
print(paste(col, foo(1)))
function_list[[col]] <- foo
}
[1]“红色3”
[1]“蓝色9”
function_list[["red"]](1)
[1] 9
function_list[["blue"]](1)
[1] 9
需要注意的是,这受到以下问题的启发:R nested for loop to write multiple functions and plot them
assign
和get
的等效解决方案有效(我对上一个问题的回答)。
答案 0 :(得分:0)
a
和b
的相关值是您调用函数时的值,而不是您定义函数时的值。您创建列表的方式是从全局环境中获取。解决方案是创建closures。我会使用Map
,但您可以使用for
循环执行相同操作:
funs <- Map(function(a, b) function(x) a*x^b, a = dt$a, b = dt$b)
print(funs)
#[[1]]
#function (x)
#a * x^b
#<environment: 0x000000000a9a4298>
#
#[[2]]
#function (x)
#a * x^b
#<environment: 0x000000000a9a3728>
请注意不同的环境。
environment(funs[[1]])$a
#[1] 3
environment(funs[[2]])$a
#[1] 9
funs[[1]](1)
#[1] 3
funs[[2]](1)
#[1] 9
答案 1 :(得分:0)
让我们检查一下您的代码无效的原因。当我尝试print(function_list)
时,您会发现存储的两个函数都将返回a*x^b
。
# Part 1 : Why it doesn't work
# --------------------------
print(function_list)
# $red
# function (x)
# {
# a * x^b
# }
#
# $blue
# function (x)
# {
# a * x^b
# }
如果您尝试删除a
并重新运行该函数,则会返回错误。
rm(a)
function_list[['red']](1)
# Error in function_list[["red"]](1) : object 'a' not found
现在关于如何使代码正常工作:
有多种方法可以使其工作,其中大部分方法都需要使用环境或更改数据结构。
管理环境的一种方法 - 以保持您的值而不是在全局环境中搜索变量的方式 - 从函数返回一个函数。
# Part 2 : How to make it work
# ----------------------------
function_list <- list()
for (col in dt$color) {
a <- dt$a[dt$color == col]
b <- dt$b[dt$color == col]
foo1 <- function(inner.a, inner.b) {
return(function(x) {inner.a*x^inner.b})
}
foo2 <- foo1(a,b)
print(paste(col, foo2(1)))
function_list[[col]] <- foo2
}
现在,如果我们检查function_list
中的内容,您可以看到这些功能在两个环境中
print(function_list)
# $red
# function (x)
# {
# inner.a * x^inner.b
# }
# <environment: 0x186fb40>
#
# $blue
# function (x)
# {
# inner.a * x^inner.b
# }
# <environment: 0x2536438>
输出也如预期。即使我们删除a
,它仍然会按预期工作。
function_list[['red']](1) # 3
function_list[['blue']](1) # 9
rm(a)
function_list[['red']](1) #[1] 3
答案 2 :(得分:0)
我认为for循环不会创建新环境(您可以在循环中通过print(environment)
进行检查),因此a
和b
的值由{{ 1}}在它们为9和1.8的全局环境中,即它们最后指定的值。