I am working with "Forest Coverage Type" Kaggle dataset (https://www.kaggle.com/c/forest-cover-type-prediction/data) and have applied support vector machine classification to predict forest coverage type from the predictors. After I cleaned and organized the data, I split the data into a training and testing set, and then built a svm model using the following commands in R:
library("e1071")
library(caret)
library(caTools)
set.seed(100) # for reproducibility
split = sample.split(forest_cover$Cover_Type, SplitRatio=0.7)
Forestcover_train = subset(forest_cover, split==T)
# Test data will have the rest 30% of data
Forestcover_test = subset(forest_cover, split==F)
forestcover_svmfit <- svm(Cover_Type ~., data=Forestcover_train, kernel='radial', gamma=0.1, cost=10, scale=F)
confusionMatrix(data=predict(forestcover_svmfit, Forestcover_train), Forestcover_train$Cover_Type)
The resulting confusion matrix is:
Reference
Prediction 1 2 3 4 5 6 7
1 1512 0 0 0 0 0 0
2 0 1512 0 0 0 0 0
3 0 0 1512 0 0 0 0
4 0 0 0 1512 0 0 0
5 0 0 0 0 1512 0 0
6 0 0 0 0 0 1512 0
7 0 0 0 0 0 0 1512
This implies that the model is perfectly predicting the coverage type for the training data. When I apply this same model to the testing data I get very different results.
svm.pred <- predict(forestcover_svmfit, Forestcover_test)
confusionMatrix(data=svm.pred, Forestcover_test$Cover_Type)
Reference
Prediction 1 2 3 4 5 6 7
1 647 648 648 642 646 647 648
2 1 0 0 0 0 0 0
3 0 0 0 0 0 0 0
4 0 0 0 6 0 0 0
5 0 0 0 0 2 0 0
6 0 0 0 0 0 1 0
7 0 0 0 0 0 0 0
This is about 14.5% accuracy, which is just slightly better than just guessing coverage_type=1 for every sample. However, when I scale the data, the results become much more palatable.
forestcover_svmfit <- svm(Cover_Type ~., data=Forestcover_train, kernel='radial', gamma=0.1, cost=10, scale=T)
confusionMatrix(data=predict(forestcover_svmfit, Forestcover_train), Forestcover_train$Cover_Type)
Reference
Prediction 1 2 3 4 5 6 7
1 1045 294 0 0 22 0 203
2 267 870 0 0 147 14 0
3 2 32 918 69 52 280 0
4 0 2 224 1415 0 140 0
5 57 246 57 0 1226 45 4
6 12 55 313 28 65 1033 0
7 129 13 0 0 0 0 1305
And applied to the testing data:
svm.pred <- predict(forestcover_svmfit, Forestcover_test)
confusionMatrix(data=svm.pred, Forestcover_test$Cover_Type)
Reference
Prediction 1 2 3 4 5 6 7
1 487 134 0 0 7 3 21
2 111 427 9 0 24 5 1
3 0 23 504 18 8 77 0
4 0 0 30 614 0 21 0
5 16 49 10 0 605 6 0
6 0 13 95 16 4 536 0
7 34 2 0 0 0 0 626
I don't understand how these results can be so different. Presumably, the training and testing sets are simply random samples from the full dataset, so it doesn't seem plausible that the model is overfitting to the extent shown here. Given that the training and testing data are on the same scales anyway, a perfect performance with the training data should imply that it will be perform relatively well on testing data, right?
Thanks for these responses.
I am familiar with tuning the hyperparameters, and yes, in this case, I simply chose a couple values that seemed to work well. What I found bizarre was not that the classifier was overfit, which it almost certainly is given the perfect classification performance on the training data. Instead, what I found bizarre was the combination of perfect performance on the training data, and effectively completely imperfect performance on the testing data. The perfect performance on the training data implies that the model has some separating hyperplanes that can divide the data into the different classes, and that these hyperplanes are in such a form as to perfectly separate the classes for the training data. I would expect, given an overfit model, that a perfect performance on training data would yield a high rate of misclassification. However, in this case, the misclassification is all in one direction; that is, basically all the data is being classified into a single class.
I'm wondering if there is an explanation for this, or if this is simply an instance where I should accept that scaling works because the results are better...