
Arrêtez de blâmer les données : une meilleure façon de gérer le changement de covariance
Bien que les données tabulaires constituent le pain quotidien de la science des données industrielles, les changements de données sont souvent négligés lors de l’analyse des performances des modèles.
Nous sommes tous passés par là : vous développez un modèle d’apprentissage automatique, obtenez d’excellents résultats sur votre ensemble de validation, puis le déployez (ou le testez) sur un nouvel ensemble de données du monde réel. Du coup, les performances chutent.
Alors, quel est le problème ?
Habituellement, nous pointons du doigt Changement de covariance. La répartition des fonctionnalités dans les nouvelles données est différente de celle des données d’entraînement. Nous utilisons cela comme une carte « Sortir de prison gratuitement » : « Les données ont changé, donc naturellement, les performances sont inférieures. C’est la faute des données, pas celle du modèle. »
Mais et si nous arrêtions d’utiliser le changement de covariance comme excuse et commencions à l’utiliser comme outil ?
Je pense qu’il existe une meilleure façon de gérer cela et de créer un « étalon-or » pour analyser les performances des modèles. Cette méthode nous permettra d’estimer les performances avec précision, même lorsque le sol bouge sous nos pieds.
Le problème : comparer des pommes avec des oranges
Prenons un exemple simple du monde médical.
Imaginez que nous formions un modèle sur des patients âgés 40-89. Cependant, dans nos nouvelles données de tests cibles, la tranche d’âge est plus stricte : 50-80.
Si nous exécutons simplement le modèle sur les données de test et le comparons à nos scores de validation d’origine, nous nous induisons en erreur. Pour comparer « des pommes avec des pommes », un bon data scientist reviendrait à l’ensemble de validation, filtrerait les patients âgés de 50 à 80 ans et recalculerait les performances de base.
Mais rendons les choses plus difficiles
Supposons que notre ensemble de données de test contienne des millions d’enregistrements âgés de 50 à 80 ans, et un seul patient âgé de 40 ans.
- Comparons-nous nos résultats à la plage de validation 40-80 ?
- Devons-nous comparer à la fourchette 50-80 ?
Si l’on ignore la répartition spécifique par âge (ce que font la plupart des analyses standards), ce seul patient de 40 ans modifie théoriquement la définition de la cohorte. En pratique, nous pourrions simplement supprimer cette valeur aberrante. Mais que se passerait-il s’il y avait 100 ou 1 000 patients âgés de moins de 50 ans ? Pouvons-nous faire mieux ? Pouvons-nous automatiser ce processus pour gérer les différences plusieurs variables simultanément sans filtrer manuellement les données ? De plus, filtrer les données n’est pas une bonne solution. Il ne prend en compte que la bonne plage mais ignore le changement de distribution au sein de cette plage.
La solution : pondération de probabilité inverse
La solution consiste à repondérer mathématiquement nos données de validation pour ressembler les données d’essai. Au lieu d’une inclusion/exclusion binaire (conserver ou supprimer une ligne), nous attribuons une variable continue poids à chaque enregistrement de notre ensemble de validation. C’est comme une extension de la méthode de filtrage simple ci-dessus pour correspondre à la même tranche d’âge.
- Poids = 1: Analyse standard.
- Poids = 0: Exclure l’enregistrement (filtrage).
- Le poids est un flotteur non négatif: Sous-échantillonner ou sur-échantillonner l’influence du disque.
L’intuition
Dans notre exemple (Test : 50-80 ans + un 40 ans), la solution consiste à imiter la cohorte de test au sein de notre ensemble de validation. Nous voulons que notre validation soit définie sur «prétendre« Il a exactement la même répartition par âge que l’ensemble de test.
Remarque : Bien qu’il soit possible de transformer ces poids en inclusion/exclusion binaire via un sous-échantillonnage aléatoire, cela n’offre généralement aucun avantage statistique par rapport à l’utilisation directe des poids. Le sous-échantillonnage est principalement utile pour l’intuition ou si vos outils d’analyse des performances spécifiques ne peuvent pas gérer les données pondérées.
Les mathématiques
Formalisons cela. Nous devons définir deux probabilités :
- P.t(x) : la probabilité de voir la valeur de la caractéristique x (par exemple, l’âge) dans le Test cible données.
- P.v(x) : la probabilité de voir la valeur de la caractéristique x dans le Validation données.
Le poids w pour tout enregistrement donné avec la caractéristique x est le rapport de ces probabilités :
w(x) := P.t(x) / P.v(x)
C’est intuitif. Si les 60 ans sont rares en formation (Pv est faible) mais courant en production (Pt est élevé), le rapport est grand. Nous pondérons ces enregistrements en haut dans notre évaluation pour correspondre à la réalité. En revanche, dans notre exemple où l’ensemble de tests est strictement âgé de 50 à 80 ans, tout patient de validation en dehors de cette plage recevra un poids de 0 (puisque Pt(Âge)=0). Cela revient en fait à les exclure, exactement selon les besoins.
Il s’agit d’une technique statistique souvent appelée Importance de l’échantillonnage ou Pondération de probabilité inverse (IPW).
En appliquant ces pondérations lors du calcul des métriques (telles que la précision, l’AUC ou le RMSE) sur votre ensemble de validation, vous créez une cohorte synthétique qui correspond parfaitement au domaine de test. Vous pouvez désormais comparer des pommes avec des pommes sans vous plaindre du changement.
L’extension : gérer les changements de grande dimension
Faire cela pour une variable (Âge) est facile. Vous pouvez simplement utiliser des histogrammes/bacs. Mais que se passe-t-il si les données se déplacent simultanément sur des dizaines de variables différentes ? Nous ne pouvons pas construire un histogramme à une douzaine de dimensions. La solution est une astuce astucieuse utilisant un classificateur binaire.
Nous formons un nouveau modèle (un « modèle de propension », appelons-le Mp) pour faire la distinction entre les deux ensembles de données.
- Saisir: Les caractéristiques de l’enregistrement (âge, IMC, tension artérielle, etc.) ou les variables que nous souhaitons contrôler.
- Cible: 0 si l’enregistrement provient de la validation, 1 si l’enregistrement provient de l’ensemble de test.
Si ce modèle peut facilement distinguer les données (AUC > 0,5), cela signifie qu’il existe un décalage de covariable. L’AUC de Mp sert également d’outil de diagnostic. Il interprète la différence entre vos données de test et l’ensemble de validation et l’importance d’en tenir compte. Surtout, les résultats probabilistes de ce modèle nous donnent exactement ce dont nous avons besoin pour calculer les pondérations.
En utilisant le théorème de Bayes, le poids d’un échantillon x devient le chances que l’échantillon appartient à l’ensemble de test :
w(x) := Mp(x) / (1 – Mp(x))
- Si Mp(x) ~ 0,5, les points de données sont indiscernables et le poids est de 1.
- Si Mp(x) -> 1, le modèle est très sûr que cela ressemble aux données de test, et le poids augmente.

Note: L’application de ces pondérations n’entraîne pas nécessairement une baisse des performances attendues. Dans certains cas, la distribution des tests peut se déplacer vers des sous-groupes pour lesquels votre modèle est réellement plus précis. Dans ce scénario, la méthode augmentera ces instances et vos performances estimées en tiendront compte.
Est-ce que ça marche ?
Oui, comme par magie. Si vous prenez votre ensemble de validation, appliquez ces poids, puis tracez les distributions de vos variables, elles se superposeront parfaitement aux distributions de votre ensemble de test cible.
C’est encore plus puissant que ça : il aligne le distribution conjointe de toutes les variables, pas seulement leur distribution individuelle. Vos données de validation pondérées deviennent pratiquement impossibles à distinguer des données de test cibles lorsque le prédicteur est optimal.
Il s’agit d’une généralisation de la variable unique que nous avons vue plus tôt et donne exactement le même résultat pour une seule variable. Intuitivement Mp apprend les différences entre nos ensembles de données de test et de validation. Nous utilisons ensuite cette « compréhension » apprise pour contrer mathématiquement la différence.
Vous pouvez par exemple regarder cet extrait de code pour générer 2 distributions d’âge : une uniforme (ensemble de validation), l’autre distribution normale (ensemble de test cible), avec nos poids.

Extrait de code
import pandas as pd
import numpy as np
import plotly.graph_objects as go
df = pd.DataFrame({"Age": np.random.randint(40,89, 10000) })
df2 = pd.DataFrame({"Age": np.random.normal(65, 10, 10000) })
df2["Age"] = df2["Age"].round().astype(int)
df2 = df2[df2["Age"].between(40,89)].reset_index(drop=True)
df3 = df.copy()
def get_fig(df:pd.DataFrame, title:str):
if 'weight' not in df.columns:
df["weight"] = 1
age_count = df.groupby("Age")["weight"].sum().reset_index().sort_values("Age")
tot = df["weight"].sum()
age_count["Percentage"] = 100 * age_count["weight"] / tot
f = go.Bar(x=age_count["Age"], y=age_count["Percentage"], name=title)
return f, age_count
f1, age_count1 = get_fig(df, "ValidationSet")
f2, age_count2 = get_fig(df2, "TargetTestSet")
age_stats = age_count1[["Age", "Percentage"]].merge(age_count2[["Age", "Percentage"]].rename(columns={"Percentage": "Percentage2"}), on=["Age"])
age_stats["weight"] = age_stats["Percentage2"] / age_stats["Percentage"]
df3 = df3.merge(age_stats[["Age", "weight"]], on=["Age"])
f3, _ = get_fig(df3, "ValidationSet-Weighted")
fig = go.Figure(layout={"title":"Age Distribution"})
fig.add_trace(f1)
fig.add_trace(f2)
fig.add_trace(f3)
fig.update_xaxes(title_text='Age') # Set the x-axis title
fig.update_yaxes(title_text='Percentage') # Set the y-axis title
fig.show()
Limites
Bien qu’il s’agisse d’une technique puissante, elle ne fonctionne pas toujours. Il existe trois principales limites statistiques :
- Confondeurs cachés: Si le changement est causé par une variable que vous n’avez pas mesurée (par exemple, un marqueur génétique que vous n’avez pas dans vos données tabulaires), vous ne pouvez pas le prendre en compte. Cependant, en tant que développeurs de modèles, nous essayons généralement d’utiliser les fonctionnalités les plus prédictives de notre modèle lorsque cela est possible.
- Ignorabilité (manque de chevauchement) : Vous ne pouvez pas diviser par zéro. Si Pv(x) vaut zéro (par exemple, vos données d’entraînement ont Non patients de plus de 90 ans, mais l’ensemble de tests le fait), le poids explose à l’infini.
- Le correctif: Identifiez ces groupes qui ne se chevauchent pas. Si votre ensemble de validation ne contient littéralement aucune information sur une sous-population spécifique, vous devez explicitement exclure cette sous-population de la comparaison et la marquer comme « territoire inconnu ».
- Qualité du modèle de propension: Puisque nous nous appuyons sur un modèle (Mp) pour estimer les poids, toute inexactitude ou mauvais calibrage dans ce modèle introduira du bruit. Pour les changements de faible dimension (comme une seule variable « Âge »), cela est négligeable, mais pour les changements complexes de haute dimension, assurer Mp est bien calibré est essentiel.
Même si le modèle de propension n’est pas parfait en pratique, l’application de ces pondérations réduit considérablement le déplacement de la distribution. Cela fournit un indicateur beaucoup plus précis des performances réelles que de ne rien faire du tout.
Une note sur la puissance statistique
Sachez que l’utilisation de poids modifie votre Taille effective de l’échantillon. Des poids de variance élevés réduisent la stabilité de vos estimations.
Amorçage: Si vous utilisez le bootstrapping, vous êtes en sécurité tant que vous intégrez les poids dans le processus de rééchantillonnage lui-même.
Calculs de puissance: N’utilisez pas le nombre brut de lignes (N). Veuillez vous référer au Taille effective de l’échantillon formule (ESS de Kish) pour comprendre la véritable puissance de votre analyse pondérée.
Qu’en est-il des images et des textes ?
La méthode du modèle de propension fonctionne également dans ces domaines. Cependant, le principal problème d’un point de vue pratique est souvent ignorabilité. Il existe une séparation complète entre notre validation et l’ensemble de tests cible, ce qui conduit à l’incapacité de contrer le changement. Cela ne signifie pas que notre modèle fonctionnera mal sur ces ensembles de données. Cela signifie simplement que nous ne pouvons pas estimer ses performances sur la base de votre validation actuelle, ce qui est complètement différent.
Résumé
La meilleure pratique pour évaluer les performances du modèle sur des données tabulaires consiste à prendre strictement en compte le changement de covariance. Au lieu d’utiliser shift comme excuse pour de mauvaises performances, utilisez Pondération de probabilité inverse pour estimer les performances de votre modèle dans le nouvel environnement.
Cela vous permet de répondre à l’une des questions les plus difficiles du déploiement : « La baisse de performances est-elle due à la modification des données, ou le modèle est-il réellement défectueux ?
Si vous utilisez cette méthode, vous pouvez expliquer l’écart entre les mesures de formation et de production.
Si vous avez trouvé cela utile, connectons-nous sur LinkedIn



