【发布时间】:2020-12-01 18:16:27
【问题描述】:
假设我们有以下数据:
# simulate data to fit
set.seed(21)
y = rnorm(100)
x = .5*y + rnorm(100, 0, sqrt(.75))
我们还假设用户已经拟合了一个模型:
# user fits a lm
mod = lm(y~x)
现在假设我有一个 R 包,旨在对对象 mod 执行多项操作。为简单起见,假设我们有两个函数,一个绘制数据,一个计算系数。但是,作为中介,假设我们要对数据执行一些操作(在本例中,加十)。
例子:
# function that adds ten to all scores
add_ten = function(model) {
data = model$model
data = data + 10
return(data)
}
# functions I defined that do something to the "add_ten" dataset
plot_ten = function(model) {
new_data = data.frame(add_ten(model))
x = all.vars(formula(model))[2]
y = all.vars(formula(model))[1]
ggplot2::ggplot(new_data, aes_string(x=x, y=y)) + geom_point() + geom_smooth()
}
coefs_ten = function(model) {
new_data = data.frame(add_ten(model))
coef(lm(formula(model), new_data))
}
(显然,这样做很愚蠢。实际上,我要执行的操作是多重插补,计算量很大)。
请注意,在上面的示例中,我必须调用 add_ten 函数两次,一次用于 plot_ten,一次用于 coefs_ten。这是低效的。
那么,现在我的问题是,在函数中创建可重用对象的最佳方法是什么?
我当然可以,create an object to be placed in the user's global environment:
add_ten = function(model) {
# check for add_ten_data in the global environment
if (exists("add_ten_data", where = .GlobalEnv)) return(get("add_ten_data", envir = .GlobalEnv))
data = model$model
data = data + 10
# assign add_ten_data to the global environment
assign('add_ten_data', data, envir = .GlobalEnv)
return(data)
}
我很乐意这样做,但担心将某些东西放在用户环境中的“网络礼节”。如果用户在他们的环境中碰巧有一个名为“add_ten_data”的对象,也会有一个潜在的问题。
那么,最好的方法是什么?
提前致谢!
【问题讨论】:
-
调用
add_ten()函数一次,然后将结果传递给plot_ten和coefs_ten函数。函数不应创建全局变量,并且函数假定某些全局变量存在并不是一个好主意。 -
同意。通常认为函数是自包含的最佳实践。传入输入,并返回结果。这可以防止奇怪的行为,并使以后更容易更新代码。所以将
new_data = data.frame(add_ten(model))移到你的函数之外。然后通过传入new_data而不是传入model来运行这些函数。如果你愿意,你可以在完成后删除 new_data。 -
感谢 cmets。我希望避免在用户端采取额外的步骤,但如果不违反最佳实践,这似乎是不可避免的。