我有9164个点,其中4303个被标记为我想要预测的类别,4861个被标记为非该类别。没有重复的点。
根据如何在sklearn中划分训练、测试和评估集?,并且由于我的dataset
是一个包含3个项目的元组(id, 向量, 标签),我做了以下操作:
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 = 9565obj = -2718.376533, rho = 0.132062nSV = 5497, nBSV = 2550Total nSV = 5497SVC(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, ... # 总共有256个坐标 67.76352596, 56.67798138, 104.89566517, 10.02616417])>>> train_labels[0]'Not Trump'>>> train_labels[1]'Trump'
回答:
scikit-learn中的大多数估计器(如SVC)在初始化时会使用多个输入参数,也称为超参数。根据你的数据,你需要弄清楚在初始化时应该传递哪些参数作为输入。如果你查看scikit-learn中的SVC文档,你会发现它可以使用多个不同的输入参数进行初始化。
为了简化,让我们考虑一下可以是’rbf’或‘linear’的kernel(还有其他几个选择);以及C,它是一个惩罚参数,你想尝试C的值0.01, 0.1, 1, 10, 100。这将导致创建和评估10个不同的可能模型。
一个简单的解决方案是编写两个嵌套的for循环,一个用于kernel,另一个用于C,创建10个可能的模型,并查看哪个模型是其他模型中最好的。然而,如果你有几个超参数需要调整,那么你必须编写几个嵌套的for循环,这可能会很繁琐。
幸运的是,scikit-learn有更好的方法来根据超参数值的不同组合创建不同的模型并选择最佳模型。为此,你使用GridSearchCV。GridSearchCV使用两个东西进行初始化:一个估计器的实例,以及一个超参数和所需值的字典。它将运行并创建所有可能的模型,给定超参数的选择,并找到最佳模型,因此你无需编写任何嵌套的for循环。这里有一个例子:
from sklearn.grid_search import GridSearchCVprint("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,它随机创建所有可能模型的一个子集(使用超参数)。如果你有很多超参数,它应该运行得更快,而且它的最佳模型通常也非常好。