【问题标题】:Scikit Learn SVC decision_function and predictScikit 学习 SVC 决策函数和预测
【发布时间】:2013-12-05 11:09:18
【问题描述】:

我试图了解 decision_function 和 predict 之间的关系,它们是 SVC 的实例方法 (http://scikit-learn.org/stable/modules/generated/sklearn.svm.SVC.html)。到目前为止,我已经收集到决策函数返回类之间的成对分数。我的印象是 predict 选择了最大化其成对分数的类,但我对此进行了测试并得到了不同的结果。这是我用来尝试理解两者之间关系的代码。首先我生成了成对分数矩阵,然后我打印出了与 clf.predict 预测的类不同的最大成对分数的类。

        result = clf.decision_function(vector)[0]
        counter = 0
        num_classes = len(clf.classes_)
        pairwise_scores = np.zeros((num_classes, num_classes))
        for r in xrange(num_classes):
            for j in xrange(r + 1, num_classes):
                pairwise_scores[r][j] = result[counter]
                pairwise_scores[j][r] = -result[counter]
                counter += 1

        index = np.argmax(pairwise_scores)
        class = index_star / num_classes
        print class
        print clf.predict(vector)[0]

有人知道这些 predict 和 decision_function 之间的关系吗?

【问题讨论】:

  • “决策函数返回类之间的成对分数”不正确。它应该是“每个类的分数”,因为它在decision_function 部分的文档页面中编写:“样本 X 到分离超平面的距离。”
  • @justhalf:不,OP 是正确的。 sklearn.svm.SVC 默认使用成对(一对一)分解,并返回每个样本到所有 n(n-1)/2 个超平面的距离。
  • 哎呀,是的,我记得在某处读过它。但被文档误导了。对不起!
  • 尝试回答后,我认为bcorso的回答应该是那个。这种关系实际上是基于他从 C++ 实现中翻译的代码:decision = decision_function(params, sv, nv, a, b, X); votes = [(i if decision[p] > 0 else j) for p,(i,j) in enumerate((i,j) for i in range(len(cs)) for j in range(i+1,len(cs)))]votes 的最高票数基本上是 predict 所做的。

标签: python numpy svm scikit-learn


【解决方案1】:

我不完全理解您的代码,但让我们看一下您引用的文档页面的示例:

import numpy as np
X = np.array([[-1, -1], [-2, -1], [1, 1], [2, 1]])
y = np.array([1, 1, 2, 2])
from sklearn.svm import SVC
clf = SVC()
clf.fit(X, y) 

现在让我们对样本应用决策函数和预测:

clf.decision_function(X)
clf.predict(X)

我们得到的输出是:

array([[-1.00052254],
       [-1.00006594],
       [ 1.00029424],
       [ 1.00029424]])
array([1, 1, 2, 2])

这很容易解释:desion 函数告诉我们我们在分类器生成的超平面的哪一侧(以及我们离它有多远)。根据该信息,估计器然后用相应的标签标记示例。

【讨论】:

  • 这很容易解释,因为这是一个二进制示例。在多类情况下,SVC.decision_function 变得更加复杂。
【解决方案2】:

对于那些感兴趣的人,我将发布一个从 C++ (here) 转换为 python 的 predict 函数的快速示例:

# I've only implemented the linear and rbf kernels
def kernel(params, sv, X):
    if params.kernel == 'linear':
        return [np.dot(vi, X) for vi in sv]
    elif params.kernel == 'rbf':
        return [math.exp(-params.gamma * np.dot(vi - X, vi - X)) for vi in sv]

# This replicates clf.decision_function(X)
def decision_function(params, sv, nv, a, b, X):
    # calculate the kernels
    k = kernel(params, sv, X)

    # define the start and end index for support vectors for each class
    start = [sum(nv[:i]) for i in range(len(nv))]
    end = [start[i] + nv[i] for i in range(len(nv))]

    # calculate: sum(a_p * k(x_p, x)) between every 2 classes
    c = [ sum(a[ i ][p] * k[p] for p in range(start[j], end[j])) +
          sum(a[j-1][p] * k[p] for p in range(start[i], end[i]))
                for i in range(len(nv)) for j in range(i+1,len(nv))]

    # add the intercept
    return [sum(x) for x in zip(c, b)]

# This replicates clf.predict(X)
def predict(params, sv, nv, a, b, cs, X):
    ''' params = model parameters
        sv = support vectors
        nv = # of support vectors per class
        a  = dual coefficients
        b  = intercepts 
        cs = list of class names
        X  = feature to predict       
    '''
    decision = decision_function(params, sv, nv, a, b, X)
    votes = [(i if decision[p] > 0 else j) for p,(i,j) in enumerate((i,j) 
                                           for i in range(len(cs))
                                           for j in range(i+1,len(cs)))]

    return cs[max(set(votes), key=votes.count)]

predictdecision_function 有很多输入参数,但请注意,这些都是模型在调用predict(X) 时在内部使用的。事实上,在拟合之后,您可以在模型中访问所有参数:

# Create model
clf = svm.SVC(gamma=0.001, C=100.)

# Fit model using features, X, and labels, Y.
clf.fit(X, y)

# Get parameters from model
params = clf.get_params()
sv = clf.support_vectors
nv = clf.n_support_
a  = clf.dual_coef_
b  = clf._intercept_
cs = clf.classes_

# Use the functions to predict
print(predict(params, sv, nv, a, b, cs, X))

# Compare with the builtin predict
print(clf.predict(X))

【讨论】:

  • 嘿!谢谢你的回答。但是,我尝试了您的解决方案,结果却不同...
  • 嗨,bcorso !感谢您的回答,但正如@lilouch 指出的那样,我无法获得相同的值。决策函数描述为$\langle \mathbf{w},\mathbf{x} \rangle + b$,这个值对于正类必须大于1,对于负类必须小于-1。问题是我无法弄清楚你如何在新示例和超平面向量之间进行点积。你能帮帮我吗?
  • sklearn好像有两对互补的dual_coef和intercept,把a = clf.dual_coef_改成a = clf._dual_coef_decision_function的输出和clf._decision_function一样,predict的结果也符合clf.predict
【解决方案3】:

datascience.sx 上有一个really nice Q&A 用于多类一对一场景:

问题

我有一个带有标签“A”、“B”、“C”、“D”的多类 SVM 分类器。

这是我正在运行的代码:

>>>print clf.predict([predict_this])
['A']
>>>print clf.decision_function([predict_this])
[[ 185.23220833   43.62763596  180.83305074  -93.58628288   62.51448055  173.43335293]]

如何使用决策函数的输出来预测类别 (A/B/C/D)概率最高,如果可能,它的价值?一世 访问过https://stackoverflow.com/a/20114601/7760998 但它是 对于二元分类器,找不到好的资源 解释了多类分类器的决策函数的输出 与形状 ovo(一对一)。

编辑:

以上示例适用于“A”类。对于另一个输入,分类器 预测'C'并在decision_function中给出以下结果

[[ 96.42193513 -11.13296606 111.47424538 -88.5356536 44.29272494 141.0069203 ]]

对于分类器预测为“C”的另一个不同输入 来自decision_function的以下结果,

[[ 290.54180354 -133.93467605  116.37068951 -392.32251314 -130.84421412   284.87653043]]

如果是 ovr(one-vs-rest),选择 一个值更高,但在 ovo(一对一)中,结果列表中有 (n * (n - 1)) / 2 值。

如何根据决定推断将选择哪个班级 功能?

回答

您的链接资源充足,我们来看看:

当您调用 decision_function() 时,您会得到每个成对分类器的输出(总共 n*(n-1)/2 个数字)。见第 127 页和 128“支持向量机模式分类”。

点击“第 127 和 128 页”链接(此处未显示,但在 堆栈溢出答案)。你应该看到:

  • Python 的 SVM 实现使用一对一。这正是这本书所说的。
  • 对于每个成对比较,我们测量决策函数
  • 决策函数就是正则二元 SVM 决策边界

这与你的问题有什么关系?

  • clf.decision_function() 将为您提供每对比较的 $D$
  • 得票最多的班级获胜

例如,

[[ 96.42193513 -11.13296606 111.47424538 -88.5356536 44.29272494 141.0069203 ]]

正在比较:

[AB、AC、AD、BC、BD、CD]

我们用符号标记他们每个人。我们得到:

[A, C, A, C, B, C]

例如,96.42193513 是正数,因此 A 是 AB 的标签。

现在我们有了三个 C,C 将是您的预测。如果你重复我的 其他两个示例的过程,您将获得 Python 的 预言。试试看!

【讨论】:

  • 是否应该从点积中添加或减去截距值 (b)?我查看了Wikipedia,它正在减去,但在文章中它正在添加。它甚至有那么重要吗?我很担心,因为我将决策函数计算为w.x + b 而不是w.x - b
  • 虽然您可以在原文中问这个问题,但直观地说,使用 +b 而不是 -b 应该会导致倒转 b。这应该不是问题。
【解决方案4】:

当您调用 decision_function() 时,您会从每个成对分类器中获得输出(总共 n*(n-1)/2 个数字)。见pages 127 and 128 of "Support Vector Machines for Pattern Classification"

每个分类器都对正确答案进行投票(基于该分类器输出的符号); predict() 返回得票最多的班级。

【讨论】:

  • 感谢罗曼!我对此进行了测试,在大多数情况下,看起来 predict 正在选择获得最多选票的班级。我最初做错的事情是选择累积边际得分最高的班级。
【解决方案5】:

他们可能有一些复杂的数学关系。但是如果你在LinearSVC分类器中使用decision_function,这两者之间的关系会更加清晰!因为然后decision_function 会给你每个类标签的分数(与 SVC 不同),并且 predict 会给你分数最好的类。

【讨论】:

    【解决方案6】:

    Predict() 遵循成对投票方案,该方案返回在所有成对比较中获得最多票的类。当两个类得分相同时,返回索引最低的类。

    下面是一个 Python 示例,该示例将此投票方案应用于一对一的 decision_function() 返回的 (n*(n-1)/2 成对分数。

    from sklearn import svm
    from sklearn import datasets
    from numpy import argmax, zeros
    from itertools import combinations
    
    # do pairwise comparisons, return class with most +1 votes
    def ovo_vote(classes, decision_function):
        combos = list(combinations(classes, 2))
        votes = zeros(len(classes))
        for i in range(len(decision_function[0])):
            if decision_function[0][i] > 0:
                votes[combos[i][0]] = votes[combos[i][0]] + 1
            else:
                votes[combos[i][1]] = votes[combos[i][1]] + 1
        winner = argmax(votes)
        return classes[winner]
    
    # load the digits data set
    digits = datasets.load_digits()
    
    X, y = digits.data, digits.target
    
    # set the SVC's decision function shape to "ovo"
    estimator = svm.SVC(gamma=0.001, C=100., decision_function_shape='ovo')
    
    # train SVC on all but the last digit
    estimator.fit(X.data[:-1], y[:-1])
    
    # print the value of the last digit
    print("To be classified digit: ", y[-1:][0])
    
    # print the predicted class
    pred = estimator.predict(X[-1:])
    print("Perform classification using predict: ", pred[0])
    
    # get decision function
    df = estimator.decision_function(X[-1:])
    
    # print the decision function itself
    print("Decision function consists of",len(df[0]),"elements:")
    print(df)
    
    # get classes, here, numbers 0 to 9
    digits = estimator.classes_
    
    # print which class has most votes
    vote = ovo_vote(digits, df)
    print("Perform classification using decision function: ", vote)
    
    

    【讨论】:

      猜你喜欢
      • 2016-02-14
      • 2017-08-19
      • 2015-12-13
      • 2014-12-06
      • 2016-12-29
      • 2015-06-15
      • 2018-05-18
      • 2017-05-03
      • 2017-04-17
      相关资源
      最近更新 更多