Je travaille sur un problème de classification avec des classes non équilibrées (5% 1). Je veux prédire la classe, pas la probabilité.
Dans un problème de classification binaire, scikit's classifier.predict()
utilise-t-il 0.5
Par défaut? Si ce n'est pas le cas, 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 pas tous. Avec class_weight='auto'
, .predict()
utiliserait-il la proportion réelle de la population comme seuil?
Quel serait le moyen de faire cela dans un classificateur comme MultinomialNB
qui ne prend pas en charge class_weight
? Autre que d'utiliser predict_proba()
et ensuite calculer les classes moi-même.
est-ce que scikit's
classifier.predict()
utilise 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é.
Quel serait le moyen de faire cela 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 déplace 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])
Le seuil dans Scikit Learn est 0.5 pour la classification binaire et quelle que soit la classe ayant la plus grande probabilité de classification multiclass. Dans de nombreux problèmes, un résultat bien meilleur peut être obtenu en ajustant le seuil. Cependant, cela doit être fait avec précaution et PAS sur les données du test de réserve, mais par validation croisée sur les données d'apprentissage. Si vous modifiez le seuil de vos données de test, vous ne faites que trop adapter les données de test.
La plupart des méthodes d'ajustement du seuil sont basées sur les caractéristiques de fonctionnement du récepteur (ROC) et statistique J de Youden algorithme.
Voici un article de revue par les pairs décrivant le faire en médecine:
http://www.ncbi.nlm.nih.gov/pmc/articles/PMC2515362/
Autant que je sache, il n'y a pas de paquet pour le faire dans Python mais il est relativement simple (mais inefficace) de le trouver avec une recherche en force brute dans 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
Le seuil peut être défini avec 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
Vous semblez confondre les concepts ici. Seuil n'est pas un concept de "classifieur générique" - les approches les plus élémentaires reposent sur un seuil réglable, mais la plupart des méthodes existantes créent des règles de classification complexes qui ne peuvent (ou du moins ne devraient pas) être considérées comme un seuillage.
Donc, premièrement, on ne peut pas répondre à votre question concernant le seuil par défaut du classifieur de scikit, car cela n'existe pas.
La pondération en deuxième classe ne concerne pas le seuil, mais la capacité du classifieur à traiter les classes déséquilibrées et dépend d'un classificateur particulier. Par exemple, dans le cas de SVM, c’est la manière de pondérer les variables de jeu dans le problème d’optimisation ou, si vous préférez, les limites supérieures des valeurs des multiplicateurs de lagrange liées à des classes particulières. Le paramétrer sur 'auto' signifie utiliser une heuristique par défaut, mais encore une fois - cela ne peut pas être simplement traduit en un certain seuillage.
Naive Bayes, d’autre part directement estime la probabilité des classes à partir de l’entraînement. Il s'appelle "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 a priori ne sont pas ajustés en fonction des données.
0,5 n'est en aucun cas lié à la proportion de la population. C'est une sortie de probabilité. 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 quoi devrait être utilisé *, et aucun paquet n'utilise un "seuil" différent. Si vos scores de probabilité sont * exacts 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 algorithmes qui supposent des hypothèses, nous ne savons pas que la probabilité est vraie, mais vous iriez à l’encontre des hypothèses de votre modèle.
Vous êtes confondez ce que fait class_weight. Si vous modifiez le poids de la classe, augmentez le poids des points de données dans les classes moins représentées (/ décroissant pour la classe sur-représentée) de sorte que le "poids" de chaque classe soit égal, comme si elles avaient le même nombre d'exemples positifs et négatifs. C'est une astuce courante pour éviter un classificateur qui vote toujours pour la classe la plus courante. Parce que de cette façon, les deux classes sont également communes du point de vue de l'algorithme d'apprentissage.
Au cas où quelqu'un visiterait ce fil en espérant une fonction prête à l'emploi (python 2.7). Dans cet exemple, cutoff est conçu pour refléter le rapport entre les événements et les non-événements dans le jeu de données d'origine df, tandis que y_prob pourrait être le résultat de la méthode .predict_proba (en supposant un train/test stratifié). Divisé).
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 des classes est hors de question et que l'ensemble de données lui-même est très déséquilibré.