簡體   English   中英

Scikit-learn predict_proba給出了錯誤的答案

[英]Scikit-learn predict_proba gives wrong answers

這是一個后續問題, 如何知道Scikit-learn中的predict_proba在返回數組中表示了哪些類

在那個問題中,我引用了以下代碼:

>>> import sklearn
>>> sklearn.__version__
'0.13.1'
>>> from sklearn import svm
>>> model = svm.SVC(probability=True)
>>> X = [[1,2,3], [2,3,4]] # feature vectors
>>> Y = ['apple', 'orange'] # classes
>>> model.fit(X, Y)
>>> model.predict_proba([1,2,3])
array([[ 0.39097541,  0.60902459]])

我在那個問題中發現這個結果表示屬於每個類的點的概率,按照model.classes_給出的順序

>>> zip(model.classes_, model.predict_proba([1,2,3])[0])
[('apple', 0.39097541289393828), ('orange', 0.60902458710606167)]

所以...這個答案,如果正確解釋,說這個點可能是一個“橙色”(由於數據量很小,信心相當低)。 但直覺上,這個結果顯然是不正確的,因為給出的點與'apple'的訓練數據相同。 只是為了確定,我也測試了反向:

>>> zip(model.classes_, model.predict_proba([2,3,4])[0])
[('apple', 0.60705475211840931), ('orange', 0.39294524788159074)]

再次,顯然不正確,但在另一個方向。

最后,我嘗試了更遠的點。

>>> X = [[1,1,1], [20,20,20]] # feature vectors
>>> model.fit(X, Y)
>>> zip(model.classes_, model.predict_proba([1,1,1])[0])
[('apple', 0.33333332048410247), ('orange', 0.66666667951589786)]

同樣,該模型預測錯誤的概率。 但是,model.predict功能正確!

>>> model.predict([1,1,1])[0]
'apple'

現在,我記得在docs中讀到一些關於predict_proba對於小數據集不准確的東西,盡管我似乎無法再找到它。 這是預期的行為,還是我做錯了什么? 如果這是預期的行為,那么為什么predict和predict_proba函數不同意輸出? 更重要的是,在我可以信任predict_proba的結果之前,數據集需要有多大?

--------更新--------

好的,所以我做了一些更多的“實驗”:predict_proba的行為嚴重依賴於'n',但不是以任何可預測的方式!

>>> def train_test(n):
...     X = [[1,2,3], [2,3,4]] * n
...     Y = ['apple', 'orange'] * n
...     model.fit(X, Y)
...     print "n =", n, zip(model.classes_, model.predict_proba([1,2,3])[0])
... 
>>> train_test(1)
n = 1 [('apple', 0.39097541289393828), ('orange', 0.60902458710606167)]
>>> for n in range(1,10):
...     train_test(n)
... 
n = 1 [('apple', 0.39097541289393828), ('orange', 0.60902458710606167)]
n = 2 [('apple', 0.98437355278112448), ('orange', 0.015626447218875527)]
n = 3 [('apple', 0.90235408180319321), ('orange', 0.097645918196806694)]
n = 4 [('apple', 0.83333299908143665), ('orange', 0.16666700091856332)]
n = 5 [('apple', 0.85714254878984497), ('orange', 0.14285745121015511)]
n = 6 [('apple', 0.87499969631893626), ('orange', 0.1250003036810636)]
n = 7 [('apple', 0.88888844127886335), ('orange', 0.11111155872113669)]
n = 8 [('apple', 0.89999988018127364), ('orange', 0.10000011981872642)]
n = 9 [('apple', 0.90909082368682159), ('orange', 0.090909176313178491)]

我應該如何在我的代碼中安全地使用此功能? 至少,是否有任何n的值可以保證與model.predict的結果一致?

predict_probas正在使用libsvm的Platt縮放功能來調用概率,請參閱:

事實上,超平面預測和問題校准可能不一致,特別是如果您的數據集中只有2個樣本。 奇怪的是,在這種情況下,libsvm用於擴展概率的內部交叉驗證不會(明確地)失敗。 也許這是一個錯誤。 人們不得不深入研究libsvm的Platt縮放代碼以了解正在發生的事情。

如果你使用svm.LinearSVC()作為估計器,而.decision_function() (類似於svm.SVC的.predict_proba())用於將結果從最可能的類排序到最不可能的類。 這與.predict()函數一致。 另外,這個估算器更快,並且使用svm.SVC()得到幾乎相同的結果

你唯一的缺點可能是.decision_function()給出一個有符號的值,比如介於-1和3而不是概率值。 但它同意預測。

這里有思想的食物。 我想我確實讓predict_proba按原樣工作。 請看下面的代碼......

# Test data
TX = [[1,2,3], [4,5,6], [7,8,9], [10,11,12], [13,14,15], [16,17,18], [19,20,21], [22,23,24]]
TY = ['apple', 'orange', 'grape', 'kiwi', 'mango','peach','banana','pear']

VX2 = [[16,17,18], [19,20,21], [22,23,24], [13,14,15], [10,11,12], [7,8,9], [4,5,6], [1,2,3]]
VY2 = ['peach','banana','pear','mango', 'kiwi', 'grape', 'orange','apple']

VX2_df = pd.DataFrame(data=VX2) # convert to dataframe
VX2_df = VX2_df.rename(index=float, columns={0: "N0", 1: "N1", 2: "N2"})
VY2_df = pd.DataFrame(data=VY2) # convert to dataframe
VY2_df = VY2_df.rename(index=float, columns={0: "label"})

# NEW - in testing
def train_model(classifier, feature_vector_train, label, feature_vector_valid, valid_y, valid_x, is_neural_net=False):

    # fit the training dataset on the classifier
    classifier.fit(feature_vector_train, label)

    # predict the top n labels on validation dataset
    n = 5
    #classifier.probability = True
    probas = classifier.predict_proba(feature_vector_valid)
    predictions = classifier.predict(feature_vector_valid)

    #Identify the indexes of the top predictions
    #top_n_predictions = np.argsort(probas)[:,:-n-1:-1]
    top_n_predictions = np.argsort(probas, axis = 1)[:,-n:]

    #then find the associated SOC code for each prediction
    top_socs = classifier.classes_[top_n_predictions]

    #cast to a new dataframe
    top_n_df = pd.DataFrame(data=top_socs)

    #merge it up with the validation labels and descriptions
    results = pd.merge(valid_y, valid_x, left_index=True, right_index=True)
    results = pd.merge(results, top_n_df, left_index=True, right_index=True)

    conditions = [
        (results['label'] == results[0]),
        (results['label'] == results[1]),
        (results['label'] == results[2]),
        (results['label'] == results[3]),
        (results['label'] == results[4])]
    choices = [1, 1, 1, 1, 1]
    results['Successes'] = np.select(conditions, choices, default=0)

    print("Top 5 Accuracy Rate = ", sum(results['Successes'])/results.shape[0])
    print("Top 1 Accuracy Rate = ", metrics.accuracy_score(predictions, valid_y))

train_model(naive_bayes.MultinomialNB(), TX, TY, VX2, VY2_df, VX2_df)

輸出:前5個准確率= 1.0前1個准確率= 1.0

無法讓它為我自己的數據工作:(

對於predict_proba實際上做了什么,有一些混亂。 它不像標題所暗示的那樣預測概率,而是輸出距離。 在蘋果vs橙色示例0.39097541,0.60902459中,最短距離0.39097541是蘋果類。 這是反直覺的。 你看的概率最高,但並非如此。

混淆的另一個原因源於predict_proba確實匹配硬標簽,而不是類的順序,從0..n順序。 Scikit似乎改變了類,但可以映射它們。

下面是它的工作原理。

   say we have 5 classes with labels:
   classifier.classes_ = [0 1 2 3 4]
   target names = ['1', '2', '3', '6', '8']

預測標簽[2 0 1 0 4]

    classifier.predict_proba
    [[ 0.20734121  0.20451986  0.17262553  0.20768649  0.20782692]
     [ 0.19099348  0.2018391   0.20222314  0.20136784  0.20357644]
     [ 0.19982284  0.19497121  0.20399376  0.19824784  0.20296435]
     [ 0.19884577  0.1999416   0.19998889  0.20092702  0.20029672]
     [ 0.20328893  0.2025956   0.20500402  0.20383255  0.1852789 ]]

    Confusion matrix:
    [[1 0 0 0 0]
     [0 1 0 0 0]
     [0 0 1 0 0]
     [1 0 0 0 0]
     [0 0 0 0 1]]

    y_test [2 0 1 3 4]
    pred [2 0 1 0 4]
    classifier.classes_ = [0 1 2 3 4]

除了第三節課以外什么都不配。 根據以cm為單位的預測標簽,預測出0級,實際等級為0 argmax(pred_prob)。 但是,它映射到

     y_test [2 0 1 3 4]

所以找到第二堂課

    0              1             2          3          4
    [ 0.20734121  0.20451986  0.17262553  0.20768649  0.20782692]
    and the winner is **0.17262553**

讓我們再來一次。 看看錯誤分類結果,其中實際的lebel 4,根據cm預測為1。

    BUT y_test [2 0 1 3 4] pred [2 0 1 0 4]
    which translates to actual label 3 predicted label 0
    0             1             2            3        4
    ]0.19884577  0.1999416   0.19998889  0.20092702  0.20029672]
    look at label number 0, and the winner is **0.19884577**

這些是我的0.02。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM