首页 文章

使用OneVsRestClassifier时,sklearn.svm.SVC的decision_function_shape是哪个?

提问于
浏览
4

我正在做多标签分类,我试图预测正确的标签到问题:

(X =问题,y =来自X的每个问题的标签列表) .

我想知道 decision_function_shape sklearn.svm.SVC应与OneVsRestClassifier一起使用?

从文档我们可以读到 decision_function_shape 可以有两个值 'ovo''ovr'

decision_function_shape:'ovo','ovr'或None,default = None是否将形状(n_samples,n_classes)的one-vs-rest('ovr')决策函数返回为所有其他分类器,或原始one-vs具有形状的libsvm的一个('ovo')决策函数(n_samples,n_classes *(n_classes - 1)/ 2) . 默认值None目前将表现为'ovo'以实现向后兼容性并提出弃用警告,但会在0.19中更改'ovr' .

但我仍然不明白有什么区别:

# First decision_function_shape set to 'ovo'
estim = OneVsRestClassifier(SVC(kernel='linear', decision_function_shape ='ovo'))

# Second decision_function_shape set to 'ovr'
estim = OneVsRestClassifier(SVC(kernel='linear', decision_function_shape ='ovr'))

哪个 decision_function_shape 应该用于multi-label classification问题?

EDIT: Question问一个没有答案的类似事情 .

2 回答

  • 2

    我认为应该使用哪个问题最好留给情境 . 这可能很容易成为您的GridSearch的一部分 . 但直觉上我会觉得,就差异而言,你将会做同样的事情 . 这是我的推理:

    OneVsRestClassifier 旨在独立地针对所有其他类对每个类建模,并为每种情况创建分类器 . 我理解这个过程的方式是 OneVsRestClassifier 抓取一个类,并为点是否是该类创建二进制标签 . 然后,这个标签被输入您选择使用的任何估算器 . 我相信混乱的原因在于 SVC 也允许你做出同样的选择,但实际上这个实现的选择并不重要,因为你总是只将两个类送入 SVC .

    这是一个例子:

    from sklearn.datasets import load_iris
    from sklearn.multiclass import OneVsRestClassifier
    from sklearn.svm import SVC
    
    data = load_iris()
    
    X, y = data.data, data.target
    estim1 = OneVsRestClassifier(SVC(kernel='linear', decision_function_shape='ovo'))
    estim1.fit(X,y)
    
    estim2 = OneVsRestClassifier(SVC(kernel='linear', decision_function_shape='ovr'))
    estim2.fit(X,y)
    
    print(estim1.coef_ == estim2.coef_)
    array([[ True,  True,  True,  True],
           [ True,  True,  True,  True],
           [ True,  True,  True,  True]], dtype=bool)
    

    因此,您可以看到两个模型构建的所有三个估算器的系数都相等 . 假设这个数据集只有150个样本和3个类,因此对于更复杂的数据集,这些结果可能会有所不同,但这是一个简单的概念证明 .

  • 3

    决策函数的形状是不同的,因为 ovo 为每个 2-pair class combination 训练一个分类器,而 ovr 为每个类别训练一个分类器以适应所有其他类别 .

    我能找到的最好的例子是found here on http://scikit-learn.org

    SVC和NuSVC针对多类分类实施“一对一”方法(Knerr等,1990) . 如果n_class是类的数量,则构造n_class *(n_class-1)/ 2个分类器,并且每个分类器训练来自两个类的数据 . 为了提供与其他分类器的一致接口,decision_function_shape选项允许将“一对一”分类器的结果聚合到形状的决策函数(n_samples,n_classes)

    >>> X = [[0], [1], [2], [3]]
    >>> Y = [0, 1, 2, 3]
    >>> clf = svm.SVC(decision_function_shape='ovo')
    >>> clf.fit(X, Y) 
    SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
        decision_function_shape='ovo', degree=3, gamma='auto', kernel='rbf',
        max_iter=-1, probability=False, random_state=None, shrinking=True,
        tol=0.001, verbose=False)
    >>> dec = clf.decision_function([[1]])
    >>> dec.shape[1] # 4 classes: 4*3/2 = 6
    6
    >>> clf.decision_function_shape = "ovr"
    >>> dec = clf.decision_function([[1]])
    >>> dec.shape[1] # 4 classes
    4
    

    What does this mean in simple terms?

    要了解 n_class * (n_class - 1) / 2 的含义,请使用 itertools.combinations 生成两个类的组合 .

    def ovo_classifiers(classes):
        import itertools
        n_class = len(classes)
        n = n_class * (n_class - 1) / 2
        combos = itertools.combinations(classes, 2)
        return (n, list(combos))
    
    >>> ovo_classifiers(['a', 'b', 'c'])
    (3.0, [('a', 'b'), ('a', 'c'), ('b', 'c')])
    >>> ovo_classifiers(['a', 'b', 'c', 'd'])
    (6.0, [('a', 'b'), ('a', 'c'), ('a', 'd'), ('b', 'c'), ('b', 'd'), ('c', 'd')])
    

    Which estimator should be used for multi-label classification?

    在您的情况下,您有一个带有多个标签的问题(如此处在StackOverflow上) . 如果你事先知道你的标签(类),我可能会建议 OneVsRestClassifier(LinearSVC()) ,但你可以尝试DecisionTreeClassifier或RandomForestClassifier(我认为):

    import pandas as pd
    from sklearn.preprocessing import MultiLabelBinarizer
    from sklearn.svm import SVC, LinearSVC
    from sklearn.feature_extraction.text import CountVectorizer
    from sklearn.pipeline import Pipeline
    from sklearn.multiclass import OneVsRestClassifier, OneVsOneClassifier
    
    df = pd.DataFrame({
      'Tags': [['python', 'pandas'], ['c#', '.net'], ['ruby'],
               ['python'], ['c#'], ['sklearn', 'python']],
      'Questions': ['This is a post about python and pandas is great.',
               'This is a c# post and i hate .net',
               'What is ruby on rails?', 'who else loves python',
               'where to learn c#', 'sklearn is a python package for machine learning']},
                      columns=['Questions', 'Tags'])
    
    X = df['Questions']
    mlb = MultiLabelBinarizer()
    y = mlb.fit_transform(df['Tags'].values)
    
    pipeline = Pipeline([
      ('vect', CountVectorizer(token_pattern='|'.join(mlb.classes_))),
      ('linear_svc', OneVsRestClassifier(LinearSVC()))
      ])
    pipeline.fit(X, y)
    
    final = pd.DataFrame(pipeline.predict(X), index=X, columns=mlb.classes_)
    
    def predict(text):
      return pd.DataFrame(pipeline.predict(text), index=text, columns=mlb.classes_)
    
    test = ['is python better than c#', 'should i learn c#',
            'should i learn sklearn or tensorflow',
            'ruby or c# i am a dinosaur',
            'is .net still relevant']
    print(predict(test))
    

    输出:

    .net  c#  pandas  python  ruby  sklearn
    is python better than c#                 0   1       0       1     0        0
    should i learn c#                        0   1       0       0     0        0
    should i learn sklearn or tensorflow     0   0       0       0     0        1
    ruby or c# i am a dinosaur               0   1       0       0     1        0
    is .net still relevant                   1   0       0       0     0        0
    

相关问题