如何使用scikit-learn和matplotlib绘制不平衡数据集的SVC分类?

时间:2015-02-12 05:44:08

标签: machine-learning nlp artificial-intelligence scikit-learn svm

我有一个文本分类任务,包含2599个文档和5个标签,从1到5.文档是

label | texts
----------
5     |1190
4     |839
3     |239
1     |204
2     |127

所有人都准备好将这些文本数据分类为非常低的性能,并且还会收到有关定义不明确的指标的警告:

Accuracy: 0.461057692308

score: 0.461057692308

precision: 0.212574195636

recall: 0.461057692308

  'precision', 'predicted', average, warn_for)
 confussion matrix:
[[  0   0   0   0 153]
  'precision', 'predicted', average, warn_for)
 [  0   0   0   0  94]
 [  0   0   0   0 194]
 [  0   0   0   0 680]
 [  0   0   0   0 959]]

 clasification report:
             precision    recall  f1-score   support

          1       0.00      0.00      0.00       153
          2       0.00      0.00      0.00        94
          3       0.00      0.00      0.00       194
          4       0.00      0.00      0.00       680
          5       0.46      1.00      0.63       959

avg / total       0.21      0.46      0.29      2080

显然,这是因为我有一个不平衡的数据集,所以我发现这个paper作者提出了几个方法来处理这个问题:

  

问题在于,对于不平衡的数据集,学习的边界是   太接近积极的情况。我们需要以某种方式偏向SVM   将推动边界远离正面实例。 Veropoulos等   [14]建议使用不同的误差成本(C +)和   负(C - )类

我知道这可能非常复杂,但是SVC提供了几个超参数,所以我的问题是:有没有办法偏离SVC的方式使用提供SVC分类器的超参数推动边界远离可能的实例? 。我知道这可能是一个困难的问题,但欢迎任何帮助,先谢谢你们。

from sklearn.feature_extraction.text import TfidfVectorizer
import numpy as np
tfidf_vect= TfidfVectorizer(use_idf=True, smooth_idf=True, sublinear_tf=False, ngram_range=(2,2))
from sklearn.cross_validation import train_test_split, cross_val_score

import pandas as pd
df = pd.read_csv('/path/of/the/file.csv',
                     header=0, sep=',', names=['id', 'text', 'label'])



reduced_data = tfidf_vect.fit_transform(df['text'].values)
y = df['label'].values



from sklearn.decomposition.truncated_svd import TruncatedSVD
svd = TruncatedSVD(n_components=5)
reduced_data = svd.fit_transform(reduced_data)

from sklearn import cross_validation
X_train, X_test, y_train, y_test = cross_validation.train_test_split(reduced_data,
                                                    y, test_size=0.33)

#with no weights:

from sklearn.svm import SVC
clf = SVC(kernel='linear', class_weight={1: 10})
clf.fit(reduced_data, y)
prediction = clf.predict(X_test)

w = clf.coef_[0]
a = -w[0] / w[1]
xx = np.linspace(-5, 5)
yy = a * xx - clf.intercept_[0] / w[1]


# get the separating hyperplane using weighted classes
wclf = SVC(kernel='linear', class_weight={1: 10})
wclf.fit(reduced_data, y)

ww = wclf.coef_[0]
wa = -ww[0] / ww[1]
wyy = wa * xx - wclf.intercept_[0] / ww[1]

# plot separating hyperplanes and samples
import matplotlib.pyplot as plt
h0 = plt.plot(xx, yy, 'k-', label='no weights')
h1 = plt.plot(xx, wyy, 'k--', label='with weights')
plt.scatter(reduced_data[:, 0], reduced_data[:, 1], c=y, cmap=plt.cm.Paired)
plt.legend()

plt.axis('tight')
plt.show()

但我一无所获,我无法理解发生了什么,这就是情节:

weighted vs normal

然后:

#Let's show some metrics[unweighted]:
from sklearn.metrics.metrics import precision_score, \
    recall_score, confusion_matrix, classification_report, accuracy_score
print '\nAccuracy:', accuracy_score(y_test, prediction)
print '\nscore:', clf.score(X_train, y_train)
print '\nrecall:', recall_score(y_test, prediction)
print '\nprecision:', precision_score(y_test, prediction)
print '\n clasification report:\n', classification_report(y_test, prediction)
print '\n confussion matrix:\n',confusion_matrix(y_test, prediction)

#Let's show some metrics[weighted]:
print 'weighted:\n'

from sklearn.metrics.metrics import precision_score, \
    recall_score, confusion_matrix, classification_report, accuracy_score
print '\nAccuracy:', accuracy_score(y_test, prediction)
print '\nscore:', wclf.score(X_train, y_train)
print '\nrecall:', recall_score(y_test, prediction)
print '\nprecision:', precision_score(y_test, prediction)
print '\n clasification report:\n', classification_report(y_test, prediction)
print '\n confussion matrix:\n',confusion_matrix(y_test, prediction)

这是我使用的data。我怎样才能解决这个问题并以正确的方式绘制这个问题?先谢谢你们!。

从这个问题的答案中我删除了这一行:

#
# from sklearn.decomposition.truncated_svd import TruncatedSVD
# svd = TruncatedSVD(n_components=5)
# reduced_data = svd.fit_transform(reduced_data)


#
# w = clf.coef_[0]
# a = -w[0] / w[1]
# xx = np.linspace(-10, 10)
# yy = a * xx - clf.intercept_[0] / w[1]

# ww = wclf.coef_[0]
# wa = -ww[0] / ww[1]
# wyy = wa * xx - wclf.intercept_[0] / ww[1]
#
# # plot separating hyperplanes and samples
# import matplotlib.pyplot as plt
# h0 = plt.plot(xx, yy, 'k-', label='no weights')
# h1 = plt.plot(xx, wyy, 'k--', label='with weights')
# plt.scatter(reduced_data[:, 0], reduced_data[:, 1], c=y, cmap=plt.cm.Paired)
# plt.legend()
#
# plt.axis('tight')
# plt.show()

This where the results:

Accuracy: 0.787878787879

score: 0.779437105112

recall: 0.787878787879

precision: 0.827705441238

此指标有所改善。 如何绘制此结果以获得类似文档的一个很好的示例。我想看看这两个超平面的行为吗?。谢谢你们!

5 个答案:

答案 0 :(得分:4)

使用5

将数据缩减为SVD个功能
svd = TruncatedSVD(n_components=5)
reduced_data = svd.fit_transform(reduced_data)

你丢失了很多信息。只需删除这些行,我就会获得78%准确度。

在设置时保留class_weight参数似乎比删除它更好。我没有试过给它其他价值。

使用k-fold cross validationgrid search调整模型的参数。如果要减少数据的维度,也可以使用pipeline,以便在不影响性能的情况下计算出减少数量的程度。 Here是一个示例,演示了如何使用网格搜索调整整个管道。

对于绘图,您只能绘制2d或3d数据。使用更多尺寸进行训练后,您可以将数据减少到2或3维并绘制出来。有关绘图示例,请参阅here。代码看起来与您正在绘制的内容类似,我得到的结果与您的相似。问题是您的数据具有许多功能,您只能将事物绘制到2d或3d曲面。这通常会使它看起来很奇怪而且很难分辨出发生了什么。

我建议你不要打扰绘图,因为它不会告诉你很多高维数据。使用k-fold交叉验证和网格搜索以获得最佳参数,如果您想更深入地研究过度拟合,请改为绘制learning curves

所有这些结合将告诉您更多关于模型行为的信息,而不是绘制超平面。

答案 1 :(得分:2)

如果我理解你的输入正确,你有:

5个标签文本中的1190个 1-4个标记文本中的1409个

您可以尝试进行后续分类。首先威胁所有5个标签为1,所有其他标签为0.为该任务训练分类器

其次,从数据集中删除所有5个示例。训练分类器以对1-4个标签进行分类。

分类后运行第一个分类器,如果返回0 - 运行第二个分类器以获得最终标签。

虽然我不认为这种分布确实是偏斜和不平衡的(它应该像5%的10%,10% - 所有其余部分,实际上是偏斜的,因此向SVC引入偏见可能会很有趣)。因此,我认为您可能想尝试其他分类算法,因为看起来您的选择不适合此任务。或者你可能需要在你的SVC上使用不同的内核(我假设你使用线性内核,尝试不同的东西 - 可能是RBF或多项式)。

答案 2 :(得分:2)

作为一个简单的解决方案,只需在较小的类中乘以实例并平衡实例数。这甚至看起来很愚蠢,并且在钻机配置中不需要。

使用这种方法的想法是模仿每个类关于其类大小的缩放学习率的行为。也就是说,在基于梯度的优化方法中,您应该将学习速率与每个类的类大小成反比,这样您就可以防止模型过度抛弃某些类而不是其他类。

如果您的问题非常大并且您正在使用批量更新,那么不要预订所有数据集和计数类,而是仅考虑小批量并动态调整学习率,以了解小批量中每个类的实例数量。

这意味着如果您的主要学习率为0.01,并且在一批实例中,您有0.4个A类,其中0.6个为B类,那么对于每个课程,您需要将最终学习率调整为A类的主要学习率(这意味着保持相同),B类的2/3 * master_learning率。因此,对于A类而言,你的步幅更大,而对于B类,你则相反。

我的选择,特别是对于大型问题,通过复制实例或作为更强大的选择来增加较小类的数据,为复制的实例添加一些噪音和差异。通过这种方式,(根据您的问题),您还可以训练一个对小变化更稳健的模型(这对于特别是图像分类问题非常常见。)。

答案 3 :(得分:2)

您可能已尝试将class-weight设置为auto,但我想检查一下。

也许平衡实验(oversampling or undersampling)可以提供帮助,klubow已经建议了一些lib。

答案 4 :(得分:1)