scikit.predict() seuil par défaut

Je travaille sur un problème de classification avec des classes déséquilibrées (5% 1). Je veux prédire la classe, pas la probabilité.

Dans un problème de classification binaire, scikit classifier.predict() utilise-t-il 0.5 par défaut? Si elle ne l'est pas, quelle est la méthode par défaut? Si c'est le cas, comment puis-je le changer?

Dans scikit, certains classificateurs ont l'option class_weight='auto', mais tous ne le font pas. Avec class_weight='auto', .predict() utiliserait-il la proportion réelle de la population comme seuil?

Quelle serait la façon de le faire dans un Classificateur comme MultinomialNB qui ne supporte pas class_weight? Autre que d'utiliser predict_proba() et ensuite calculer les classes moi-même.

48
demandé sur codegeek 2013-11-14 22:00:48

6 réponses

Scikit classifier.predict() utilise-t-il 0.5 par défaut?

Dans les classificateurs probabilistes, Oui. C'est le seul seuil raisonnable d'un point de vue mathématique, comme d'autres l'ont expliqué.

Quelle serait la façon de le faire dans un classificateur comme MultinomialNB qui ne supporte pas class_weight?

, Vous pouvez définir le class_prior, qui est la probabilité a priori P(y) par classe y. Cela modifie effectivement la limite de décision. Par exemple

# minimal dataset
>>> X = [[1, 0], [1, 0], [0, 1]]
>>> y = [0, 0, 1]
# use empirical prior, learned from y
>>> MultinomialNB().fit(X,y).predict([1,1])
array([0])
# use custom prior to make 1 more likely
>>> MultinomialNB(class_prior=[.1, .9]).fit(X,y).predict([1,1])
array([1])
30
répondu Fred Foo 2013-11-15 09:23:53

Le seuil dans scikit learn est de 0,5 pour la classification binaire et la classe la plus probable pour la classification multiclasse. Dans de nombreux problèmes, un résultat bien meilleur peut être obtenu en ajustant le seuil. Cependant, cela doit être fait avec soin et non pas sur les données de test de retenue, mais par validation croisée sur les données de formation. Si vous effectuez un ajustement du seuil sur vos données de test, vous ne faites que surajuster les données de test.

La plupart des méthodes d'ajustement du seuil est basé sur les caractéristiques de fonctionnement du récepteur (ROC) et statistique J de Youden mais il peut également être fait par d'autres méthodes telles qu'une recherche avec un algorithme génétique.

Voici un article de la revue peer review décrivant ce faisant en médecine:

Http://www.ncbi.nlm.nih.gov/pmc/articles/PMC2515362/

Pour autant que je sache, il n'y a pas de paquet pour le faire en Python mais il est relativement simple (mais inefficace) de le trouver avec une force brute de recherche en Python.

C'est un code R qui le fait.

## load data
DD73OP <- read.table("/my_probabilites.txt", header=T, quote="\"")

library("pROC")
# No smoothing
roc_OP <- roc(DD73OP$tc, DD73OP$prob)
auc_OP <- auc(roc_OP)
auc_OP
Area under the curve: 0.8909
plot(roc_OP)

# Best threshold
# Method: Youden
#Youden's J statistic (Youden, 1950) is employed. The optimal cut-off is the threshold that maximizes the distance to the identity (diagonal) line. Can be shortened to "y".
#The optimality criterion is:
#max(sensitivities + specificities)
coords(roc_OP, "best", ret=c("threshold", "specificity", "sensitivity"), best.method="youden")
#threshold specificity sensitivity 
#0.7276835   0.9092466   0.7559022
25
répondu denson 2016-02-09 19:32:18

Vous semblez être des concepts confus ici. Le seuil n'est pas un concept pour un "classificateur Générique" - les approches les plus fondamentales sont basées sur un seuil réglable, mais la plupart des méthodes existantes créent des règles complexes pour la classification qui ne peuvent pas (ou du moins ne devraient pas) être considérées comme un seuil.

Donc d'abord - on ne peut pas répondre à votre question pour le seuil par défaut du Classificateur de scikit car il n'y a pas une telle chose.

La pondération de deuxième classe n'est pas sur le seuil, est A propos de la capacité du Classificateur à faire face à des classes déséquilibrées, et c'est quelque chose qui dépend d'un classificateur particulier. Par exemple - dans le cas SVM, c'est la façon de pondérer les variables slack dans le problème d'optimisation, ou si vous préférez-les limites supérieures pour les valeurs des multiplicateurs de Lagrange liés à des classes particulières. Définir cela sur 'auto' signifie utiliser une heuristique par défaut, mais encore une fois-il ne peut pas être simplement traduit en un seuillage.

Naïf Bayes d'autre part directement estime la probabilité de classes à partir de l'ensemble de formation. Il est appelé " class prior "et vous pouvez le définir dans le constructeur avec la variable" class_prior".

De la documentation :

Probabilités antérieures des classes. Si spécifié, les antécédents ne sont pas ajustés en fonction des données.

8
répondu lejlot 2013-11-14 21:47:20

Le seuil peut être défini en utilisant clf.predict_proba()

Par exemple:

from sklearn.tree import DecisionTreeClassifier
clf = DecisionTreeClassifier(random_state = 2)
clf.fit(X_train,y_train)
# y_pred = clf.predict(X_test)  # default threshold is 0.5
y_pred = (clf.predict_proba(X_test)[:,1] >= 0.3).astype(bool) # set threshold as 0.3
4
répondu Yuchao Jiang 2018-08-03 19:32:20

0.5 n'est en aucun cas lié à la proportion de la population. Ses une probabilité de sortie. Il n'y a pas de "seuil", si une classe a une probabilité de 0,51, alors il semble être la classe la plus probable. 0.5 si toujours le ce qui devrait être utilisé*, et aucun paquet n'utilise un "seuil" différent. Si vos scores de probabilité sont * précis et vraiment représentatifs*, alors vous devez toujours choisir la classe la plus probable . Faire autrement ne peut que réduire votre précision. Puisque nous utilisons divers les algorithmes qui font des hypothèses, nous ne savons pas que la probabilité est vraie - mais vous iriez à l'encontre des hypothèses faites par votre modèle.

Vous Êtes confus sur ce que fait class_weight. Changer le poids de la classe augmenter les poids pour les points de données dans les classes moins représentées (/diminuer pour la classe surreprésentée) de sorte que le "poids" de chaque classe est égal - comme s'ils avaient le même nombre d'exemples positifs et négatifs. C'est un truc commun pour essayer pour éviter un classificateur qui vote toujours pour la classe la plus commune. Parce que de cette façon, les deux classes sont également communes du point de vue de l'algorithme d'apprentissage.

  • NOTE: Si vous avez peur des faux positifs / faux négatifs, vous pouvez choisir d'accepter une classe uniquement si sa probabilité répond à une certaine valeur minimale. Mais cela ne change pas la façon dont l'apprentissage est fait, et cette dose ne change pas le sens d'une probabilité.
2
répondu Raff.Edward 2013-11-14 23:37:12

Dans le cas où quelqu'un visite ce thread en espérant une fonction prête à l'emploi (Python 2.7). Dans cet exemple, cutoff est conçu pour refléter le rapport des événements aux non-événements dans l'ensemble de données d'origine df , alors que y_prob pourrait être le résultat de .méthode predict_proba (en supposant une Division train/test stratifié).

def predict_with_cutoff(colname, y_prob, df):
    n_events = df[colname].values
    event_rate = sum(n_events) / float(df.shape[0]) * 100
    threshold = np.percentile(y_prob[:, 1], 100 - event_rate)
    print "Cutoff/threshold at: " + str(threshold)
    y_pred = [1 if x >= threshold else 0 for x in y_prob[:, 1]]
    return y_pred

N'hésitez pas à critiquer / modifier. J'espère que cela aidera dans de rares cas lorsque l'équilibrage de classe est hors de question et que l'ensemble de données lui-même est très déséquilibré.

1
répondu michalw 2017-09-06 13:59:58