Scikit了解SVC decision_function并进行预测

时间:2013-11-21 05:29:36

标签: python numpy svm scikit-learn

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

有谁知道这些预测与决策功能之间的关系?

6 个答案:

答案 0 :(得分:26)

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

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函数告诉我们分类器生成的超平面的哪一侧(以及我们离它多远)。根据该信息,估算器然后用相应的标签标记示例。

答案 1 :(得分:14)

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

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

答案 2 :(得分:13)

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

# 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))

答案 3 :(得分:11)

datascience.sx上的多级一对一场景有一个really nice Q&A

问题

  

我有一个多类SVM分类器,标签为'A','B','C','D'。

     

这是我正在运行的代码:

>>>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,但确实如此   对于二元分类器而言,找不到一个好的资源   解释了多类分类器的decision_function输出   形状卵(一对一)。

     

修改

     

以上示例适用于“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(一对一休息),选择它会变得更容易   一个值较高,但在卵内(一对一),结果列表中有(n * (n - 1)) / 2个值。

     

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

答案

  

你的链接有足够的资源,所以让我们通过:

     
    

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

  
     

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

     

enter image description here

     
      
  • Python的SVM实现使用one-vs-one。这正是本书所讨论的内容。
  •   
  • 对于每个成对比较,我们测量决策函数
  •   
  • 决策函数只是常规二进制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的   预测。试试吧!

答案 4 :(得分:1)

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

在下面的Python示例中,该示例将此投票方案应用于(n *(n-1)/ 2成对得分,由一对一的Decision_function()返回)。

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)

答案 5 :(得分:0)

他们可能有一些复杂的数学关系。但是,如果您在decision_function分类器中使用LinearSVC,则这两者之间的关系将更加明确!因为那时decision_function将为每个类标签(与SVC不同)给出分数,并且预测将为该类提供最佳分数。