【问题标题】:Save an object in R using a function parameter as name使用函数参数作为名称在 R 中保存对象
【发布时间】:2017-06-19 11:51:07
【问题描述】:

我翻遍了整个网站,都找不到这个难题的正确答案:

我有一个 UDF 用于评估一些分类模型,具有不同的数据集,我希望有一个单独的函数来评估它们。我想要类似下面的东西,给定模型的名称和数据,它会计算一些指标(例如混淆矩阵)并将它们保存到函数外部的对象中。

这里的问题是我想使用我正在评估的模型的名称来创建这个对象。

我最终得到了这样的结果:

foo <- function(x) {return(as.character(substitute(x)))}
model1 <- lm(Sepal.Width ~ Sepal.Length, iris)

Validation.func <- function(model_name, dataset){
  Pred_Train = predict(model_name, dataset)
  assign(paste("Pred_Train_",foo(model_name), sep=''), Pred_Train, envir=globalenv())
  Pred_Train_prob = predict(model_name, dataset, type = "prob")
  MC_Train = confusionMatrix(Pred_Train, dataset$target_salto)
}

Validation.func(model1,iris) 运行它我们希望将变量存储为“Pred_Train_model1”。

由于 model_name 不是字符串,我们不得不尝试使用 foo 函数(这是我在这里找到的答案)foo = function(x)deparse(substitute(x)) 我没有得到我想要的,因为它将对象保存为:“Pred_Train_model_name ” 而不是“Pred_Train_model1”。 有人知道怎么解决吗?

【问题讨论】:

  • 如果 model_name 不能用于粘贴,问题不在分配中,您是否 100% 确定 model_name 是一个字符串(而不是例如包含一个字符串等的列表)?您可以使用debugdebugonce 并尝试打印paste("Pred_Train_",model_name, sep='')
  • model_name 是不可接受的,因为它确实不是字符串。这里的问题是我无法将其转换为字符串(我尝试使用 foo 函数,但它并没有像我想象的那样工作)
  • @Dason 后面写的,就是把参数转换成字符串[foo = function(x)deparse(substitute(x))]的方式。但是如果我们尝试使用这个方法,它不会接受我们传递给更高层函数的参数。
  • 您是否真的将代码放入函数中,然后调用foo(model_name)?直接使用foo中的代码(使用model_name而不是x)来获取传入的“名称”。

标签: r user-defined-functions


【解决方案1】:

函数中的model_name 必须是模型对象,因此不能在需要字符的paste 函数中使用。

我想你希望你的函数知道模型对象在它来自的环境中实际上被称为“model1”。我认为这是一个非常棘手的尝试,因为您的模型对象可能被各种名称调用。

最简单的实现是分别给出模型对象和名称,并使用前者进行预测,后者用于命名结果。

func1 <- function(model, model_str, dataset)
{
  p <- predict(model, dataset)
  assign(paste("predict_", model_str, sep=""), p, envir=globalenv())
}


model1 <- lm(mpg ~ cyl, data=mtcars)
func1(model1, "model1", mtcars)
predict_model1

另一种实现方式,虽然很棘手,但如果小心使用也可以,只给出模型的角色名称,并通过父环境中的get 函数获取模型对象。

func2 <- function(model_str, dataset)
{
  p <- predict(get(model_str, envir=parent.env(environment())), dataset)
  assign(paste("predict_", model_str, sep=""), p, envir=globalenv())
}

model2 <- lm(mpg ~ cyl, data=mtcars)
func2("model2", mtcars)
predict_model2

最后,为了将模型对象交给函数,让函数找到变量名,那么你可以使用match.call函数来恢复函数是如何被调用的。

func3 <- function(model, dataset)
{
  s <- match.call()
  model_str <- as.character(s)[2]
  p <- predict(model, dataset)
  assign(paste("predict_", model_str, sep=""), p, envir=globalenv())
}

model3 <- lm(mpg ~ cyl, data=mtcars)
func3(model3, mtcars)
predict_model3

【讨论】:

  • 非常感谢!!我认为第 3 种方式是我正在寻找的方式,它工作得很好,也很容易实现。
【解决方案2】:

所以这里有一个建议,它并不能完全解决问题,但确实可以使功能正常工作。

Validation.func <- function(model_name, dataset){
  model_name_obj<- eval(parse(text = model_name))   
  Pred_Train = predict(model_name_obj, dataset)
  assign(paste("Pred_Train_",model_name, sep=''), Pred_Train, envir=globalenv())
  Pred_Train_prob = predict(model_name_obj, dataset, type = "prob")
  MC_Train = confusionMatrix(Pred_Train, dataset$target_salto)
}

Validation.func("model1", data)

我所做的与您尝试的几乎相反。我将model_name 作为字符串传递,然后使用parse(text = model_name) 对其进行评估。请注意,被评估的对象现在称为 model_name_obj,并在 predict 函数中传递。

我后来在函数中遇到了一些错误,但它们与手头的问题无关。它们与predict 中的type 参数有关,以及无法识别confusionMatrix,因为我假设我没有加载相应的包。

【讨论】:

  • 真的有效!我会做一些额外的测试,但似乎正是我想要的。非常感谢您的帮助:)