首页 文章

Scikit-learn predict_proba给出了错误的答案

提问于
浏览
36

这是How to know what classes are represented in return array from predict_proba in Scikit-learn的后续问题

在那个问题中,我引用了以下代码:

>>> 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的结果之前,数据集需要有多大?

-------- UPDATE --------

好吧,所以我做了一些更多的“实验”: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的结果一致?

4 回答

  • 19

    如果你使用 svm.LinearSVC() 作为估计,并且 .decision_function() (类似于svm.SVC的.predict_proba())用于将结果从最可能的类排序到最不可能的类 . 这与 .predict() 函数一致 . 此外,这个估算器更快,并且 svm.SVC() 给出几乎相同的结果

    你唯一的缺点可能是 .decision_function() 给出了一个有符号的值,比如介于-1和3而不是概率值 . 但它同意预测 .

  • 17

    predict_probas 正在使用libsvm的Platt缩放功能来调用概率,请参阅:

    事实上,超平面预测和问题校准可能不一致,特别是如果您的数据集中只有2个样本 . 奇怪的是,在这种情况下,libsvm用于扩展概率的内部交叉验证不会(明确地)失败 . 也许这是一个错误 . 人们不得不深入研究libsvm的Platt缩放代码以了解正在发生的事情 .

  • -1

    这里有思想的食物 . 我想我确实让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

    无法让它为我自己的数据工作:(

  • 0

    对于predict_proba实际上做了什么,有一些混乱 . 它不像 Headers 所暗示的那样预测概率,而是输出距离 . 在苹果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 .

相关问题