I'm fine tuning parameters for a linear support vector machine. There are multiple ways to do it, but I wanted to compare LinearSVC and SDGClassifier in terms of time. I expected the accuracy score to be the same but, even after fine tuning with GridSearchCV, the score of the LinearSVC is lower. I tried changing up parameters many times, but the maximum with LinearSVC I can get is 41.176 versus 41.503 of SDGClassifier. Why?
The code:
class SVMSentiment(Base):
"""Predict sentiment scores using a linear Support Vector Machine (SVM).
Uses a sklearn pipeline.
"""
def __init__(self, model_file: str=None) -> None:
super().__init__()
# pip install sklearn
from sklearn.feature_extraction.text import CountVectorizer, TfidfTransformer, TfidfVectorizer
from sklearn.linear_model import SGDClassifier
from sklearn.svm import SVC, LinearSVC
from sklearn.pipeline import Pipeline
self.pipeline = Pipeline(
[
('vect', CountVectorizer()),
('tfidf', TfidfTransformer()),
#('tfidf', TfidfVectorizer()),
('clf', LinearSVC( loss='hinge',
penalty='l2', max_iter = 10,
#SGDClassifier(
#loss='hinge',
# penalty='l2',
#alpha=1e-3,
# random_state=42,
#max_iter=100,
#learning_rate = 'optimal',
#tol=None
)),
]
)
def predict(self, train_file: str, test_file: str, lower_case: bool) -> pd.DataFrame:
"Train model using sklearn pipeline"
from sklearn.model_selection import GridSearchCV
from sklearn.svm import SVC
from sklearn.linear_model import SGDClassifier
from sklearn import svm
from sklearn import preprocessing
from sklearn.preprocessing import LabelEncoder, OneHotEncoder
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.svm import LinearSVC
train_df = self.read_data(train_file, lower_case)
param_range = [0.001, 0.01, 0.1, 1, 10, 100]
parameters = {
# 'vect__ngram_range': [(1, 1), (1, 2)],
'tfidf__use_idf': (True, False),
#'clf__alpha': [0.0001, 0.001, 0.01, 1, 10, 100],
'clf__max_iter': [10, 100, 1000],
'clf__tol': [0, 0.0001, 0.001, 0.01],
'clf__loss':['hinge'],
'clf__penalty': ['l2'],
'clf__C': param_range
}
parameters1 = {'clf__C': param_range, 'clf__gamma': param_range, 'clf__kernel': ['linear'], 'clf__tol' : [0, 0.01]
}
lr = LinearSVC()
print(lr.get_params().keys())
gs_clf = GridSearchCV(self.pipeline, parameters, cv=5, n_jobs=-1)
gs_clf = gs_clf.fit(train_df['text'], train_df['truth'])
print(gs_clf.best_score_)
for param_name in sorted(parameters.keys()):
print("%s: %r" % (param_name, gs_clf.best_params_[param_name]))
# estimator_svm.best_score
learner = self.pipeline.fit(train_df['text'], train_df['truth'])
# Fit the learner to the test data
test_df = self.read_data(test_file, lower_case)
test_df['pred'] = learner.predict(test_df['text'])
return test_df
best_score_
(and so the averaged k-fold cross-val score)? You're using potentially a different cv-split each time, so some variation is to be expected there. Try passing an explicit splitter (even set arandom_state
) so you're sure to be comparing the same things. Also,max_iter=10
seems awfully low; do you get convergence warnings? $\endgroup$