将LinearSVC的决策函数转换为概率(Scikit learn python)

53
我使用scikit-learn中的线性SVM(LinearSVC)解决二分类问题。我知道LinearSVC可以给出预测标签和决策得分,但我想要概率估计(标签的置信度)。我想继续使用LinearSVC因为它比带有线性核的sklearn.svm.SVC速度更快。将决策得分转换为概率估计是否可行,例如使用逻辑函数?
import sklearn.svm as suppmach
# Fit model:
svmmodel=suppmach.LinearSVC(penalty='l1',C=1)
predicted_test= svmmodel.predict(x_test)
predicted_test_scores= svmmodel.decision_function(x_test) 

我想检查使用 [1 / (1 + exp(-x))] 来获取概率估计是否有意义,其中x是决策得分。

或者,是否有其他关于分类器的选项可以高效地实现这一点?

谢谢。

5个回答

133
scikit-learn提供了CalibratedClassifierCV,可以用来解决这个问题:它允许将概率输出添加到LinearSVC或任何其他实现decision_function方法的分类器中。
svm = LinearSVC()
clf = CalibratedClassifierCV(svm) 
clf.fit(X_train, y_train)
y_proba = clf.predict_proba(X_test)

用户指南在那方面有很好的部分。默认情况下,CalibratedClassifierCV+LinearSVC将为您提供Platt缩放,但它还提供其他选项(等距回归方法),并且不仅限于SVM分类器。


1
有没有想法如何在网格搜索中使用它?尝试设置参数,例如 base_estimator__C,但是 GridSearchCV 不接受。 - Stefan Falk
1
base_estimator__C 看起来是正确的。我建议提供一个完整的例子并在 Stack Overflow 上开一个新的问题。 - Mikhail Korobov
当我拟合clf时,它会导致错误,无法拟合到svm。因此我必须对两者进行训练。我认为这不会改变什么。这样正确吗? - Mattia Ducci
1
哦,我的天啊,这快多了(而且在我的情况下性能相似)。 - arno_v

18

我查看了sklearn.svm.*系列中的API。以下所有模型,例如:

  • sklearn.svm.SVC
  • sklearn.svm.NuSVC
  • sklearn.svm.SVR
  • sklearn.svm.NuSVR

都有一个共同的接口,提供了

probability: boolean, optional (default=False) 

参数设置为True时,libsvm将基于Platt Scaling的想法,在SVM输出之上训练概率转换模型。转换形式类似于逻辑函数,但是需要在后处理步骤中学习两个特定的常数AB。详情请参见stackoverflow帖子。

enter image description here

实际上我不知道为什么这种后处理方法不适用于LinearSVC。否则,您只需调用predict_proba(X)即可获得概率估计。

当然,如果您只应用朴素的逻辑变换,那么它的表现不会像Platt Scaling这样经过校准的方法那么好。如果您能理解Platt Scaling的底层算法,可能可以编写自己的算法或者贡献给scikit-learn SVM系列。:)


1
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - chet
4
这段话的意思是因为LinearSVC已经实现了逻辑回归(LogisticRegression),所以Liblinear中没有内置它,同时线性支持向量机加上Platt缩放可能比直接使用逻辑回归要更好,但我从未尝试过。在SVC中的Platt缩放来自于LibSVM。 - Fred Foo
另一个可能的问题是使用LinearSVC允许选择不同于默认“l2”的惩罚。由于LibSVM不允许,因此SVC不允许这样做。 - Eran
我同时使用了 SVC(kernel='linear', **kwargs)CalibratedClassifier(LinearSVC(**kwargs)),但是得到了不同的结果... - irene

15
如果想要速度,只需使用sklearn.linear_model.LogisticRegression替换SVM即可。它使用与LinearSVC完全相同的训练算法,但是它使用的是log-loss而不是hinge loss。
在形式上产生概率(介于零和一之间的数字)时,使用[1 /(1 + exp(-x))],但它们不遵循任何可证明的概率模型。

这很有道理。谢谢你的澄清。 - chet
4
这应该是真正的答案。我用sklearn.linear_model.LogisticRegression替换了我的sklearn.svm.SVC,不仅获得了类似的ROC曲线,而且在我的数据集上时间差异非常大(秒级对比小时级),甚至不值得使用timeit。另外值得注意的是,您可以将求解器指定为“liblinear”,这将使其与LinearSVC完全相同。 - thefourtheye
在方程[1 / (1 + exp(-x))]中,x的值是多少? - Sakib
7
我认为这不是一个适当的解决方案,就像Fred所指出的那样,用SVM来获取概率。LR旨在通过逻辑函数对独立信号进行概率估计。SVM旨在提供更好的准确性并尝试避免过度拟合,但您将获得的概率估计值通过hinge函数会更不准确。它会惩罚错误预测。读者们,请理解权衡并为您的学习目标选择最适合的函数。我个人选择LinearSVC+CalibratedClassifierCV。 - ldmtwo
@thefourtheye:LinearSVC 表示:“与参数 kernel=’linear’ 的 SVC 类似,但是它是基于 liblinear 而不是 libsvm 实现的,因此在选择惩罚和损失函数方面具有更大的灵活性,并且应该能够更好地扩展到大量样本。”因此,如果您使用了 LinearSVC(就像 OP 一样),您将使用 liblinear(就像您的 LogisticRegression 一样),并且它也会很快。因此,使其快速的不是方法本身,而是您使用了错误的实现后端。 - Make42
@Fred:首先,如果您使用相同的算法,但不同的损失函数,那么您将得到一个差异-所以,不,它们不是相同的。其次,概率不仅仅是“介于零和一之间的数字”,因此,如果您的建议不“符合任何可证明的概率模型”,那么它就不是概率(在正式意义上或其他任何意义上)。它只是介于零和一之间的数字。然而,您也错了,它确实符合任何可证明的概率模型-它确实符合(https://www.youtube.com/watch?v=BfKanl1aSG0)-因此,它确实是概率。 - Make42

3
如果您需要的是置信度而不是实际概率,您可以使用方法LinearSVC.decision_function()。请参阅文档

0

就像对于二元分类使用SVM的扩展一样:您也可以看一下SGDClassifier,它默认使用梯度下降和SVM。为了估计二元概率,它使用修改后的huber loss

(clip(decision_function(X), -1, 1) + 1) / 2)

一个例子看起来像这样:

from sklearn.linear_model import SGDClassifier
svm = SGDClassifier(loss="modified_huber") 
svm.fit(X_train, y_train)
proba = svm.predict_proba(X_test)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接