避免与用户提供的变量名冲突的最佳实践 - R
Best practice to avoid conflict with user supplied variable names - R
我正在尝试为一个包创建一个 R 函数,它将获取用户数据和公式(的右侧),进行一些处理,然后 return 一个模型。但是,当用户数据或公式包含与我在内部使用的名称相同的变量时,我遇到了麻烦。一个可重现的例子,
(请注意,需要更新公式的环境以防止 R 在用户的 R_GlobalEnv 中查找我的变量 y。)
# R Version 3.6.2
my_function <- function(user_data, user_formula){
y <- as.numeric(user_data[,1] > mean(user_data[,1]))
my_formula <- update.formula(user_formula, y ~ .)
environment(my_formula) <- environment()
my_model <- lm(my_formula, data = user_data, model = TRUE)
return(my_model)
}
some_data <- data.frame(x1 = c(1,2,3,3))
some_formula <- response ~ x1
my_function(some_data, some_formula)
以上是我想要的 运行,只要 user_formula 或 user_data 中没有名为 "y" 的变量,它就可以工作。但是当 user_data 包含同名变量时,模型将使用该变量而不是我的变量。
some_data <- data.frame(x1 = c(1,2,3,3), y = c(6,7,5,6))
some_formula <- response ~ x1 + y
my_function(some_data, some_formula)$model
# y x1
# 1 6 1
# 2 7 2
# 3 5 3
# 4 6 3
# Warning messages:
# 1: In model.matrix.default(mt, mf, contrasts) :
# the response appeared on the right-hand side and was dropped
# 2: In model.matrix.default(mt, mf, contrasts) :
# problem with term 2 in model.matrix: no columns are assigned
我尝试使用 get() 强制 R 在函数的环境中搜索 y,
my_function <- function(user_data, user_formula){
y <- as.numeric(user_data[,1] > mean(user_data[,1]))
e1 <- environment()
my_formula <- update.formula(user_formula, get("y", e1) ~ .)
environment(my_formula) <- environment()
my_model <- lm(my_formula, data = user_data, model = TRUE)
return(my_model)
}
some_data <- data.frame(x1 = c(1,2,3,3), y = c(6,7,5,6))
some_formula <- response ~ x1 + y
my_function(some_data, some_formula)$model
# get("y", e1) x1 y
# 1 0 1 6
# 2 0 2 7
# 3 1 3 5
# 4 1 3 6
但是如果用户数据有一个与我的内部环境名称同名的变量,这也会失败,
some_data <- data.frame(x1 = c(1,2,3,3), y = c(6,7,5,6), e1 = c(1,2,3,4))
some_formula <- response ~ x1 + y + e1
my_function(some_data, some_formula)$model
# Error in get("y", e1) : invalid 'envir' argument
避免内部变量与用户提供的变量名称重叠的正确方法是什么?如果可能的话,我更喜欢基于 R 的方法。
Per docs of lm
,data 参数以两种方式处理公式中的变量,即不互斥:
data
an optional data frame, list or environment (or object coercible by as.data.frame
to a data frame) containing the variables in the model. If not found in data
, the variables are taken from environment(formula)
, typically the environment from which lm
is called.
具体来说,函数中计算的 y 向量与数据框中潜在的 y 列发生名称冲突。正如您注意到的以及上面文档中强调的那样,lm
将默认为 y 向量之前的 y 列。
为避免命名冲突,请考虑添加合适的占位符,例如 response 或 dependent_variable 并引发 tryCatch
如果用户提供具有相同列名的数据框,则会发出警告。这种方法还允许您避免重置 environment(formula)
.
my_function <- function(user_data, user_formula){
tryCatch({
user_data$response <- as.numeric(user_data[,1] > mean(user_data[,1]))
my_formula <- update.formula(user_formula, response ~ .)
my_model <- lm(my_formula, data = user_data, model = TRUE)
return(my_model)
}, warning = function(w) message("Please rename column 'response' in your data frame")
, error = function(e) print(e)
)
}
输出
some_data <- data.frame(x1 = c(1,2,3,3))
some_formula <- response ~ x1
my_function(some_data, some_formula)
# Call:
# lm(formula = my_formula, data = user_data, model = TRUE)
# Coefficients:
# (Intercept) x1
# -0.7273 0.5455
some_data <- data.frame(x1 = c(1,2,3,3), y = c(6,7,5,6), e1 = c(1,2,3,4))
some_formula <- response ~ x1 + y + e1
my_function(some_data, some_formula)
# Call:
# lm(formula = my_formula, data = user_data, model = TRUE)
# Coefficients:
# (Intercept) x1 y e1
# 1.667e+00 3.850e-16 -3.333e-01 3.333e-01
some_data <- data.frame(x1 = c(1,2,3,3), y = c(6,7,5,6), response=c(1,1,1,1))
some_formula <- response ~ x1 + y + response
my_function(some_data, some_formula)
# Please rename column 'response' in your data frame
我正在尝试为一个包创建一个 R 函数,它将获取用户数据和公式(的右侧),进行一些处理,然后 return 一个模型。但是,当用户数据或公式包含与我在内部使用的名称相同的变量时,我遇到了麻烦。一个可重现的例子,
(请注意,需要更新公式的环境以防止 R 在用户的 R_GlobalEnv 中查找我的变量 y。)
# R Version 3.6.2
my_function <- function(user_data, user_formula){
y <- as.numeric(user_data[,1] > mean(user_data[,1]))
my_formula <- update.formula(user_formula, y ~ .)
environment(my_formula) <- environment()
my_model <- lm(my_formula, data = user_data, model = TRUE)
return(my_model)
}
some_data <- data.frame(x1 = c(1,2,3,3))
some_formula <- response ~ x1
my_function(some_data, some_formula)
以上是我想要的 运行,只要 user_formula 或 user_data 中没有名为 "y" 的变量,它就可以工作。但是当 user_data 包含同名变量时,模型将使用该变量而不是我的变量。
some_data <- data.frame(x1 = c(1,2,3,3), y = c(6,7,5,6))
some_formula <- response ~ x1 + y
my_function(some_data, some_formula)$model
# y x1
# 1 6 1
# 2 7 2
# 3 5 3
# 4 6 3
# Warning messages:
# 1: In model.matrix.default(mt, mf, contrasts) :
# the response appeared on the right-hand side and was dropped
# 2: In model.matrix.default(mt, mf, contrasts) :
# problem with term 2 in model.matrix: no columns are assigned
我尝试使用 get() 强制 R 在函数的环境中搜索 y,
my_function <- function(user_data, user_formula){
y <- as.numeric(user_data[,1] > mean(user_data[,1]))
e1 <- environment()
my_formula <- update.formula(user_formula, get("y", e1) ~ .)
environment(my_formula) <- environment()
my_model <- lm(my_formula, data = user_data, model = TRUE)
return(my_model)
}
some_data <- data.frame(x1 = c(1,2,3,3), y = c(6,7,5,6))
some_formula <- response ~ x1 + y
my_function(some_data, some_formula)$model
# get("y", e1) x1 y
# 1 0 1 6
# 2 0 2 7
# 3 1 3 5
# 4 1 3 6
但是如果用户数据有一个与我的内部环境名称同名的变量,这也会失败,
some_data <- data.frame(x1 = c(1,2,3,3), y = c(6,7,5,6), e1 = c(1,2,3,4))
some_formula <- response ~ x1 + y + e1
my_function(some_data, some_formula)$model
# Error in get("y", e1) : invalid 'envir' argument
避免内部变量与用户提供的变量名称重叠的正确方法是什么?如果可能的话,我更喜欢基于 R 的方法。
Per docs of lm
,data 参数以两种方式处理公式中的变量,即不互斥:
data
an optional data frame, list or environment (or object coercible byas.data.frame
to a data frame) containing the variables in the model. If not found indata
, the variables are taken fromenvironment(formula)
, typically the environment from whichlm
is called.
具体来说,函数中计算的 y 向量与数据框中潜在的 y 列发生名称冲突。正如您注意到的以及上面文档中强调的那样,lm
将默认为 y 向量之前的 y 列。
为避免命名冲突,请考虑添加合适的占位符,例如 response 或 dependent_variable 并引发 tryCatch
如果用户提供具有相同列名的数据框,则会发出警告。这种方法还允许您避免重置 environment(formula)
.
my_function <- function(user_data, user_formula){
tryCatch({
user_data$response <- as.numeric(user_data[,1] > mean(user_data[,1]))
my_formula <- update.formula(user_formula, response ~ .)
my_model <- lm(my_formula, data = user_data, model = TRUE)
return(my_model)
}, warning = function(w) message("Please rename column 'response' in your data frame")
, error = function(e) print(e)
)
}
输出
some_data <- data.frame(x1 = c(1,2,3,3))
some_formula <- response ~ x1
my_function(some_data, some_formula)
# Call:
# lm(formula = my_formula, data = user_data, model = TRUE)
# Coefficients:
# (Intercept) x1
# -0.7273 0.5455
some_data <- data.frame(x1 = c(1,2,3,3), y = c(6,7,5,6), e1 = c(1,2,3,4))
some_formula <- response ~ x1 + y + e1
my_function(some_data, some_formula)
# Call:
# lm(formula = my_formula, data = user_data, model = TRUE)
# Coefficients:
# (Intercept) x1 y e1
# 1.667e+00 3.850e-16 -3.333e-01 3.333e-01
some_data <- data.frame(x1 = c(1,2,3,3), y = c(6,7,5,6), response=c(1,1,1,1))
some_formula <- response ~ x1 + y + response
my_function(some_data, some_formula)
# Please rename column 'response' in your data frame