如何修复线性 SVM 的误报率?

Posted

技术标签:

【中文标题】如何修复线性 SVM 的误报率?【英文标题】:How to fix the false positives rate of a linear SVM? 【发布时间】:2014-02-20 15:40:35 【问题描述】:

我是 SVM 新手,这是我的用例:我有很多不平衡的数据要使用线性 SVM 进行二进制分类。我需要将误报率固定在某些值,并测量每个值对应的误报率。我正在使用类似以下代码的代码来使用 scikit-learn svm 实现:

# define training data
X = [[0, 0], [1, 1]]
y = [0, 1]

# define and train the SVM
clf = svm.LinearSVC(C=0.01, class_weight='auto') #auto for unbalanced distributions
clf.fit(X, y)

# compute false positives and false negatives
predictions = [clf.predict(ex) for ex in X]    
false_positives = [(a, b) for (a, b) in zip(predictions,y) if a != b and b == 0]
false_negatives = [(a, b) for (a, b) in zip(predictions,y) if a != b and b == 1] 

有没有办法使用分类器的一个参数(或几个参数),从而有效地固定测量指标?

【问题讨论】:

【参考方案1】:

class_weights 参数允许您提高或降低此误报率。让我用一个日常例子来说明它是如何工作的。假设您拥有一家夜总会,并且您在两个限制条件下运营:

    您希望尽可能多的人进入俱乐部(付费客户) 您不希望任何未成年人进入,因为这会给您带来国家麻烦

平均而言,(比如说)试图进入俱乐部的人中只有 5% 的人是未成年人。你面临着一个选择:宽容还是严格。前者将使您的利润增加多达 5%,但您面临着昂贵诉讼的风险。后者将不可避免地意味着一些刚刚超过法定年龄的人将被拒绝入境,这也会花费你的钱。您想调整宽大与严格的relative cost。注意:您无法直接控制有多少未成年人进入俱乐部,但您可以控制保镖的严格程度。

这里有一点 Python 说明,当您更改相对重要性时会发生什么。

from collections import Counter
import numpy as np
from sklearn.datasets import load_iris
from sklearn.svm import LinearSVC

data = load_iris()

# remove a feature to make the problem harder
# remove the third class for simplicity
X = data.data[:100, 0:1] 
y = data.target[:100] 
# shuffle data
indices = np.arange(y.shape[0])
np.random.shuffle(indices)
X = X[indices, :]
y = y[indices]

for i in range(1, 20):
    clf = LinearSVC(class_weight=0: 1, 1: i)
    clf = clf.fit(X[:50, :], y[:50])
    print i, Counter(clf.predict(X[50:]))
    # print clf.decision_function(X[50:])

哪些输出

1 Counter(1: 22, 0: 28)
2 Counter(1: 31, 0: 19)
3 Counter(1: 39, 0: 11)
4 Counter(1: 43, 0: 7)
5 Counter(1: 43, 0: 7)
6 Counter(1: 44, 0: 6)
7 Counter(1: 44, 0: 6)
8 Counter(1: 44, 0: 6)
9 Counter(1: 47, 0: 3)
10 Counter(1: 47, 0: 3)
11 Counter(1: 47, 0: 3)
12 Counter(1: 47, 0: 3)
13 Counter(1: 47, 0: 3)
14 Counter(1: 47, 0: 3)
15 Counter(1: 47, 0: 3)
16 Counter(1: 47, 0: 3)
17 Counter(1: 48, 0: 2)
18 Counter(1: 48, 0: 2)
19 Counter(1: 48, 0: 2)

请注意分类为0 的数据点数量是如何减少的,​​而1 类的相对权重会增加。假设您有计算资源和时间来训练和评估 10 个分类器,您可以绘制每个分类器的准确率和召回率,并得到如下图(无耻地从互联网上窃取)。然后,您可以使用它来确定 class_weights 的正确值对于您的用例是什么。

【讨论】:

@mbatchkarov 您可以随时更改分类器的决策边界。 这是我知道的一种方式,不完全确定它是否是标准方式。 @MattiLyra 描述了你可以做的另一件事,当你只训练一个模型时它会更快。【参考方案2】:

sklearn中LinearSVC的predict方法是这样的

def predict(self, X):
    """Predict class labels for samples in X.

    Parameters
    ----------
    X : array-like, sparse matrix, shape = [n_samples, n_features]
        Samples.

    Returns
    -------
    C : array, shape = [n_samples]
        Predicted class label per sample.
    """
    scores = self.decision_function(X)
    if len(scores.shape) == 1:
        indices = (scores > 0).astype(np.int)
    else:
        indices = scores.argmax(axis=1)
    return self.classes_[indices]

因此,除了mbatchkarov 的建议之外,您还可以通过更改分类器说某物属于一类或另一类的边界来更改分类器(实际上是任何分类器)做出的决定。

from collections import Counter
import numpy as np
from sklearn.datasets import load_iris
from sklearn.svm import LinearSVC

data = load_iris()

# remove a feature to make the problem harder
# remove the third class for simplicity
X = data.data[:100, 0:1] 
y = data.target[:100] 
# shuffle data
indices = np.arange(y.shape[0])
np.random.shuffle(indices)
X = X[indices, :]
y = y[indices]

decision_boundary = 0
print Counter((clf.decision_function(X[50:]) > decision_boundary).astype(np.int8))
Counter(1: 27, 0: 23)

decision_boundary = 0.5
print Counter((clf.decision_function(X[50:]) > decision_boundary).astype(np.int8))
Counter(0: 39, 1: 11)

您可以根据自己的需要优化决策边界。

【讨论】:

以上是关于如何修复线性 SVM 的误报率?的主要内容,如果未能解决你的问题,请参考以下文章

如何计算分层 K 折交叉验证的不平衡数据集的误报率?

在训练 SVM 时惩罚误报

调试 boost::thread 应用,误报率高

如何避免 SQL 查询检查 IS NULL 的误报?

训练稳健的级联分类器时要考虑的建议?

金融企业做AIOps,如何解决运维监控误报率高和时效性延迟?