Thursday, October 13, 2016

Error: "'what' must be a function or character string" when tuning svm models.

TL;DR: Pass the svm() function used to fit your svm model to tune(), not the model itself. Also, make sure you didn't overshadow the svm() function by assigning your model or any other object to the svm variable. If you do this, tune() will not recognize svm as the original svm() function, which it expects.


Here is a first post for any future person who googles this problem.

You have generated an svm model model using the svm() function from the e1071 library, like so:

data(iris)
model <- svm(Species ~ ., data = iris)

Now you want to tune your model. You decide to do it by passing it to the tune function, like so:

tuning_result <- tune(model, Species ~ ., data = iris, ranges = list(epsilon = seq(0,1,0.1), cost = 2^(2:9)))

You run the command, and R spits out the following error:

Error in do.call(method, c(list(train.x, data = data, subset = train.ind[[sample]]), : 'what' must be a function or character string

The manual for the tune function (accessed via ?tune) reveals that the first argument passed to tune should be the function you want to tune, not the model itself.

You re-run your code, like so:

tuning_result <- tune(svm, Species ~ ., data = iris,ranges = list(epsilon = seq(0,1,0.1), cost = 2^(2:9)))

And this time around it should work.


If tune(svm, Species ~ ., data = iris,ranges = list(epsilon = seq(0,1,0.1), cost = 2^(2:9))) still throws the same error, then check in your code or workspace history, that you didn't accidentally assign a different object to the variable svm.

Here is an example. If you fit a model using the svm() function, and assign it to the variable svm, the function tune() will get confused, as it sees your model assigned to svm, instead of the svm() function it expects:

We fit a model using the svm() function and assign it to the variable svm, and the try to tune svm the same way as in the previous working example.

svm <- svm(Species ~ ., data = iris)
tuning_result <- tune(svm, Species ~ ., data = iris,ranges = list(epsilon = seq(0,1,0.1), cost = 2^(2:9)))

Again, we'll get the same error as before, even though we passed svm to the tune() function:

Error in do.call(method, c(list(train.x, data = data, subset = train.ind[[sample]]), : 'what' must be a function or character string

If you overshadow the svm() function this way, tune() will not recognize svm as the svm() function.

To fix this, assign the contents of svm to a different variable, and run rm(svm), or be more explicit about which svm you're referring to, by specifying that you want to use the svm() function from the e1071 package, like so:

# This should work: tuning_result <- tune(e1071::svm, Species ~ ., data = iris,ranges = list(epsilon = seq(0,1,0.1), cost = 2^(2:9)))


2017-01-13 Edit: Fixed an error in the text (thanks to Morris for pointing it out in the comment section), and edited the text for clarity and less resignation.

2018-07-18 Edit: I rewrote the post to make it more reproducible (since y'all are still googling this), and added an example of things going wrong if you overshadow the svm() function.