web-dev-qa-db-ja.com

Scikit-learn predict_probaが間違った答えを与える

これは からのフォローアップの質問です。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'

今、私は小さなデータセットに対してpredict_probaが不正確であることについてドキュメントで何かを読んだことを覚えていますが、再び見つけることはできないようです。これは予想される動作ですか、何か間違っていますか?これがIS予想される動作である場合、predictおよびpredict_proba関数が出力の1つと一致しないのはなぜですか?そして重要なことは、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)]

この関数をコードで安全に使用するにはどうすればよいですか?少なくとも、model.predictの結果と一致することが保証されるnの値はありますか?

39
Alex

svm.LinearSVC()を推定器として使用し、.decision_function()(svm.SVCの.predict_proba()と同様)を使用して、最も可能性の高いクラスから最も可能性の低いクラスに結果をソートする場合。これは.predict()関数と一致します。さらに、この推定器は高速で、svm.SVC()とほぼ同じ結果が得られます

唯一の欠点は、.decision_function()が確率値の代わりに-1〜3のような符号付きの値sthを与えることです。しかし、それは予測と一致しています。

19
Bilal Dadanlar

predict_probasは、libsvmのPlattスケーリング機能を使用して確率を呼び出しています。以下を参照してください。

そのため、特にデータセットにサンプルが2つしかない場合は、超平面予測と確率キャリブレーションが一致しない可能性があります。この場合、確率をスケーリングするためにlibsvmによって実行される内部相互検証が失敗しないことは奇妙です(明示的に)。たぶんこれはバグです。何が起こっているのかを理解するには、libsvmのPlattスケーリングコードに飛び込む必要があります。

21
ogrisel

ここでの思考の糧。実際に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
Statmonger