J'ai beaucoup de mal à comprendre comment fonctionne le class_weight
paramètre de la régression logistique de scikit-learn.
La situation
Je souhaite utiliser la régression logistique pour effectuer une classification binaire sur un ensemble de données très déséquilibré. Les classes sont étiquetées 0 (négatif) et 1 (positif) et les données observées sont dans un rapport d'environ 19: 1 avec la majorité des échantillons ayant un résultat négatif.
Première tentative: préparation manuelle des données d'entraînement
J'ai divisé les données que j'avais en ensembles disjoints pour la formation et les tests (environ 80/20). Ensuite, j'ai échantillonné au hasard les données d'entraînement à la main pour obtenir des données d'entraînement dans des proportions différentes de 19: 1; de 2: 1 -> 16: 1.
J'ai ensuite formé la régression logistique sur ces différents sous-ensembles de données d'entraînement et tracé le rappel (= TP / (TP + FN)) en fonction des différentes proportions d'entraînement. Bien sûr, le rappel a été calculé sur les échantillons TEST disjoints qui avaient les proportions observées de 19: 1. Notez que bien que j'aie entraîné les différents modèles sur différentes données d'entraînement, j'ai calculé le rappel pour tous sur les mêmes données de test (disjointes).
Les résultats étaient comme prévu: le rappel était d'environ 60% à des proportions d'entraînement de 2: 1 et a chuté assez rapidement au moment où il est arrivé à 16: 1. Il y avait plusieurs proportions 2: 1 -> 6: 1 où le rappel était décemment supérieur à 5%.
Deuxième tentative: recherche de grille
Ensuite, je voulais tester différents paramètres de régularisation et j'ai donc utilisé GridSearchCV et fait une grille de plusieurs valeurs du C
paramètre ainsi que du class_weight
paramètre. Pour traduire mes proportions n: m de négatifs: échantillons d'apprentissage positifs dans la langue du dictionnaire, class_weight
j'ai pensé que je viens de spécifier plusieurs dictionnaires comme suit:
{ 0:0.67, 1:0.33 } #expected 2:1
{ 0:0.75, 1:0.25 } #expected 3:1
{ 0:0.8, 1:0.2 } #expected 4:1
et j'ai également inclus None
et auto
.
Cette fois, les résultats ont été totalement décevants. Tous mes rappels sont sortis minuscules (<0,05) pour chaque valeur de class_weight
sauf auto
. Je ne peux donc que supposer que ma compréhension de la configuration du class_weight
dictionnaire est erronée. Il est intéressant de noter que la class_weight
valeur de «auto» dans la recherche de grille était d'environ 59% pour toutes les valeurs de C
, et j'ai deviné que son équilibre était de 1: 1?
Mes questions
Comment utilisez-vous correctement
class_weight
pour obtenir des équilibres différents dans les données d'entraînement par rapport à ce que vous leur donnez réellement? Plus précisément, à quel dictionnaire dois-je passer pourclass_weight
utiliser n: m proportions de négatifs: échantillons d'apprentissage positifs?Si vous transmettez divers
class_weight
dictionnaires à GridSearchCV, lors de la validation croisée, rééquilibrera-t-il les données de pli d'entraînement en fonction du dictionnaire, mais utilisera-t-il les vraies proportions d'échantillons données pour calculer ma fonction de notation sur le pli de test? Ceci est essentiel car toute métrique ne m'est utile que si elle provient de données dans les proportions observées.Que fait la
auto
valeur de enclass_weight
ce qui concerne les proportions? J'ai lu la documentation et je suppose que "équilibre les données inversement proportionnelles à leur fréquence" signifie simplement qu'il est 1: 1. Est-ce correct? Sinon, quelqu'un peut-il clarifier?
la source
Réponses:
Tout d'abord, il n'est peut-être pas bon de se contenter de se souvenir uniquement. Vous pouvez simplement obtenir un rappel de 100% en classant tout comme la classe positive. Je suggère généralement d'utiliser AUC pour sélectionner les paramètres, puis de trouver un seuil pour le point de fonctionnement (par exemple un niveau de précision donné) qui vous intéresse.
Pour la façon dont cela
class_weight
fonctionne: Cela pénalise les erreurs dans les échantillons declass[i]
avecclass_weight[i]
au lieu de 1. Donc, un poids de classe plus élevé signifie que vous voulez mettre davantage l'accent sur une classe. D'après ce que vous dites, il semble que la classe 0 est 19 fois plus fréquente que la classe 1. Vous devriez donc augmenter laclass_weight
classe 1 par rapport à la classe 0, disons {0: .1, 1: .9}. Si laclass_weight
somme ne vaut pas 1, cela changera fondamentalement le paramètre de régularisation.Pour savoir comment
class_weight="auto"
fonctionne, vous pouvez jeter un œil à cette discussion . Dans la version de développement, vous pouvez utiliserclass_weight="balanced"
, ce qui est plus facile à comprendre: cela signifie essentiellement répliquer la classe la plus petite jusqu'à ce que vous ayez autant d'échantillons que dans la plus grande, mais de manière implicite.la source
La première réponse est bonne pour comprendre comment cela fonctionne. Mais je voulais comprendre comment je devrais l'utiliser dans la pratique.
RÉSUMÉ
class_weight="balanced"
fonctionne correctement en l'absence de vous voulant optimiser manuellementclass_weight="balanced"
vous capturez plus d'événements vrais (rappel TRUE plus élevé) mais vous êtes également plus susceptible de recevoir de fausses alertes (précision TRUE inférieure)NB
Le résultat peut différer lors de l'utilisation de RF ou GBM. sklearn n'a pas
class_weight="balanced"
pour GBM mais lightgbm aLGBMClassifier(is_unbalance=False)
CODE
la source