Scikit-learn: Estimateurs de rééchantillonnage qui modifient la taille de l'échantillon lors de l'ajustement

Créé le 15 nov. 2014  ·  68Commentaires  ·  Source: scikit-learn/scikit-learn

Certaines transformations de données - y compris le sur/sous-échantillonnage (#1454), la suppression des valeurs aberrantes, la réduction d'instances et d'autres formes de compression de jeu de données, comme celle utilisée dans BIRCH (#3802) - impliquent de modifier un jeu de données au moment de la formation, mais en laissant il n'a pas été modifié au moment de la prédiction. (Dans certains cas, comme la suppression des valeurs aberrantes, il est logique de réappliquer un modèle ajusté à de nouvelles données, tandis que dans d'autres, la réutilisation du modèle après l'ajustement semble moins applicable.)

Comme indiqué ailleurs , les transformateurs qui modifient le nombre d'échantillons ne sont actuellement pas pris en charge, certainement dans le contexte de Pipeline s où une transformation est appliquée à la fois à fit et predict time ( bien qu'un hack puisse abuser de fit_transform pour que ce ne soit pas le cas). Pipeline s de Transformer s ne feraient pas non plus face aux changements de la taille de l'échantillon au moment de l'ajustement pour les problèmes supervisés car les Transformer s ne renvoient pas de y modifié , seulement X .

Pour traiter cette classe de problèmes, je propose d'introduire une nouvelle catégorie d'estimateurs, appelée Resampler . Il doit définir au moins une méthode fit_resample , que Pipeline appellera à l'heure fit , en transmettant les données inchangées à d'autres moments. (Pour cette raison, un Resampler ne peut pas être aussi un Transformer , sinon nous devons définir leur priorité.)

Pour de nombreux modèles, fit_resample n'a besoin de retourner que sample_weight . Pour les approches de compression d'échantillons (par exemple dans BIRCH), cela n'est pas suffisant car les centroïdes représentatifs sont modifiés à partir des échantillons d'entrée. Par conséquent, je pense que fit_resample devrait renvoyer directement les données modifiées, sous la forme d'un dict avec les clés X , y , sample_weight selon les besoins. (Il peut toujours être approprié pour de nombreux Resampler de ne modifier que sample_weight ; si nécessaire, un autre Resampler peut être enchaîné qui réalise les poids en tant qu'entrées répliquées ou supprimées dans X et y .)

API Moderate New Feature help wanted

Tous les 68 commentaires

J'entends cela positivement après avoir discuté de ce même pb avec @MechCoder

pouvez-vous écrire quelques lignes de code de la manière dont vous souhaitez rediriger quelque chose
comme Birch avec un estimateur qui prend en charge sample_weights ?

Je ne suis pas sûr de la tuyauterie du bouleau avec des poids d'échantillon, mais BIRCH pourrait être mis en œuvre comme

make_pipeline(BirchResampler, PredictorToResampler(SomeClusterer), KNeighborsClassifier)

Non pas que ce soit si soigné, mais cela donne un exemple de la puissance de l'approche. ( PredictorToResampler prend simplement les prédictions d'une méthode et la renvoie comme y pour l'entrée X .)

Je pense que nous devrions énumérer quelques cas d'utilisation pour proposer une API qui
travail. Le code semble un peu trop générique pour un seul cas d'utilisation, ce que je
reconnaître la pertinence compte tenu de nos travaux sur le bouleau.

Je pense que ce problème est un problème d'API de base et un bloqueur pour 1.0.
Merci d'avoir amené le débat.

Pour traiter cette classe de problèmes, je propose d'introduire une nouvelle catégorie de
estimateur, appelé rééchantillonneur. Il doit définir au moins une méthode fit_resample,
que Pipeline appellera au moment de l'ajustement, transmettant les données inchangées à d'autres
fois. (Pour cette raison, un rééchantillonneur ne peut pas être aussi un transformateur, sinon nous
besoin de définir leur priorité.)

Pourquoi confondre ajustement et rééchantillonnage ? Je peux voir des cas d'utilisation pour un ajustement séparé
et rééchantillonner.

De plus, à mon humble avis, le fait que la transformation ne modifie pas y est un échec de conception
(mien). Je serais plus heureux de définir une nouvelle méthode, similaire à transformer,
qui modifie y (je cherche un bon nom), et de sortir progressivement
phase « transformer ».

De cette façon, nous évitons d'introduire une nouvelle classe d'objet et un nouveau concept.
Plus il y a de concepts et de classes d'objets dans une bibliothèque, plus
plus difficile à comprendre.

Enfin, je n'aime pas trop le nom 'resample'. je trouve que c'est trop
spécifiques, et qu'il s'agit d'autres cas d'utilisation de la méthode que le rééchantillonnage
(apprentissage semi-supervisé pour propager des étiquettes à des données non étiquetées, par
exemple).

Voici des suggestions de noms :

  • appliquer
  • monnaie
  • modifier
  • subir une mutation
  • convertir

Le nom transform est tout simplement trop beau, à mon humble avis. À long terme, nous pourrions venir
y revenir, après quelques années de dépréciation de l'ancien comportement.
Le nouveau comportement serait qu'il renvoie toujours le même nombre de tableaux
qu'il n'est donné (et génère une erreur si seul X est donné pour un
méthode qui a besoin de y).

La modification de y n'est pas la question fondamentale ici. Oui, c'est autre chose qu'il faut gérer. Le problème ici est que l'ensemble d'échantillons passé hors du rééchantillonnage n'est pas nécessairement l'ensemble passé. Ce type d'opération (dont le rééchantillonnage est emblématique, mais je suis heureux de lui trouver un meilleur nom) est fréquemment requis pour la formation, et est rarement la bonne chose à faire au moment du test lorsque vous voulez que les prédictions correspondent aux entrées.

Non seulement le "se produit principalement [dans un contexte de pipeline] au moment de l'ajustement" (et oui, comme ci-dessus, il y a des cas où un modèle d'ajustement sera réappliqué, en particulier la détection des valeurs aberrantes) le distingue des transformateurs qui doivent également s'appliquer au moment de l'ajustement et runtime, mais l'idée que la taille de l'échantillon peut changer.

Alors peu importe de modifier y . Un transformateur qui permet à la taille de l'échantillon de changer ne peut pas être utilisé dans un FeatureUnion . Un transformateur qui permet à la taille de l'échantillon de changer ne peut pas être utilisé dans un Pipeline moins qu'il ne modifie y aussi parce que score va se casser, mais même ainsi, cela semble une définition étrange de la notation un jeu de données s'il est modifié en tant que tel.

Ainsi, même si la refonte de l'API du transformateur peut être souhaitable, il existe une valeur IMO dans un type distinct d'estimateur qui : (a) a un effet sur un Pipeline pendant la formation et aucun autrement ; (b) est autorisé à modifier la taille de l'échantillon, où Transformer s ou leurs successeurs devraient continuer à ne pas le faire.

L'idée du nom « rééchantillonnage » est que le travail le plus important de cette classe d'estimateurs est de modifier la taille de l'échantillon d'une manière ou d'une autre, en suréchantillonnant, autrement en repondérant, en compressant ou en incorporant des instances non étiquetées provenant d'ailleurs.

Un transformateur qui permet à la taille de l'échantillon de changer ne peut pas être utilisé dans un
FeatureUnion.

C'est l'argument qui me manquait. Merci! Y a-t-il d'autres cas ?

L'idée du nom "resample" est que le travail le plus important de ce
d'estimateurs consiste à modifier la taille de l'échantillon d'une manière ou d'une autre, en
suréchantillonnage, autrement repondération, compression ou incorporation
instances non étiquetées d'ailleurs.

Sur la base de vos arguments justifiant la nécessité de la nouvelle classe, j'ai été
penser au nom. Et en effet, il devrait tourner autour de la notion
d'échantillon, et peut-être même le terme "échantillon", car c'est ce que nous utilisons dans
scikit-apprendre. Le terme le plus explicite serait "transform_samples", mais je
pense que c'est trop long (nous pourrions avoir besoin de choses comme
"fit_transform_samples").

Une chose qui m'inquiète cependant, c'est que si nous introduisons un
"rééchantillonner" et conserver l'ancienne méthode "transformer", ce sera ambigu
un pipeline signifie. Bien sûr, nous pouvons introduire un argument à la
pipeline ou créez une nouvelle variante de pipeline. Cependant, je crains que
la complexité supplémentaire pour les utilisateurs et les développeurs ne justifie pas la création
l'objet supplémentaire par rapport aux Transformers. Dans d'autres temps, je pense
qu'on ferait mieux de dire que certains transformateurs changent le
nombre d'échantillons (et nous pouvons créer une sous-classe supplémentaire pour cela).

Et cette sous-classe de transformateurs fonctionnerait-elle également uniquement au moment de l'ajustement ? Je pense que c'est suffisamment différent pour motiver une autre famille d'estimateurs, mais je peux me tromper.

Ce type de pipeline d'estimateurs peut également être facilement modélisé en tant que méta-estimateurs. Le seul vrai problème est l'imbrication inconfortable des noms de paramètres (bien que j'aie déjà joué avec un peu de magie qui permet à une structure imbriquée d'être encapsulée afin que les

Et cette sous-classe de transformateurs fonctionnerait-elle également uniquement au moment de l'ajustement ?

Y a-t-il une raison pour laquelle un fit_transform ne résoudrait pas ce problème ?

fit_transform résout ce composant si fit_transform et fit().transform peuvent avoir des résultats différents. Je pense que les transformateurs sont suffisamment déroutants pour de nombreux utilisateurs, même s'ils promettent plus ou moins l'équivalence fonctionnelle de fit_transform et fit().transform .

fit_transform résout ce composant si fit_transform et
fit().transform sont autorisés à avoir des résultats différents. je pense
les transformateurs sont suffisamment déroutants pour de nombreux utilisateurs, même s'ils sont plus ou moins
promettant l'équivalence fonctionnelle de fit_transform et
fit().transform.

Assez clairement, je suis d'accord avec vous pour dire que rompre cette équivalence serait une
très mauvaise idée.

Mais je ne sais pas pourquoi il serait nécessaire (bien que je commence à
comprendre, je ne suis pas encore convaincu qu'il n'est pas possible de
implémenter une méthode de transformation qui a la logique nécessaire pour avoir le
correspondance entre fit().transform et fit_transform).

Je prépare quelques exemples pour que nous ayons quelque chose à signaler dans
discussion, mais cela prend plus de temps que d'écrire des réponses rapides !

Le 17 novembre 2014 à 20h45, Gael Varoquaux [email protected] a écrit :

fit_transform résout ce composant si fit_transform et
fit().transform sont autorisés à avoir des résultats différents. je pense
les transformateurs sont suffisamment déroutants pour de nombreux utilisateurs, même s'ils sont plus ou moins
promettant l'équivalence fonctionnelle de fit_transform et
fit().transform.

Assez clairement, je suis d'accord avec vous pour dire que rompre cette équivalence serait une
très mauvaise idée.

Mais je ne sais pas pourquoi il serait nécessaire (bien que je commence à
comprendre, je ne suis pas encore convaincu qu'il n'est pas possible de
implémenter une méthode de transformation qui a la logique nécessaire pour avoir le
correspondance entre fit().transform et fit_transform).

-
Répondez directement à cet e-mail ou consultez-le sur GitHub
https://github.com/scikit-learn/scikit-learn/issues/3855#issuecomment -63280553
.

Je prépare quelques exemples pour que nous ayons quelque chose à signaler dans
discussion, mais cela prend plus de temps que d'écrire des réponses rapides !

Merci. C'est très utile !

Merci d'avoir relancé la discussion à ce sujet.
Donc, avec la mise en œuvre de quelque chose qui, par exemple, rééchantillonne les classes à des tailles égales pendant la formation, il y a trois problèmes distincts :

1) Cela change y.
2) Il rééchantillonne pendant l'entraînement, mais nous voulons avoir des prédictions pour tous les échantillons pendant la durée du test.
3) Cet estimateur ne peut pas être FeatureUnion 'ed avec autre chose.

Le premier pourrait être résolu en changeant le comportement des transformateurs, pour les deux autres, ce qu'il faut faire n'est pas aussi évident.
Je pense que nous pourrions quand même nous en sortir avec l'interface du transformateur.
Je ne m'inquiéterais pas trop à propos de 3). Je pense que soulever une erreur raisonnable lorsque quelqu'un essaie ce serait bien. Cela devrait être assez facile à détecter.

3) est peut-être la plus délicate car elle nécessitera certainement un nouveau mécanisme et nous devons être prudents si cela vaut la peine d'ajouter cette complexité.
Que diriez-vous d'ajouter transform(X, y, fit=False) ou transform(X, y, filter=False) ou quelque chose de mot-clé, qui contrôle si la suppression d'échantillons est autorisée ou non.
Dans un pipeline, l'option pourrait alors dépendre du fait que quelqu'un ait appelé « fit » ou non.

Cela me fait réfléchir : dans quels cas nous voulons un comportement différent lors de l'ajustement et de la prédiction ? Voulons-nous toujours rééchantillonner pendant l'apprentissage, mais pas pendant la prédiction ? Que se passe-t-il si nous voulons effectuer une visualisation et filtrer les valeurs aberrantes pour les deux ?

@jnothman

Pour autant que je comprends cette discussion, (désolé si j'ai raté quelque chose, j'ai juste parcouru rapidement, en particulier les parties qui disent Birch :P ), vous voulez dire sous-classer Birch (et d'autres méthodes de réduction d'instance) d'une nouvelle classe d'estimateurs , appelé Resamples, et dont nous appelons la méthode fit_resample pendant le fit de Pipeline, n'est-ce pas ?. Quelques questions naïves pour commencer.

  1. D'une certaine manière (comme dans Birch), on peut voir les centroïdes obtenus à partir de MBKMeans (et d'autres clusterers), comme une réduction d'instance, en particulier lorsque n_clusters est suffisamment grand, comment tracer une ligne entre si un fit_resample ou un fit_transform doit être appelé ?
  2. Quelles sont les méthodes de transformation des transformateurs généralement utilisées dans un pipeline ? Il me semble qu'utiliser brc.subcluster_centers_ pourrait être beaucoup plus utile que de transformer les données d'entrée dans l'espace subcluster_centers_ , surtout lorsqu'elles sont redirigées avec AgglomerativeClustering et. al qui est ce qui est fait en interne.

@MechCoder

Premièrement, je ne suis pas sûr que la réimplémentation de BIRCH soit ce que j'ai l'intention ici. C'est plus que ce type d'algorithme peut être présenté comme un pipeline de réduction, de clustering, etc. Il devrait y avoir une _bonne façon_ de bricoler des estimateurs dans ce genre de choses dans scikit-learn, dans la mesure où cela est facilité par l'API. En ce qui concerne la réimplémentation de BIRCH lui-même, le rééchantillonneur pourrait être retiré en tant que composant séparé, et le clusterer complet peut également être proposé.

Oui, l'utilisation de MBKmeans pour la réduction d'instance est également applicable ; le fait qu'il arrive à définir transform avec une sémantique différente signifie que, quelle que soit la manière dont il est encapsulé en tant que rééchantillonneur, il doit apparaître comme une classe distincte (un peu comme WardAgglommeration et Ward sont des classes distinctes).

Les classifieurs ou clusterers ou régresseurs qui implémentent transform sont un peu problématiques en général car, comme vous le suggérez, la sémantique de la transformation associée n'est pas forcément inhérente au prédicteur, ne sont pas forcément décrites dans les mêmes textes de référence comme prédicteur, etc. Par exemple, bien que dans #2160 suggérant que pour la cohérence tous les estimateurs avec coef_ ou feature_importances_ devraient également avoir _LearntSelectorMixin pour agir en tant que sélecteur de caractéristique, je plus tard, nous avons pensé que l'approche du #3011, désormais obsolète, serait plus appropriée, où nous remplaçons ce mixin par un moyen d'envelopper un classificateur/régresseur afin qu'il agisse comme un sélecteur de fonctionnalités ; alternativement, une méthode d'un classificateur/régresseur comme .as_feature_selector() pourrait effectuer la même magie. L'idée est de séparer plus clairement modèle et fonction.

@amueller

3) est peut-être le plus délicat

Vouliez-vous dire (2) ?

dans quels cas nous voulons un comportement différent lors de l'ajustement et de la prédiction ? Voulons-nous toujours rééchantillonner pendant l'apprentissage, mais pas pendant la prédiction ? Que se passe-t-il si nous voulons effectuer une visualisation et filtrer les valeurs aberrantes pour les deux ?

Je pense que c'est une question clé. Il doit certainement y avoir un moyen de réappliquer le rééchantillonnage ajusté le cas échéant ; la visualisation en est un bon exemple. Pourtant, ce n'est peut-être pas grave d'attendre des utilisateurs qu'ils se passent de la magie du pipeline.

@jnothman oui, je voulais dire (2).
Désolé, je ne suis pas sûr de comprendre votre réponse.
Qu'entendez-vous par "sans la magie du pipeline" ? Que les utilisateurs ne devraient pas pouvoir utiliser le pipeline dans ce cas ? Ou que l'heuristique de ne pas appliquer le rééchantillonnage pour predict , score ou transform devrait être la valeur par défaut mais il devrait y avoir une option pour ne pas utiliser cette heuristique ?

Au fait, cette heuristique ne me donne aucune option pour calculer le score sur l'ensemble d'apprentissage qui a été utilisé, ce qui est un peu étrange.

Je n'en suis pas entièrement satisfait, mais j'ai simulé quelques exemples (pas des tracés, juste du code d'utilisation) sur https://gist.github.com/jnothman/274710f945e311697466

Qu'entendez-vous par "sans la magie du pipeline" ? Que les utilisateurs ne devraient pas pouvoir utiliser le pipeline dans ce cas ?

Je veux dire qu'actuellement, il y a des cas où Pipeline ne peut raisonnablement pas être utilisé. C'est particulièrement utile pour les recherches de grille, etc., où le clonage et le paramétrage sont impliqués, tout en exigeant la visualisation des inliers pour ne pas utiliser un objet Pipeline ne fait probablement pas trop de mal à l'utilisateur.

Je suis d'accord qu'il est un peu contrariant que ce modèle ne fournisse pas un moyen de calculer le score d'entraînement.

Pour résumer une discussion avec @GaelVaroquaux , nous avons tous les deux pensé que briser l'équivalence de fit().transform() et fit_transform pourrait être une voie à suivre viable. fit_transform sous-échantillonnerait, mais pas fit().transform() .

Je pense qu'il est temps de régler ça. Nous cassons déjà fit_transform et transformons l'équivalence ailleurs.

Mais êtes-vous sûr que nous voulons permettre à fit_transform de retourner (X, y, props) parfois et seulement X à d'autres ? Avons-nous alors besoin que la transformation ne renvoie que X ou est-il également autorisé à modifier y (je pense que nous ne devrions pas lui permettre de modifier y ; c'est une mauvaise idée pour l'évaluation).

Nous avons également un petit problème dans la gestion des fit_params par le pipeline : tout fit_params en aval d'un rééchantillonneur ne peut pas être utilisé et devrait générer une erreur. (Tout accessoire renvoyé par le rééchantillonneur doit être interprété avec la stratégie de routage du pipeline.) En effet, il s'agit peut-être d'un défaut de conception dans le pipeline, mais la gestion des échantillons d'accessoires et y suppose que la sortie de fit_transform est alignée sur l'entrée, échantillon pour échantillon .

Je trouve ces arguments ensemble convaincants pour suggérer que cela mérite une méthode distincte, par exemple fit_resample, pas seulement une option pour qu'un transformateur renvoie un tuple qui entraîne une gestion très différente. Cependant, je ne pense pas que nous devrions avoir une méthode d'échantillonnage correspondante (et trouver la méthode Pipeline.sample d'imblearn assez problématique). Au moment du test, transform doit être appelé, sinon nous pourrions envisager que tous les rééchantillonneurs effectuent la transformation d'identité au moment du test. (Sur les objets prenant en charge fit_resample, fit_transform devrait être interdit.)

Faisons en sorte que cela se produise.

Je pense que pour l'instant, nous devrions interdire aux rééchantillonneurs d'implémenter la transformation, car les cas d'utilisation courants sont les transformations d'identité, et autoriser la transformation est alors possible à l'avenir sans rompre la compatibilité descendante.

Proposition de travail sur ce et #9630 :

Mise en œuvre

  1. Créez un OutlierDetectorMixin comme exemple concret d'un estimateur avec fit_resample . fit_resample est défini pour renvoyer (X, y, props) correspondant uniquement aux inliers. De cette façon, les détecteurs de valeurs aberrantes agiront comme des éliminateurs de valeurs aberrantes dans un pipeline une fois le reste du travail terminé (voir #9630). Ils ne sont ici qu'à titre d'exemple tangible d'un rééchantillonneur. props est simplement un dict de paramètres qui seraient passés pour s'adapter. {'sample_weight': [...]} ou {} plus souvent.
  2. Hériter de OutlierDetectorMixin cas échéant. Essaye-le.
  3. Étendre les tests communs pour couvrir les rééchantillonneurs. Cela devrait:

    • vérifiez que la sortie de fit_resample est de structure correcte

    • vérifier que la sortie de fit_resample a des longueurs cohérentes

    • vérifiez que la sortie de fit_resample est cohérente pour les appels répétés

    • affirmer qu'avoir fit_resample signifie pas de fit_transform ou transform

  4. gérer fit_resample dans Pipeline.fit , en s'assurant que les accessoires sont gérés correctement (aucun accessoire ne doit déjà être défini pour les étapes du pipeline en aval ; les accessoires renvoyés doivent être interprétés comme Pipeline.fit 's fit_params sont)
  5. effectuer une transformation d'identité pour les rééchantillonneurs dans Pipeline.{transform,predict,...}
  6. ? ajouter la méthode fit_resample aux Pipelines dont la dernière étape a fit_resample
  7. peut-être implémenter d'autres rééchantillonneurs (par exemple suréchantillon), peut-être basé sur #1454

Documentation

  1. ajouter/modifier un exemple de suppression de valeurs aberrantes
  2. discuter de la suppression des valeurs aberrantes dans les documents de détection des valeurs aberrantes
  3. discuter des rééchantillonneurs dans les documents Pipeline
  4. ajouter OutlierDetectorMixin à classes.rst
  5. mentionner OutlierDetectorMixin dans le glossaire sous détecteur de valeurs aberrantes
  6. entrée pour resampler dans le glossaire
  7. décrire les rééchantillonneurs dans la documentation des développeurs

Je suis heureux d'ouvrir ceci à un contributeur (ou à un GSoC) si d'autres pensent que c'est la bonne voie à suivre.

Ping @glemaitre

  1. peut-être implémenter d'autres rééchantillonneurs (par exemple suréchantillon), peut-être basé sur #1454

Pensez-vous que OutlierDetectorMIxin sera un bon nom pour les rééchantillonneurs ?

Un détecteur de valeurs aberrantes est une sorte de rééchantillonneur qui supprime les valeurs aberrantes. Tous les rééchantillonneurs ne sont pas des détecteurs de valeurs aberrantes.

L'idée est de commencer par implémenter quelque chose de tangible, plutôt qu'une API ou un pipeline abstrait qui ne peut pas être testé.

J'ai précisé plus haut.

D'ACCORD. Pourriez-vous créer un lien vers le PR ou le problème des accessoires. Sinon le plan semble bon.
Peut-être devrions-nous ajouter que les différentes méthodes doivent réussir le test commun des estimateurs_checks.

Par accessoires, je veux simplement dire un dict de paramètres qui serait transmis pour s'adapter. {'sample_weight': [...]} ou {} plus souvent.

Cela ressemble à un projet très intéressant. J'aimerais explorer davantage et demander de l'aide en cas de doute.

J'ai marqué cette aide et j'aimerais vraiment voir quelqu'un poursuivre https://github.com/scikit-learn/scikit-learn/issues/3855#issuecomment -357949997, ne serait-ce que pour que nous ayons une implémentation concrète à atteindre consensus sur.

Je nommerais le Mixin comme ResamplerMixin ou SamplerMixin . De plus, je nommerais la méthode fit_sample pour être en ligne avec l'apprentissage déséquilibré.

Je pense que faire cela en accord avec l'apprentissage du déséquilibre serait bien et nous devrions simplement adopter leurs trucs. cc @NicolasHug aussi ;)

je pourrais travailler dessus

allez-y, je dirais !

Je serais heureux de voir cela avancer. Ping moi si je peux aider :)

Je me souviens de certains comportements bizarres dans imblearn que je ne veux pas reproduire
ici. Les estimateurs génératifs prennent en charge une méthode d'échantillonnage afin que fit_sample sonne
comme autre chose. Il me semble également que l'utilisateur naïf s'attendrait à
cela signifie « ajustement sur un échantillon », c'est-à-dire un ajustement partiel. Donc je suis contre fit_sample

Je me souviens de fit_resample de votre main si je ne me trompe pas ?

Quoi d'autre ne me dérange pas, je n'aime tout simplement pas fit_sample

Il me semble également que l'utilisateur naïf s'attendrait à ce que cela signifie "
sur un échantillon", c'est-à-dire ajustement partiel. Je suis donc contre fit_sample

+1

C'est un peu fastidieux, mais c'était mon implémentation pour un pipeline sklearn qui peut rééchantillonner :

https://github.com/dmbee/seglearn/blob/master/seglearn/pipe.py

Je ne pense pas que nous puissions réutiliser le verbe transformer. Et je ne pense pas que nous puissions
transformer y au moment du test. Pourquoi avez-vous pensé qu'il était approprié de le faire dans
apprendre?

Je suis d'accord avec toi Joel que la plupart des cas d'utilisation n'auront pas besoin ou même interdire le rééchantillonnage pendant le test.

seglearn traite des séries/séquences temporelles et le rééchantillonnage est toujours nécessaire au test pour segmenter les données. Je ne sais pas si d'autres applications nécessiteraient également un rééchantillonnage lors du test. Aucun ne me vient à l'esprit pour le moment.

Dans tous les cas, vous pouvez utiliser le verbe transformer pour le rééchantillonneur (comme je l'ai fait) et l'appeler uniquement pendant l'ajustement / la transformation. Cependant, la mise en œuvre que vous avez proposée a également du sens. Je viens de poster mon implémentation comme exemple de travail.

Heureux d'aider si nécessaire.

  • David

@dmbee , vous êtes invités à aider avec une contribution ici. Nous avons besoin de quelqu'un capable et dévoué pour faire avancer cela avec le mentorat de l'équipe de développement de base.

@jnothman - ok, je vais commencer et

@jnothman - J'ai une question sur votre implémentation proposée :

sample_weight est transmis au pipeline pendant fit / fit_transform / fit_predict dans le cadre de **fit_params et doit être préfixé par l'étiquette de l'estimateur final (par exemple 'logreg__sample_weight')

Je pense que la solution la plus propre consiste à faire vérifier le pipeline si *__sample_weight est dans fit_params et à le transmettre en tant que sample_weight au rééchantillonneur. Le rééchantillonneur renverra alors (X, y, sample_weight), qui peut être utilisé pour écraser sample_weight pour l'estimateur final.

Je ne sais pas pourquoi vous voulez qu'un accessoire de dictionnaire soit renvoyé par fit_resample ? Étant donné que chaque étape du pipeline ne reçoit que les fit_params qui lui sont attribués à l'aide de l'API de préfixe.

Acclamations,
David

Voici à peu près le modèle qui, selon moi, pourrait bien fonctionner pour les rééchantillonneurs : :

class ResamplerMixin(object):

    def fit_resample(self, X, y, **fit_params):
        sample_weight = None
        if 'sample_weight' in fit_params:
            sample_weight = fit_params.pop('sample_weight')

        return self.fit(X, y, **fit_params).resample(X, y, sample_weight)

    def fit(self, X, y):
        return self

    def resample(self, X, y, sample_weight):
        return X, y, sample_weight

Vous posez les bonnes questions, donc c'est très encourageant :)

Je ne sais pas pourquoi vous voulez qu'un accessoire de dictionnaire soit renvoyé par fit_resample ? Étant donné que chaque étape du pipeline ne reçoit que les fit_params qui lui sont attribués à l'aide de l'API de préfixe.

Eh bien, nous avons un problème que nous ne sommes pas vraiment d'accord sur la conception d'un exemple de mécanisme de routage de propriétés, et celui de Pipeline pour le moment n'est tout simplement pas conçu pour fonctionner lorsque les propriétés ne peuvent pas être spécifiées à chaque étape lorsque fit est appelé.

Mais si nous voulons que fit_resample puisse modifier ou générer sample_weight alors il doit pouvoir modifier ou générer d'autres choses (non spécifiées) qui s'alignent sur chaque échantillon ; l'alignement sur les échantillons originaux n'a pas de sens. D'où un dict.

Cependant, la gestion de cela dans un pipeline est ouverte au débat

aucun accessoire ne doit déjà être défini pour les étapes de pipeline en aval

Je pense que cela doit être le cas.

les accessoires renvoyés doivent être interprétés comme les fit_params de Pipeline.fit sont

Pour l'instant, j'envisagerais de lever une erreur NotImplementedError si dans un pipeline et que le dict n'est pas vide, et nous pourrons déterminer quel comportement approprié devrait être une fois que nous aurons élaboré un exemple de routage d'accessoires (puis-je avoir le temps d'y réfléchir !). ..

Merci Joël. Je suis presque sûr de comprendre ce que vous recherchez. Essentiellement:

Certains fit_params (par exemple, sample_weight et peut-être d'autres) sont liés aux échantillons et doivent être modifiés en conséquence par les rééchantillonneurs pour tout estimateur en aval. Appelons ces sample_props.

Une implémentation rétrocompatible qui impliquerait le moins de changements à l'API (transformateurs existants, estimateurs, etc.) pourrait être la suivante.

Ajoutez un paramètre facultatif aux routines d'ajustement du pipeline appelé sample_props. Il s'agit d'une liste de chaînes qui correspondent aux clés des fit_params qui sont des sample_props et qui doivent être modifiées par les rééchantillonneurs. Les paramètres pertinents peuvent ensuite être transmis et mis à jour par les rééchantillonneurs. La routine pipeline _fit est modifiée pour obtenir les fit_params appropriés à chaque étape comme suit :

for step_idx, (name, transformer) in enumerate(self.steps[:-1]):

    fit_params_step = {key.split('__', 1)[1]: fit_params.pop(key) for key in fit_params if name + "__" in key};

    if isinstance(transformer, ResamplerMixin):
        props = {key : fit_params[key] for key in sample_props}
        X, y, props = transformer.fit_resample(X, y, **fit_params_step, props)
        fit_params.update(props)


    else: ... # is a regular transfomer

Aucune précipitation pour prendre cette décision d'architecture, mais j'aimerais avoir un plan avant d'aller de l'avant avec l'écriture du code.

édité pour utiliser pop pour éviter de recalculer sample_props pour les transformateurs en amont

Ne vous inquiétez pas pour la routine d'ajustement du Pipeline en particulier. S'inquiéter de la
API fit_resample. En général, les méthodes d'ajustement peuvent prendre des paramètres supplémentaires
au-delà (X, y) qui sont alignés avec X, c'est-à-dire des exemples d'accessoires. je crois
fit_resample doit être capable de retourner de telles choses ainsi que de les prendre comme
contribution. Comment ils sont ensuite traités dans un pipeline est une question ouverte, et l'OMI
nous n'avons pas encore besoin de nous engager là-dessus pour créer l'API de rééchantillonnage.

Assez juste. Je suppose que la modification du pipeline était la partie que j'ai trouvée la plus intéressante. Dans tous les cas, cela vous convient-il comme ébauche de l'API ?

class ResamplerMixin(object):

    def fit_resample(self, X, y, **fit_params, props=None ):
        return self.fit(X, y, **fit_params).resample(X, y, props)

class TakeOneSample(BaseEstimator, ResamplerMixin):

    def __init__(self):
        pass        

    def fit(self, X, y=None):
        return self

    def resample(self, X, y, props):
        return X[0], y[0], {k : v[k][0] for k in props}

Je ne connais aucun cas d'utilisation qui nécessite une méthode de rééchantillonnage, vraiment, et il
complique certainement les choses dans Pipeline : pourquoi changer l'ensemble des
échantillons au moment du test, et comment cela affecterait-il la notation d'un pipeline
prédictions ?

C'est-à-dire que je propose de prendre en charge fit_resample, mais pas resample.

pourquoi modifierions-nous l'ensemble d'échantillons au moment du test et comment cela affecterait-il la notation des prédictions d'un pipeline ?

Oui, changer le nombre d'échantillons au moment du test est une sémantique qui est
pas clair pour moi. Je préférerais m'en détourner.

+1 pour n'avoir défini que fit_resample dans le Mixin. Je ne me souviens d'aucun cas d'utilisation n'ayant que resample .

En ce qui concerne l'implémentation de Pipeline , je pense que les changements effectués dans l'implémentation d'imblearn devraient faire l'affaire ou au moins un bon début. Il restera le problème concernant la gestion des props .

Concernant la gestion des sample_props dans le rééchantillonneur lui-même, il semble que @dmbee irait dans le même sens que ce que nous pensions gérer sample_weight :
https://github.com/scikit-learn-contrib/imbalanced-learn/pull/463/files

@dmbee n'hésite pas à refaire une partie du code/tests de imblearn . Vous pouvez également me cingler pour revoir le PR. Je vais redevenir actif dans scikit-learn partir de la semaine prochaine.

Je ne connais aucun cas d'utilisation nécessitant une méthode de rééchantillonnage, vraiment, et cela complique certainement les choses dans Pipeline : pourquoi modifierions-nous l'ensemble d'échantillons au moment du test et comment cela affecterait-il la notation des prédictions d'un pipeline ?

Ci-dessus, je n'avais pas l'intention de prendre en charge le rééchantillonnage au moment du test. Je comprends que c'est hors de portée ici / niche.

Autoriser des méthodes d'ajustement / rééchantillonnage séparées (au lieu de simplement fit_resample) n'affecte pas la façon dont le rééchantillonneur est utilisé dans le pipeline ou la complexité du pipeline à mon avis (voir mon code de pipeline ci-dessus). Il est venu à l'esprit qu'il peut être utile de séparer les méthodes d'ajustement et de rééchantillonnage pour certains cas d'utilisation potentiels (par exemple, le rééchantillonnage génératif).

Cependant, si cette capacité n'est pas souhaitable, nous pouvons utiliser une API très similaire pour ne pas comprendre l'ajout de la gestion de sample_props, ce qui est simple si le rééchantillonneur indexe simplement les données. Voir l'exemple approximatif ci-dessous.

Dis moi ce que tu penses?

import numpy as np
from sklearn.base import BaseEstimator
from abc import abstractmethod

class ResamplerMixin(object):

    def fit_resample(self, X, y, props=None, **fit_params): # gets called by pipeline._fit()
        self._check_data(X, y, props)
        return self._fit_resample(X, y, props, **fit_params)

    <strong i="11">@abstractmethod</strong> # must be implemented in derived classes
    def _fit_resample(self, X, y, props=None, **fit_params):
        return X, y, props

    def _check_data(self, X, y, props): # to be expanded upon
        if props is not None:
            if not np.all((np.array([len(props[k]) for k in props]) == len(y))):
                raise ValueError

    def _resample_from_indices(self, X, y, props, indices):
        if props is not None:
            return X[indices], y[indices], {k : props[k][indices] for k in props}
        else:
            return X[indices], y[indices], None


class TakeOneSample(BaseEstimator, ResamplerMixin):

    def __init__(self, index = 0):
        self.index = index

    def _fit_resample(self, X, y, props=None):
        return self._resample_from_indices(X, y, props, self.index)

@glemaitre - merci. Je n'ai certainement aucune envie de reproduire ce qui a été fait dans imblearn (j'aime et j'utilise ce package d'ailleurs !). Il semble que la principale chose qui manque à l'atm de imblearn est les changements de pipeline / rééchantillonneur requis pour prendre en charge sample_props. Sinon, il semble très compatible avec sklearn .

  • David

Je n'aime pas vraiment que nous nous engagions dans un format pour les exemples d'accessoires ici dans un sens, mais je suppose que ce n'est pas si différent de la gestion de fit_params dans le code de validation croisée en ce moment. Donc je pense que ça devrait être bon d'y aller.

Je n'ai certainement aucune envie de reproduire ce qui a été fait dans imblearn

En fait, vous devriez prendre tout ce qui fonctionne pour scikit-learn à partir d'imblearn. Notre idée est d'apporter ce qui est bon en amont et de retirer de notre base de code. Nous sommes à un stade où l'API commence à être plus stable et nous avons récemment apporté quelques modifications pour refléter certaines discussions avec @jnothman.

En bout de ligne, prenez tout ce qui est bénéfique pour scikit-learn ;)

Donc je pense que ça devrait être bon d'y aller.

Eh bien, en théorie, nous aurions besoin de travailler sur les SLEP.

Cependant, ce peut être un bon exercice de faire avancer cette question, afin de
être capable d'écrire un SLEP concis.

En fait, vous devriez prendre tout ce qui fonctionne pour scikit-learn à partir d'imblearn. Notre idée est d'apporter ce qui est bon en amont et de retirer de notre base de code.

OK bon à savoir - merci. J'aurais dû utiliser ré-implémenter plutôt que répliquer. Il semble que la plupart des éléments de imblearn puissent être facilement portés.

Eh bien, en théorie, nous aurions besoin de travailler sur les SLEP.

Je ne sais pas ce qu'est un SLEP...

Un SLEP est une proposition d'amélioration Scikit-learn (sous-utilisée). https://github.com/scikit-learn/enhancement_proposals/

En ce qui concerne la proposition d'API dans https://github.com/scikit-learn/scikit-learn/issues/3855#issuecomment -446690557, oui, cette approche de rééchantillonnage semble bonne... Tous les estimateurs ne prennent pas en charge fit_resample pouvez le faire à partir d'indices, mais je pense que vous en êtes conscient; les techniques de réduction d'échantillons ne le seront pas, par exemple.

En ce qui concerne la proposition d'API dans #3855 (commentaire) , oui, cette approche de rééchantillonnage semble bonne... Tous les estimateurs prenant en charge fit_resample ne peuvent pas le faire à partir d'indices, mais je pense que vous en êtes conscient ; les techniques de réduction d'échantillons ne le seront pas, par exemple.

OK bonnes choses. Oui - Je suis conscient que tous les rééchantillonneurs n'échantillonneront pas à partir d'indices. Ceux qui ne le font pas devront soit implémenter leur propre méthode de traitement des accessoires (s'il existe une option sensée - difficile à savoir avec certitude sans savoir ce qu'il y aura dans les accessoires), soit générer une erreur non implémentée si les accessoires ne sont pas nuls.

Est-ce que quelqu'un à Paris travaille là-dessus ? Je serais heureux de vous aider (et l'API serait utile pour l'ajustement des classificateurs semi-supervisés, comme discuté dans cette revue .)

Oui, j'ai commencé à porter l'implémentation imblearn. Voulez-vous en prendre d'autres et je peux vous aider pour l'examen à la place ?

Bien sûr, où puis-je vous trouver ?

J'ai commencé à travailler dessus (je ne suis pas à Paris), mais j'ai été trop occupé ces derniers mois. Je suis heureux de partager ce que j'ai déjà fait et de continuer à travailler dessus.

J'ai commencé à travailler dessus (je ne suis pas à Paris), mais j'ai été trop occupé ces derniers mois. Je suis heureux de partager ce que j'ai déjà fait et de continuer à travailler dessus.

Je commence à travailler là-dessus maintenant pour le sprint. Si vous avez des travaux existants qui, selon vous, pourraient être utiles, je serais plus qu'heureux de m'appuyer sur ce que vous avez fait.

le voici - regardez le dossier de rééchantillonnage dans sklearn
https://github.com/dmbee/scikit-learn/tree/dmbee-resampling

Cette page vous a été utile?
0 / 5 - 0 notes