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
.
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.
This comment has been removed by the author.
ReplyDeleteErm sorry, I don't get it. The first and the second snippet are exactly the same. I reckon the proper one would be:
ReplyDeletetuneResult <- tune(svm, y ~ x, data = hellTable, ranges = list(epsilon = seq(0,1,0.1), cost = 2^(2:9)))
You're right — my bad. Thanks for pointing it out!
DeleteThank you sooooo much
ReplyDeleteThanks, I've spent 20 minutes figuring this out on my own.
ReplyDeleteDon't shadow function names by local variables!
Error in do.call(method, c(list(train.x, data = data, subset = train.ind[[sample]]), :
ReplyDelete'what' must be a function or character string
Getting this error for my code below:
svm_ <- svm(Next.Close ~ Open + High + Low + Close, train_)
predResults1_SVM <- predict(svm_, test_[,-1])
finetuned <- tune(svm, Next.Close ~ Open + High + Low + Close, data=test_[,-1],ranges=list(elsilon=seq(0,1,0.1), cost=1:100))
Notice, I am using svm for my first argument not my model
You sure you didnt assign a different object (like a data frame or vector) to the svm variable? Doing so overshadows the svm variable, but the svm() function will (probably) still work as it should.
DeleteHere's a reproducible example of what I'm talking about, using the built-in mean() function:
> test_data <- c(2,1,2,2,3,3)
>
> # This works as it should:
> mean(test_data)
[1] 2.166667
>
> # Assign string to variable mean
> mean <- "I am a string"
>
> # Printing the variable mean yields a string:
> mean
[1] "I am a string"
>
> # However, this still works:
> mean(test_data)
[1] 2.166667
R is hell.
Spent the last 60 mins. trying to resolve this.
ReplyDeleteThank you so much!!
ReplyDeleteThank you so much! This saved me a lot of time!
ReplyDeleteI'm glad this short post of mine helps people along the way still after four years!
DeleteThanks. That is also a great response for 2020! It almost solved my problem. It rather helped me realize the problem was caused by one variable (docvar) which comes with my quanteda dfmat preprocessing. I removed the docvar from the quanteda dfmat and converted it to a data frame and then to a matrix. Now, svm with hyperparameter tuning and 10-fold cv seems working. I wanted to share my experience for others who may be working on text data and are in a similar problem.
ReplyDeleteThe docvar was in column number 1, I removed it with the [,-1].
dfmat_train_matrix <- dfmat_trainnew[,-1] %>% as.data.frame() %>% as.matrix
head(dfmat_train_matrix)
## Tuned cross validation svm model
set.seed(123)
library(e1071)
svm_tuned <- tune(svm,
train.x=dfmat_train_matrix, y=test$Include,
kernel = "linear",
type = "C-classification",
ranges =list(cost=c(0.001,0.01,0.1, 1,5,10,100)),
tune.control(sampling = "cross",cross=10))
You also need to remove the docvar from the test dfmat in the same was to make the predict function work for you.