Scikit-learn predict_proba da respuestas incorrectas

Esta es una pregunta de seguimiento de Cómo saber qué clases están representadas en la matriz de retorno de predict_proba en Scikit-learn

En esa pregunta, cité el siguiente código:

>>> 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]]) 

Descubrí en esa pregunta que este resultado representa la probabilidad de que el punto pertenezca a cada clase, en el orden dado por model.classes_

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

Entonces … esta respuesta, si se interpreta correctamente, dice que el punto es probablemente un ‘naranja’ (con una confianza bastante baja, debido a la pequeña cantidad de datos). Pero intuitivamente, este resultado es obviamente incorrecto, ya que el punto dado fue idéntico a los datos de entrenamiento para “manzana”. Para estar seguro, también probé el reverso:

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

Una vez más, obviamente incorrecto, pero en la otra dirección.

Finalmente, lo probé con puntos que estaban mucho más lejos.

 >>> 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)] 

Nuevamente, el modelo predice las probabilidades equivocadas. PERO, la función model.predict lo hace bien!

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

Ahora, recuerdo haber leído algo en los documentos acerca de predict_proba que es inexacto para conjuntos de datos pequeños, aunque parece que no puedo encontrarlo de nuevo. ¿Es este el comportamiento esperado, o estoy haciendo algo mal? Si este es el comportamiento esperado, ¿por qué la función predict y predict_proba no está de acuerdo con la salida? Y, lo que es más importante, ¿qué tamaño debe tener el conjunto de datos antes de que pueda confiar en los resultados de predict_proba?

——– ACTUALIZACIÓN ——–

Ok, así que hice más ‘experimentos’ en esto: el comportamiento de predict_proba depende en gran medida de ‘n’, ¡pero no de una manera predecible!

 >>> 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)] 

¿Cómo debo usar esta función de forma segura en mi código? Como mínimo, ¿hay algún valor de n para el cual se garantice que está de acuerdo con el resultado de model.predict?

si usa svm.LinearSVC() como estimador, y .decision_function() (que es como .predict_proba () de svm.SVC para clasificar los resultados de la clase más probable a la menos probable. esto está de acuerdo con la función .predict() . Además, este estimador es más rápido y da casi los mismos resultados con svm.SVC()

El único inconveniente para usted podría ser que .decision_function() da un valor con signo sth como entre -1 y 3 en lugar de un valor de probabilidad. Pero está de acuerdo con la predicción.

predict_probas está utilizando la función de escalado de Platt de libsvm para calibrar las probabilidades, consulte:

  • ¿Cómo funciona internamente la función predict_proba () de sklearn.svm.svc?

Así que, de hecho, las predicciones del hiperplano y la calibración de la probabilidad pueden estar en desacuerdo, especialmente si solo tiene 2 muestras en su conjunto de datos. Es extraño que la validación cruzada interna realizada por libsvm para escalar las probabilidades no falle (explícitamente) en este caso. Tal vez esto es un error. Uno tendría que sumergirse en el código de escalamiento de Platt de libsvm para comprender lo que está sucediendo.

Alimento para el pensamiento aquí. Creo que en realidad pude que predict_proba funcione como es. Por favor vea el código abajo …

 # 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) 

Salida: Top 5 Tasa de precisión = 1.0 Top 1 Tasa de precisión = 1.0

Sin embargo, no pude hacerlo funcionar para mis propios datos 🙁

Hay algo de confusión sobre lo que predice realmente en proba. No predice probabilidades como sugiere el título, pero arroja distancias. En el ejemplo de manzana vs naranja 0.39097541, 0.60902459, la distancia más corta 0.39097541 es la clase de manzana. Lo cual es contrario a la intuición. Usted está mirando la probabilidad más alta, pero no es el caso.

Otra fuente de confusión proviene de que predict_proba hace coincidir las tags duras, pero no en el orden de las clases, desde 0..n secuencialmente. Scikit parece barajar las clases, pero es posible mapearlas.

Así es como funciona.

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

tags predichas [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] 

Cualquier cosa menos la tercera clase es un partido. según las tags pronosticadas en cm, la clase 0 se predice y la clase real es 0 argmax (pred_prob). Pero, su mapeado a

  y_test [2 0 1 3 4] 

entonces encuentra la segunda clase

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

hagámoslo de nuevo. mire el resultado número 4 de clasificación errónea donde lebel real 4, predijo 1 según cm.

  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** 

Estos son mis 0.02.