2

I looked all over the website and could not get the correct answer for this dilemma:

I have an UDF for evaluating some classification models, with different datasets, and i wanted to have a single function for evaluating them. I want to have something like the following, that given the name of the model and the data, it computes some metrics (confusion matrix for example) and saves them to an object outside the function.

The problem here is that I want to create this object using the name of the model I am evaluating.

I ended up with something like this:

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)
}

Running it for Validation.func(model1,iris) We would want to get the variable stored as "Pred_Train_model1".

As model_name is not a string we had to try to convert it using the foo function (which is the answer i found in here) foo = function(x)deparse(substitute(x)) I do not get what I want, since it saves the object as: "Pred_Train_model_name" instead of "Pred_Train_model1". Does anyone know how to solve it?

6
  • 2
    Please review How to Ask and minimal reproducible example. Commented Jun 19, 2017 at 12:05
  • if model_name is not acceptable for paste, the issue isn't in assign, are you 100% sure that model_name is a string (and not for example a list containing one string etc) ? you could use debug or debugonce and try to print paste("Pred_Train_",model_name, sep='') Commented Jun 19, 2017 at 12:23
  • model_name is not acceptable because it is not a String, indeed. The problem here is that i cannot transform it into String (i tried to use the foo function but it did not work the way i thought) Commented Jun 19, 2017 at 12:30
  • 1
    @Dason It is written just after, it is the way to transform a parameter to string [foo = function(x)deparse(substitute(x))]. But it does not take the parameter that we are passing to the higher function if we try to use this method. Commented Jun 19, 2017 at 12:36
  • 1
    Are you literally putting that code in a function and then calling foo(model_name)? Just use the code found in foo (using model_name instead of x) directly to get the "name" of what was passed in. Commented Jun 19, 2017 at 12:39

2 Answers 2

3

model_name in your function must be a model object, hence cannot be used in paste function, which expects characters.

I think you want your function to know that the model object is actually called "model1" in the environment where it comes from. I think this is quite tricky attempt since your model object may be called by various names.

The easiest implementation would be to give both model object and the name separately, and the use the former for prediction and the latter for naming the outcome.

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

Another implementation, tricky but works if used with care, would be to give only the character name of the model and obtain the model object by get function from the parent environment.

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

Finally, in order to give the model object to the function and let the function to find the variable name, then you can use match.call function to recover how the function has been called.

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
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you very much!! I think the 3rd way was the one i looked for, it worked perfectly and was also easy to implement.
2

So here's a suggestion, that does not exactly solve the problem, but does make the function work.

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)

What I did is pretty much the opposite of what you were trying. I passed model_name as a string, and then evaluate it using parse(text = model_name). Note that the evaluated object is now called model_name_obj and it is passed in the predict function.

I got some errors later on in the function, but they are irrelevant to the issue at hand. They had to do with the type argument in predict and about not recognizing the confusionMatrix, because I assume I didn't load the corresponding package.

1 Comment

It really worked! I will make some additional tests, but seems like is just what i wanted. I really appreciate your help :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.