Solved – Efficient way to evaluate an SVM classifier

machine learningpythonsvm

I coded an SVM classifier which is giving good accuracy most of the times. To be sure of its performance, I'm generating 100 different train and test sets out of my dataset and applying my classifier on each pair of train and test sets and computing the accuracy. Then the accuracy is stored in a list. After the 100th iteration I'm computing the mean, median, mode of all of the 100 accuracy values.In each of 100 iterations I'm applying cross validation to find the best value for the Regularization parameter from a defined range of values. Here's the code:

accuracy = []
for i in range(0, 100): #iterates through the dataset 100 times

    #prtitions the data into train and test
    data_train, data_test, label_train, label_test = train_test_split(data_data, data_label, test_size=0.3)
    print(len(data_train))
    print(len(label_test))
    print('--------------------------------------------')
    print(data_train.head())
    print('--------------------------------------------')
    print(data_test.head())
    print('--------------------------------------------')
    print(label_train.head())
    print('--------------------------------------------')
    print(label_test.head())
    print('--------------------------------------------')

    c_s = list(np.arange(.01, 2, 0.01)) #range for the optimum val of regularization parameter

    #perform k fold cross validation 
    MSE = []
    cv_scores = []
    training_scores = []

    for c in c_s:
        clf = svm.SVC(C = c, decision_function_shape='ovo', kernel = 'linear')
        scores = cross_val_score(clf, data_train, label_train, cv=20, scoring='accuracy')                           
        #score() returns the mean accuracy on the given test data and labels
        scores_training = clf.fit(data_train, label_train).score(data_train, label_train)

        cv_scores.append(scores.mean())
        training_scores.append(scores_training)

    #changing to misclassification error
    MSE = [1 - x for x in cv_scores]  

    #determining best C
    optimal_c = c_s[MSE.index(min(MSE))]
    print('\nThe optimal value of C for accuracy is %f' % optimal_c)

    #print("the misclassification error for each C value is : ", np.round(MSE,5))
    #plot misclassification error vs C
    plt.plot(c_s, MSE)
    plt.xlabel('C(Regularization Parameter)')
    plt.ylabel('Misclassification Error')
    plt.show()

    #plot cross-validated score, training score vs C
    #print(cv_scores)
    #print(training_scores)
    plt.plot(c_s, cv_scores, 'r', label='Validation')
    plt.plot(c_s, training_scores, 'b', label='Train')
    plt.xlabel('C(Regularization Parameter)')
    plt.ylabel('Score')
    plt.legend(['validation', 'train'], loc='upper left')
    plt.show()
    print('--------------------------------------------------')

    clf = svm.SVC(C=optimal_c, decision_function_shape='ovo', kernel = 'linear') #classifier with the optimum value for the regularization parameter
    print(clf)
    print('--------------------------------------------------')
    clf.fit(data_train, label_train)

    # save the model to disk
    filename = 'finalized_model.sav'
    pickle.dump(clf, open(filename, 'wb'))

    print('--------------------------------------------------')
    # loads the model from disk

    loaded_model = pickle.load(open('finalized_model.sav', 'rb'))
    category_predicted = loaded_model.predict(data_test)
    #print(category_predicted)
    #print('--------------------------------------------------')
    acc = accuracy_score(label_test, category_predicted) * 100
    #print(acc)
    accuracy.append(acc)

print('--------------------------------------------------')    
print(accuracy) #the list which stores the all of 100 values of accuracy
print(len(accuracy))
print('--------------------------------------------------') 
print("Mean accuracy : {}".format(np.mean(accuracy)))
print("Median accuracy : {}".format(np.median(accuracy)))
print("Mode accuracy : {}".format(stats.mode(accuracy)))

Output for 100th iteration and the subsequent code:

280
120
--------------------------------------------
          0       1       2       3       4       5       6
342   43.38   82.49  275.93  193.62  136.89   52.72  114.76
191   99.24  208.31  737.37  728.50  257.96   93.20   84.19
231   76.72   54.29  200.74  155.35   48.39   53.42   95.93
228  118.43   75.12  288.13  235.81   59.40   57.87   95.92
143  462.30   89.70   84.60   85.88   81.44  237.38  255.60
--------------------------------------------
          0       1       2       3       4       5       6
129  551.31  103.94   91.86   59.05   62.79  154.05  188.08
75    19.47   27.99   84.84   52.16   40.02   27.32   22.96
9    339.38  509.56  200.26  608.46  462.07  177.77  394.43
77    19.83   25.19   54.61   45.43   41.71   27.79   22.59
76    20.29   26.75   83.72   61.73   42.71   28.99   23.30
--------------------------------------------
342    7
191    4
231    5
228    5
143    3
Name: 7, dtype: int64
--------------------------------------------
129    3
75     2
9      1
77     2
76     2
Name: 7, dtype: int64
--------------------------------------------

The optimal value of C for accuracy is 0.010000

[![enter image description here][1]][1]

[![enter image description here][1]][1]

--------------------------------------------------
SVC(C=0.01, cache_size=200, class_weight=None, coef0=0.0,
  decision_function_shape='ovo', degree=3, gamma='auto', kernel='linear',
  max_iter=-1, probability=False, random_state=None, shrinking=True,
  tol=0.001, verbose=False)
--------------------------------------------------
--------------------------------------------------
--------------------------------------------------
[97.5, 98.33333333333333, 96.66666666666667, 97.5, 95.83333333333334, 95.83333333333334, 98.33333333333333, 99.16666666666667, 99.16666666666667, 99.16666666666667, 97.5, 96.66666666666667, 96.66666666666667, 97.5, 95.0, 98.33333333333333, 96.66666666666667, 95.83333333333334, 98.33333333333333, 98.33333333333333, 96.66666666666667, 95.83333333333334, 99.16666666666667, 97.5, 99.16666666666667, 96.66666666666667, 99.16666666666667, 97.5, 97.5, 100.0, 98.33333333333333, 96.66666666666667, 97.5, 96.66666666666667, 96.66666666666667, 95.83333333333334, 96.66666666666667, 96.66666666666667, 96.66666666666667, 97.5, 100.0, 98.33333333333333, 98.33333333333333, 98.33333333333333, 95.83333333333334, 98.33333333333333, 97.5, 96.66666666666667, 100.0, 97.5, 97.5, 97.5, 98.33333333333333, 99.16666666666667, 96.66666666666667, 97.5, 97.5, 98.33333333333333, 96.66666666666667, 97.5, 97.5, 95.83333333333334, 97.5, 97.5, 98.33333333333333, 96.66666666666667, 98.33333333333333, 97.5, 99.16666666666667, 95.83333333333334, 97.5, 98.33333333333333, 96.66666666666667, 97.5, 99.16666666666667, 99.16666666666667, 95.83333333333334, 100.0, 98.33333333333333, 96.66666666666667, 97.5, 96.66666666666667, 95.83333333333334, 96.66666666666667, 97.5, 96.66666666666667, 98.33333333333333, 95.83333333333334, 97.5, 98.33333333333333, 98.33333333333333, 96.66666666666667, 99.16666666666667, 97.5, 98.33333333333333, 95.0, 97.5, 96.66666666666667, 96.66666666666667]
99
--------------------------------------------------
Mean accuracy : 97.51683501683499
Median accuracy : 97.5
Mode accuracy : ModeResult(mode=array([97.5]), count=array([27])) 

Now my questions are:

  1. Is this the right way to evaluate a classifier? If not, what should I do?

  2. For each of the 100 iterations of the loop it finds the best value of regularization parameter from a range of values which is time consuming. So the time complexity of the entire procedure is high. How to tackle that or should I continue with this procedure?

Best Answer

To assess the accuracy of your SVM for your particular dataset use the bootstrap technique.

Sample with replacement from your training data (performing CV on the sample if you wish to find the optimal hypers) $n$ times (1000 is great, but do what you can) and then evaluate on your testing (all of it, no sampling). Order the results and take the middle $x$% for an $x$% confidence interval.

By the way if you want to make robust predictions save your $n$ models and take their average to obtain a prediction. This technique is known as bagging and can be shown to monotonically increase accuracy.

If you have a large dataset you may want to use a method not bounded cubically by the number of samples (IE a linear SVM or gradient boosting, neural network, etc.)

Related Question