3

我正在做多標籤分類,我試圖根據問題預測正確的標籤:使用OneVsRestClassifier時sklearn.svm.SVC的哪個decision_function_shape?

(X = questions,y =來自X的每個問題的標籤列表)。

我在想,哪個decision_function_shapesklearn.svm.SVC應該用OneVsRestClassifier

從文檔,我們可以讀到decision_function_shape可以有兩個值'ovo''ovr'

decision_function_shape: '大毛', 'OVR' 或無,默認=無

是否返回(n_samples,n_classes)作爲所有其他分類器的一對一休止('ovr')決策函數,或者具有形狀爲 (n_samples,n_classes)的一對一(vsO)決策函數*(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問題?

編輯:Question要求類似的事情沒有答案。

+0

你可以嘗試都和檢查哪些一個給你的具體數據更好的結果。 –

回答

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個類別,因此對於更復雜的數據集,這些結果可能會不同,但這是一個簡單的概念證明。

2

的決定函數的形狀是不同的,因爲ovo訓練爲每個2對類組合ovr列車一個分類爲嵌合針對所有其他類的每個類的分類器。

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

SVCNuSVC實行「一對一」的方式爲多級(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 

簡單來說這是什麼意思?

要理解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')]) 

哪個估計器應該用於多標籤分類?

在你的情況,你有一個問題與多個標籤(就像這裏在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 
+0

很好的回答。你能解釋一下爲什麼你會使用LinearSVC()而不是SVC(kernel ='linear')來解決這個問題?根據文檔,它們在實施方面存在差異嗎?它們基本上不一樣嗎? (我只知道LinearSVC()的一個優點 - 對於較大的數據集,它的縮放比例更好) – delusionX

+0

老實說,這很奇怪!在上面的示例中,在我的'pipeline'中,如果用'SVC(kernel ='linear')'替換'LinearSVC()',預測輸出就不太好。例如,它不識別'sklearn'或'.net'。我覺得這很有趣,但我不知道爲什麼。我認爲他們也基本一樣。這是一個驚喜。 – Jarad

相關問題