sklearn SVM的表现非常差



我有9164个点,其中4303被标记为我想要预测的类,4861被标记为不是那个类。它们没有重复点。

在sklearn中如何划分训练集、测试集和评估集?,由于我的dataset是一个包含3个项目(id, vector, label)的元组,我这样做:
df = pd.DataFrame(dataset)
train, validate, test = np.split(df.sample(frac=1), [int(.6*len(df)), int(.8*len(df))])
train_labels = construct_labels(train)
train_data = construct_data(train)
test_labels = construct_labels(test)
test_data = construct_data(test)
def predict_labels(test_data, classifier):
    labels = []
    for test_d in test_data:
        labels.append(classifier.predict([test_d]))
    return np.array(labels)
def construct_labels(df):
    labels = []
    for index, row in df.iterrows():
        if row[2] == 'Trump':
            labels.append('Atomium')
        else:
            labels.append('Not Trump')
    return np.array(labels)
def construct_data(df):
    first_row = df.iloc[0]
    data = np.array([first_row[1]])
    for index, row in df.iterrows():
        if first_row[0] != row[0]:
            data = np.concatenate((data, np.array([row[1]])), axis=0)
    return data

然后:

>>> classifier = SVC(verbose=True)
>>> classifier.fit(train_data, train_labels)
[LibSVM].......*..*
optimization finished, #iter = 9565
obj = -2718.376533, rho = 0.132062
nSV = 5497, nBSV = 2550
Total nSV = 5497
SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
  decision_function_shape=None, degree=3, gamma='auto', kernel='rbf',
  max_iter=-1, probability=False, random_state=None, shrinking=True,
  tol=0.001, verbose=True)
>>> predicted_labels = predict_labels(test_data, classifier)
>>> for p, t in zip(predicted_labels, test_labels):
...     if p == t:
...             correct = correct + 1

和我得到正确的只有943个标签的1833 (=len(test_labels)) -> (943*100/1843 = 51.4%)


我怀疑我在这里错过了一些大的时间,也许我应该设置一个参数给分类器做更精细的工作或什么?

注意:第一次在这里使用svm,所以你可能得到的任何东西都是理所当然的,我甚至可能没有想到…


尝试:

我继续把负面例子的数量减少到4303(与正面例子的数量相同)。这稍微提高了精度。


在答案后编辑:

>>> print(clf.best_estimator_)
SVC(C=1000.0, cache_size=200, class_weight='balanced', coef0=0.0,
  decision_function_shape=None, degree=3, gamma=0.0001, kernel='rbf',
  max_iter=-1, probability=False, random_state=None, shrinking=True,
  tol=0.001, verbose=False)
>>> classifier = SVC(C=1000.0, cache_size=200, class_weight='balanced', coef0=0.0,
...   decision_function_shape=None, degree=3, gamma=0.0001, kernel='rbf',
...   max_iter=-1, probability=False, random_state=None, shrinking=True,
...   tol=0.001, verbose=False)
>>> classifier.fit(train_data, train_labels)
SVC(C=1000.0, cache_size=200, class_weight='balanced', coef0=0.0,
  decision_function_shape=None, degree=3, gamma=0.0001, kernel='rbf',
  max_iter=-1, probability=False, random_state=None, shrinking=True,
  tol=0.001, verbose=False)

我还尝试了clf.fit(train_data, train_labels),其执行相同。


用数据编辑(数据不是随机的):

>>> train_data[0]
array([  20.21062112,   27.924016  ,  137.13815308,  130.97432804,
        ... # there are 256 coordinates in total
         67.76352596,   56.67798138,  104.89566517,   10.02616417])
>>> train_labels[0]
'Not Trump'
>>> train_labels[1]
'Trump'

scikit-learn中的大多数估计器(如SVC)都是由许多输入参数启动的,也称为超参数。根据您的数据,您必须确定在初始化期间将什么作为输入传递给估计器。如果您查看scikit-learn中的SVC文档,您会发现可以使用几个不同的输入参数初始化SVC。

为简单起见,让我们考虑内核,它可以是'rbf'或'线性'(在其他一些选择中);C是一个惩罚参数,你想为C尝试0.01,0.1,1,10,100的值,这将导致创建和评估10个不同的可能模型。

一个简单的解决方案是编写两个嵌套的for循环,一个用于内核,另一个用于C,并创建10个可能的模型,看看哪个是最好的模型。然而,如果你有几个超参数要调优,那么你就必须编写几个嵌套的for循环,这可能会很繁琐。

幸运的是,scikit learn有一种更好的方法,可以根据超模型的不同值组合创建不同的模型,并选择最好的模型。为此,使用GridSearchCV。GridSearchCV是用两样东西初始化的:一个估计器的实例,一个包含超参数和需要检查的值的字典。然后,它将运行并创建给定超参数选择的所有可能的模型,并找到最佳模型,因此您不需要编写任何嵌套的for循环。下面是一个例子:

from sklearn.grid_search import GridSearchCV
print("Fitting the classifier to the training set")
param_grid = {'C': [0.01, 0.1, 1, 10, 100], 'kernel': ['rbf', 'linear']}
clf = GridSearchCV(SVC(class_weight='balanced'), param_grid)
clf = clf.fit(train_data, train_labels)
print("Best estimator found by grid search:")
print(clf.best_estimator_)

您将需要使用类似于本示例的东西,并使用不同的超参数。如果你的超参数有各种各样的值,那么你很有可能用这种方法找到一个更好的模型。

然而,GridSearchCV可能需要很长时间来创建所有这些模型以找到最好的模型。更实用的方法是使用RandomizedSearchCV,它随机创建所有可能模型的子集(使用超参数)。如果您有很多超参数,它应该运行得更快,并且它的最佳模型通常非常好。

看了sascha的评论和shahins的回答后,我终于这么做了:

df = pd.DataFrame(dataset)
train, validate, test = np.split(df.sample(frac=1), [int(.6*len(df)), int(.8*len(df))])
train_labels = construct_labels(train)
train_data = construct_data(train)
test_labels = construct_labels(test)
test_data = construct_data(test)
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
train_data = scaler.fit_transform(train_data)
from sklearn.svm import SVC
# Classifier found with shahins' answer
classifier = SVC(C=10, cache_size=200, class_weight='balanced', coef0=0.0,
  decision_function_shape=None, degree=3, gamma='auto', kernel='rbf',
  max_iter=-1, probability=False, random_state=None, shrinking=True,
  tol=0.001, verbose=False)
classifier = classifier.fit(train_data, train_labels)
test_data = scaler.fit_transform(test_data)
predicted_labels = predict_labels(test_data, classifier)

,得到:

>>> correct_labels = count_correct_labels(predicted_labels, test_labels)
>>> print_stats(correct_labels, len(test_labels))
Correct labels = 1624
Accuracy = 88.5979268958

使用以下方法:

def count_correct_labels(predicted_labels, test_labels):
    correct = 0
    for p, t in zip(predicted_labels, test_labels):
        if p[0] == t:
            correct = correct + 1
    return correct
def print_stats(correct_labels, len_test_labels):
    print "Correct labels = " + str(correct_labels)
    print "Accuracy = " + str((correct_labels * 100 / float(len_test_labels)))

我能够优化更多与更多的超参数调整!

帮助链接:RBF SVM参数


注意:如果我不变换test_data,准确率为52.7%。

相关内容

  • 没有找到相关文章

最新更新