Caractéristiques et moment de la cible
- Leçon 13
- 50 min
- Module 5 : Préparer la modélisation sans risque
Leçon 13 sur 18 · SQL et préparation des données pour l'IACaractéristiques et moment de la cible
1. Sources et structure des données
2. L'essentiel de SQL
3. Des requêtes d'analyse utiles
4. Nettoyer et transformer les données
5. Préparer la modélisation sans risque
6. Contrats de données et passation
Ce que vous saurez faire
Créez une table de modélisation où chaque colonne était connue au moment de l’arrivée du billet. Une colonne provenant du futur donne d’excellents résultats en test, mais rend le modèle inutile en pratique, sans aucune erreur.
Carnet JupyterFaites cette leçon dans un carnet Jupyter
Le carnet (notebook) Jupyter contient tous les scripts, tâches et vérifications de cette leçon, avec les instructions. Ses cellules de préparation installent pandas, téléchargent les données d’exercice et recréent les tables nettoyées du module 4. Il fonctionne donc sans le projet local. Lisez les explications ici et exécutez le code dans le carnet.
Le carnet est en anglais. Colab et Kaggle ouvrent votre propre copie. Il faut un compte Google ou Kaggle gratuit. Vous êtes bloqué ? Consultez le carnet de solution.
Avant de commencerCe qu’il faut savoir et avoir sous la main
Ce que vous devez savoir
- Lire et joindre des tables dans pandas (
read_csvavec des types,merge,groupby), selon Transformer avec Python. - Ce que le nettoyage a changé et pourquoi une valeur
order_valuemanquante a un sens, selon Traiter les valeurs désordonnées. - Utiliser les dates en SQL avec
datetime(…, '-90 days'), selon Le temps et le classement.
Ce qu’il vous faut sur votre ordinateur (seulement pour le travail local; le carnet n’en a pas besoin)
- Le dossier
~/projects/ticket-dataaveclarkfield.dbetq.py, selon Préparer une base de données d’exercice : créer la base de données. - L’environnement
.venvavec pandas 3.0.6, actif dans un terminal ouvert dans~/projects/ticket-data. Vous l’avez créé dans Profiler avant de modifier : le même profil dans pandas. Sipython -c "import pandas"échoue, activez de nouveau.venv(source .venv/bin/activatesur macOS et Linux,.venv\Scripts\Activate.ps1sur Windows). - Les tables nettoyées
data/clean/tickets.csv(1 398 lignes) etdata/clean/outcomes.csv(1 834 lignes). Vous les avez créées avecpython scripts/clean.pydans Traiter les valeurs désordonnées : exercice guidé : terminer clean.py. - Si les tables nettoyées manquent ou sont incorrectes, utilisez les scripts terminés du cours dans C04/pipeline. Téléchargez
queries/extract_tickets.sql,queries/extract_outcomes.sql,scripts/extract.pyetscripts/clean.pydans les mêmes dossiers de votre projet. Par exemple :curl -fsSL -o scripts/clean.py https://raw.githubusercontent.com/Nextia-Intelligence/nextia-learning-labs/main/C04/pipeline/scripts/clean.py(curl.exesur Windows). Exécutez ensuitepython scripts/extract.pyetpython scripts/clean.py. - Cette leçon ajoute
scripts/build_features.py,data/model/etqueries/50-prior-tickets.sql.
Testé sur macOS avec Python 3.14.6 et pandas 3.0.6. Les commandes Windows ne sont pas testées. Le carnet a été testé dans Jupyter.
La question de Larkfield
Section intitulée « La question de Larkfield »Larkfield, la boutique en ligne de produits pour la maison et le jardin, veut confier rapidement les billets difficiles à un agent principal. À l’arrivée d’un billet de soutien, un modèle donne un score : quelle est la probabilité que ce billet nécessite un agent principal? Ce cours prépare les données pour ce modèle. Les données sont inventées pour ce cours; elles ne concernent aucune personne réelle.
Les mots importants sont à l’arrivée d’un billet. C’est le moment de la prédiction : le moment où le modèle doit donner sa réponse. Tout ce que le modèle utilise doit exister à ce moment.
Un billet, du début à la fin
Section intitulée « Un billet, du début à la fin »Examinez le parcours du billet T-10033. Chaque événement remplit d’autres colonnes :
| Heure (9 janvier 2026) | Ce qui se passe | Colonnes remplies | Connues à l’arrivée du billet? |
|---|---|---|---|
| 8 h 31 min 54 s | Le client envoie un formulaire Web au sujet d’un paiement. | created_at, channel = web_form, team = payment, priority = 3, word_count = 61, order_value = 66,25 |
Oui |
| 9 h 24 min 54 s | Un agent répond pour la première fois, après 53 minutes. | first_reply_minutes = 53 |
Non |
| 10 h 45 min 45 s | Un agent principal prend le billet (événement de résultat O-00026, escalated (transféré à un niveau supérieur)). |
priority_now passe de 3 à 1 |
Non |
| 22 h 32 min 2 s | Le billet est résolu par un remboursement (O-00033). | closed_at, resolution_code, puis peut-être csat |
Non |
À 8 h 31 min 54 s, le modèle ne voit que la première ligne. Il ne peut pas savoir que la première réponse prendra 53 minutes. Il ne sait pas non plus qu’un agent principal prendra le billet deux heures plus tard. L’exportation du service de soutien contient les quatre lignes, car elle date du 1er juillet 2026, plusieurs mois plus tard. Voilà le piège : l’exportation connaît l’avenir de chaque billet, mais le modèle utilisé en pratique ne le connaît pas.
Trois termes pour la suite du cours :
- Une variable est une colonne que le modèle utilise comme entrée. Ici : des faits sur le billet au moment de la prédiction, comme
teametword_count. - La cible est la colonne que le modèle apprend à prédire. Certaines personnes l’appellent l’étiquette. Ici : un agent principal a-t-il pris le billet dans les 72 heures?
- Une fuite de données est une information dans les variables que le modèle n’aurait pas au moment de la prédiction. Elle concerne souvent la cible elle-même. Une variable avec fuite rend le score d’évaluation trop élevé. En pratique, cette information manque, et le modèle fait moins bien que ce que son score annonçait.
Définir la cible avec précision
Section intitulée « Définir la cible avec précision »« Transféré à un niveau supérieur » n’est pas assez précis. Transféré quand? Mei, l’ingénieure de données, définit la cible avec Grace, la responsable du soutien :
escalated_72h= 1 si le billet a un événement de résultatescalateddans les 72 heures aprèscreated_at; sinon 0.
Grace explique le choix des 72 heures : « Un agent principal prend la plupart des billets difficiles le premier jour. Un transfert après trois jours concerne habituellement un autre problème, par exemple un client qui revient mécontent. » Pour T-10033, le transfert a eu lieu 2 h et 14 minutes après la création, donc escalated_72h = 1.
Dans les données nettoyées, 224 billets ont un événement escalated. Parmi eux, 30 ont été transférés plus de 72 heures après leur création; leur cible vaut donc 0. Une définition précise change des lignes réelles.
Une cible a besoin de temps pour devenir définitive
Section intitulée « Une cible a besoin de temps pour devenir définitive »L’instantané date du 1er juillet 2026 à 6 h. Un billet créé le 30 juin à 20 h 04 n’avait qu’environ 10 heures pour être transféré avant l’exportation. S’il n’a pas encore d’événement de transfert, sa cible n’est pas 0. Elle est inconnue : les 72 heures ne sont pas écoulées.
La cible d’un billet est donc définitive seulement si sa création précède l’instantané d’au moins 72 heures :
snapshot − 72 hours = 2026-07-01 06:00 − 72 hours = 2026-06-28 06:00Parmi les billets nettoyés, 29 ont été créés après le 28 juin 2026 à 6 h. Six ont déjà été transférés. Les 23 autres semblent valoir 0, mais certains pourraient encore être transférés. Mei retire les 29 billets de la table de modélisation. Si elle les gardait, les billets les plus récents auraient trop de zéros. Le modèle apprendrait que les billets récents sont moins souvent transférés. C’est faux; leur parcours n’est simplement pas terminé.
Ce que chaque colonne sait
Section intitulée « Ce que chaque colonne sait »Mei classe chaque colonne des billets nettoyés dans l’un de trois groupes. Pour chaque colonne, elle pose une question : quand cette valeur est-elle écrite?
| Colonne | Moment où la valeur est écrite | Utilisation |
|---|---|---|
ticket_id, customer_id |
À la création | Identifiants, pas des variables. Ils désignent la ligne. |
created_at |
À la création | Sert à créer des variables et à séparer les données selon le temps. Ce n’est pas une variable en soi. |
channel, team, priority, order_value, word_count |
À la création | Variables. |
segment, region, joined_on |
Avant la création (dans la table des clients) | Variables (joined_on devient customer_tenure_days). |
first_reply_minutes |
Après la première réponse | Jamais une variable. |
priority_now |
Change pendant le parcours du billet. Prend la valeur 1 lors du transfert à un niveau supérieur. | Jamais une variable. |
closed_at |
À la résolution | Jamais une variable. |
Événements de résultat : status, resolution_code, csat |
Après la création | Seulement pour la cible, jamais comme variables. |
Regardez priority et priority_now. Leurs noms sont presque identiques et leurs valeurs vont de 1 à 3. L’une décrit un fait à la création. L’autre garde une trace de ce qui s’est passé ensuite. Le nom d’une colonne ne dit pas quand une valeur a été écrite. Demandez à la personne qui connaît le système, ici Grace.
Historique du client : le passé seulement
Section intitulée « Historique du client : le passé seulement »L’historique d’un client peut aider le modèle. Un client qui a écrit cinq fois ce mois-ci peut être mécontent. Mais les fuites de données se cachent facilement dans l’historique.
Le client C-0094 a six billets dans la table de modélisation. L’un d’eux, T-11014, a été transféré à un niveau supérieur en mai. Comparez deux façons de décrire ce client pour chaque billet :
| Billet | Création | prior_tickets_90d (billets des 90 jours précédents) |
Tous les billets du client | Taux de transfert du client, tous les billets |
|---|---|---|---|---|
| T-10072 | 2026-01-14 | 0 | 6 | 1 sur 6 = 0,17 |
| T-10350 | 2026-02-19 | 1 | 6 | 0,17 |
| T-10464 | 2026-03-04 | 2 | 6 | 0,17 |
| T-11014 | 2026-05-13 | 2 | 6 | 0,17 |
| T-11085 | 2026-05-22 | 2 | 6 | 0,17 |
| T-11241 | 2026-06-11 | 2 | 6 | 0,17 |
Les deux colonnes de droite contiennent des fuites. Le 14 janvier, personne ne savait que C-0094 créerait six billets ni que l’un serait transféré en mai. La valeur 0,17 de T-10072 contient de l’information du futur. Pire encore, le taux de transfert contient la cible de T-11014 lui-même.
prior_tickets_90d compte seulement les billets du même client créés dans les 90 jours avant celui-ci. Pour T-11241, créé le 11 juin, les 90 jours commencent le 13 mars. T-11014 et T-11085 comptent donc, et la valeur est 2. Chaque valeur était connue au moment de l’arrivée de son billet. Dans la leçon 3, vous mesurez à quel point le taux de transfert avec fuite gonfle un score.
Exemple détaillé : build_features.py
Section intitulée « Exemple détaillé : build_features.py »Mei rassemble ces décisions dans un script. Il lit les fichiers nettoyés, crée la cible, retire les billets trop récents et ajoute les variables.
"""Build the modelling table: one row per ticket, with only the facts knownwhen the ticket is created, and the target, escalated_72h."""
import jsonfrom pathlib import Path
import pandas as pd
IN = Path("data/clean")OUT = Path("data/model")SNAPSHOT = pd.Timestamp("2026-07-01 06:00:00") # from data/extract/manifest.jsonWINDOW = pd.Timedelta(hours=72)TIME_FORMAT = "%Y-%m-%d %H:%M:%S"
# Columns filled in after the ticket is created. They describe the future of# the ticket, so they must not be features.AFTER_CREATION = ["priority_now", "first_reply_minutes", "closed_at"]FEATURES = ["channel", "team", "priority", "segment", "region", "order_value", "word_count", "customer_tenure_days", "prior_tickets_90d", "created_hour"]
def main(): tickets = pd.read_csv(IN / "tickets.csv", parse_dates=["created_at", "joined_on"], dtype={"customer_id": "string"}, keep_default_na=False, na_values=[""]) outcomes = pd.read_csv(IN / "outcomes.csv", parse_dates=["recorded_at"])
# Target: an escalation within 72 hours of creation. first_escalation = outcomes[outcomes["status"] == "escalated"].groupby("ticket_id")["recorded_at"].min() tickets["escalated_at"] = tickets["ticket_id"].map(first_escalation) tickets["escalated_72h"] = (tickets["escalated_at"] <= tickets["created_at"] + WINDOW).astype(int)
# A ticket's 72 hours must be over before the snapshot, or its label is # not final yet. eligible = tickets["created_at"] <= SNAPSHOT - WINDOW counts = {"clean_tickets": len(tickets), "too_recent_for_label": int((~eligible).sum())} df = tickets[eligible].copy()
# Features known at creation time. df["customer_tenure_days"] = (df["created_at"] - df["joined_on"]).dt.days df["created_hour"] = df["created_at"].dt.hour df = df.sort_values(["created_at", "ticket_id"]) df["prior_tickets_90d"] = prior_count(df, tickets)
columns = ["ticket_id", "customer_id", "created_at"] + FEATURES + ["escalated_72h"] df = df[columns] OUT.mkdir(parents=True, exist_ok=True) df.to_csv(OUT / "tickets_model.csv", index=False, date_format=TIME_FORMAT) counts.update({"rows": len(df), "escalated": int(df["escalated_72h"].sum()), "escalated_rate": round(df["escalated_72h"].mean(), 3)}) (OUT / "build_summary.json").write_text(json.dumps(counts, indent=2) + "\n", encoding="utf-8") print(json.dumps(counts, indent=2))
def prior_count(df, all_tickets): """For each ticket: how many tickets the same customer created in the 90 days before it. Only earlier tickets count, so the value is known at creation time. Guests have no history: 0.""" history = all_tickets.dropna(subset=["customer_id"]).groupby("customer_id")["created_at"].apply(sorted) result = [] for customer, created in zip(df["customer_id"], df["created_at"]): if pd.isna(customer): result.append(0) continue earlier = [t for t in history[customer] if created - pd.Timedelta(days=90) <= t < created] result.append(len(earlier)) return result
if __name__ == "__main__": main()Les lignes importantes :
| Lignes | Pourquoi |
|---|---|
groupby("ticket_id")["recorded_at"].min() sur les événements escalated |
Le moment du premier transfert de chaque billet. Un billet sans transfert reçoit une valeur manquante (NaT, « pas une date ou une heure »). |
escalated_at <= created_at + WINDOW |
1 si le premier transfert a eu lieu dans les 72 heures. Une comparaison avec NaT donne False (faux), donc un billet sans transfert reçoit 0. |
eligible = created_at <= SNAPSHOT - WINDOW |
Garde seulement les billets dont les 72 heures étaient écoulées avant l’instantané. Le nombre de lignes retirées figure dans le résumé; rien ne disparaît sans indication. |
columns = [...] |
La sortie a une liste explicite de colonnes. priority_now, first_reply_minutes et closed_at n’y figurent pas et ne peuvent donc pas atteindre le modèle par accident. |
prior_count(df, tickets) |
Compte l’historique dans tous les billets nettoyés, y compris les 29 récents. Ceux-ci font réellement partie du passé pour les lignes suivantes. La condition t < created garde seulement les billets antérieurs. |
customer_tenure_days |
Nombre de jours entre joined_on et la création. Les invités et les clients supprimés n’ont pas de joined_on; la valeur est donc manquante. La leçon 3 la remplit. |
Mei exécute le script :
python scripts/build_features.py{ "clean_tickets": 1398, "too_recent_for_label": 29, "rows": 1369, "escalated": 188, "escalated_rate": 0.137}Comptez chaque ligne : 1 398 billets nettoyés − 29 trop récents = 1 369 lignes. Parmi eux, 188 ont été transférés dans les 72 heures. Le taux de transfert est donc de 188 ÷ 1 369 = 13,7 %. Les mêmes nombres sont enregistrés dans data/model/build_summary.json, à côté de tickets_model.csv.
Exercice guidé : créer et vérifier la table
Section intitulée « Exercice guidé : créer et vérifier la table »-
Créez le fichier
scripts/build_features.pyavec le code ci-dessus et enregistrez-le. -
Exécutez-le depuis le dossier du projet :
Terminal python scripts/build_features.pyVous devriez voir les mêmes cinq nombres que Mei : 1 398, 29, 1 369, 188 et 0,137.
-
Examinez une ligne. Créez le fichier
check_row.pydans le dossier du projet :check_row.py import pandas as pdmodel = pd.read_csv("data/model/tickets_model.csv")print(model.shape)print(model[model["ticket_id"] == "T-11241"].T) -
Exécutez
python check_row.py..Ttransforme la ligne en colonne pour faciliter la lecture :Sortie (1369, 14)1236ticket_id T-11241customer_id C-0094created_at 2026-06-11 17:53:05channel emailteam warrantypriority 3segment homeregion southorder_value 59.85word_count 92customer_tenure_days 2506.0prior_tickets_90d 2created_hour 17escalated_72h 0La table a 14 colonnes : trois identifiants et repères temporels, 10 variables et la cible.
priority_now,first_reply_minutesetclosed_atn’y sont pas. -
Vérifiez
prior_tickets_90d= 2 avec SQL, sans utiliser pandas. Enregistrez cette requête dansqueries/50-prior-tickets.sql:queries/50-prior-tickets.sql SELECT ticket_id, created_atFROM ticketsWHERE customer_id = 'C-0094'AND created_at >= datetime('2026-06-11 17:53:05', '-90 days')AND created_at < '2026-06-11 17:53:05'ORDER BY created_at; -
Exécutez-la avec
python q.py queries/50-prior-tickets.sql:Sortie ticket_id created_at--------- -------------------T-11014 2026-05-13 11:25:10T-11085 2026-05-22 10:58:452 rowsDeux billets antérieurs dans les 90 jours, comme dans le script. La requête utilise
larkfield.db, l’exportation brute. Cela convient pour C-0094, qui n’a aucune ligne en double.
Pourquoi la requête utilise-t-elle datetime(..., '-90 days') et <?
datetime('2026-06-11 17:53:05', '-90 days') renvoie 2026-03-13 17:53:05, le début des 90 jours. >= inclut un billet créé à cette seconde précise, comme le script (created - 90 days <= t). < '2026-06-11 17:53:05' exclut le billet lui-même et tout ce qui vient après. Si vous écrivez <=, T-11241 se compte lui-même et la valeur devient 3.
À vous de jouer : une cible de 48 heures
Section intitulée « À vous de jouer : une cible de 48 heures »Omar, le responsable produit, demande : « Et si on acheminait plutôt les billets transférés dans les 48 heures? » Changez une chose et examinez le résultat.
- Copiez le script dans
scripts/build_features_48h.py. - Dans la copie, définissez
WINDOW = pd.Timedelta(hours=48). - Dans la copie, changez les noms des sorties pour
tickets_model_48h.csvetbuild_summary_48h.json. La suite du module utilise les fichiers de 72 heures. - Prédisez : y aura-t-il plus ou moins de billets trop récents? Le nombre de billets transférés augmentera-t-il ou diminuera-t-il?
- Exécutez la copie et notez les cinq nombres.
Afficher la réponse
La date limite passe au 29 juin 2026 à 6 h. Il y a donc moins de billets trop récents : 22 au lieu de 29. La sortie est :
{ "clean_tickets": 1398, "too_recent_for_label": 22, "rows": 1376, "escalated": 190, "escalated_rate": 0.138}La cible de 48 heures pose une question légèrement différente. Certains transferts entre 48 et 72 heures comptent maintenant comme 0, mais la table contient aussi 7 lignes récentes supplémentaires. Le nombre de billets transférés passe donc de 188 à 190, au lieu de diminuer. Les deux changements agissent en sens opposés; seule l’exécution révèle le résultat. Supprimez les deux fichiers _48h et la copie du script quand vous avez terminé. Ils ne risqueront ainsi pas de créer de confusion dans la prochaine leçon.
Erreur courante
Une variable qui fonctionne trop bien
Symptôme : Tomás, l’ingénieur en IA, examine les billets nettoyés. « Utilisez priority_now. Ça fonctionne vraiment bien. » Il a raison : cela fonctionne. Voici les 1 369 lignes de modélisation, avec priority_now ajouté par jointure depuis le fichier nettoyé :
import pandas as pd
clean = pd.read_csv("data/clean/tickets.csv")model = pd.read_csv("data/model/tickets_model.csv")both = model.merge(clean[["ticket_id", "priority_now"]], on="ticket_id", validate="one_to_one")print(pd.crosstab(both["priority_now"], both["escalated_72h"]))print(pd.crosstab(both["priority"], both["escalated_72h"]))escalated_72h 0 1priority_now1 138 1882 431 03 612 0escalated_72h 0 1priority1 117 642 444 673 620 57Chacun des 188 billets transférés a priority_now = 1. Aucun billet avec priority_now à 2 ou 3 n’a été transféré. La colonne sans fuite, priority, est beaucoup moins révélatrice : on trouve des billets transférés à chaque niveau de priorité.
Cause : priority_now est écrit après le transfert. Le service de soutien lui donne la valeur 1 quand un agent principal prend le billet. La colonne ne prédit donc pas le transfert; elle l’enregistre. Au moment de la prédiction, chaque nouveau billet a un priority_now égal à priority. Le lien fort n’existe pas encore.
Correction : demandez quand chaque valeur est écrite et gardez la réponse dans le code. Le script de Mei inscrit la colonne dans AFTER_CREATION et l’exclut des colonnes de sortie. Une variable qui sépare presque parfaitement les classes justifie une vérification des fuites, pas une célébration.
Conséquence dans le travail en IA : avec priority_now, un modèle obtient un score très élevé en test (la leçon 3 le mesure). En pratique, la colonne ne contient aucune information sur le futur et l’acheminement échoue. L’équipe fait confiance au modèle grâce au score de test élevé. Trouver le problème peut donc prendre des semaines.
Vérification des connaissances
Section intitulée « Vérification des connaissances »Vérifiez votre compréhension
Lesquelles de ces colonnes peuvent servir de caractéristiques au modèle de transfert au niveau supérieur : team, csat, word_count, closed_at, first_reply_minutes, segment? Expliquez pourquoi chacune des autres ne convient pas.
Afficher la réponse
team (équipe), word_count (nombre de mots) et segment peuvent servir de caractéristiques : on les connaît à l’arrivée du billet de soutien. csat (satisfaction de la clientèle) est enregistré après la résolution du billet. closed_at (date de fermeture) est écrit à la fermeture du billet. On connaît first_reply_minutes (minutes avant la première réponse) seulement après la première réponse. Ces trois valeurs décrivent l’avenir du billet. Elles constituent donc une fuite de données.
Votre réponse contient-elle les points principaux de la nôtre ?
Connectez-vous et inscrivez-vous au cours pour enregistrer vos réponses. Chaque vérification compte pour le certificat.
Vérifiez votre compréhension
Tomás dit : « Gardez les 29 billets récents. Ceux sans événement de transfert au niveau supérieur ont escalated_72h = 0, donc la cible est correcte. » A-t-il raison?
Afficher la réponse
Non. Les 72 heures n’étaient pas écoulées au moment de l’instantané. L’absence de transfert signifie donc « pas encore connu », et non « non ». Certains des 23 zéros pourraient devenir des 1 après l’instantané. Si on les garde, les billets les plus récents semblent moins susceptibles d’être transférés au niveau supérieur. Le modèle apprend alors une tendance qui n’est pas réelle. Retirez-les et comptez-les, comme le fait build_features.py.
Votre réponse contient-elle les points principaux de la nôtre ?
Connectez-vous et inscrivez-vous au cours pour enregistrer vos réponses. Chaque vérification compte pour le certificat.
Vérifiez votre compréhension
Priya propose une caractéristique : le nombre de billets créés par le client dans les 30 jours entourant le billet. Cela comprend les 15 jours avant et les 15 jours après. Est-ce sans risque? Comment la modifieriez-vous?
Afficher la réponse
Ce n’est pas sans risque. Au moment de la prédiction, les 15 jours après le billet sont dans l’avenir. La caractéristique entraîne donc une fuite de données. Un client dont le billet est transféré au niveau supérieur peut écrire de nouveau dans les jours suivants. La fuite est donc aussi liée à la cible. Utilisez plutôt les billets des 30 jours avant le billet, avec t < created, comme le fait prior_tickets_90d.
Votre réponse contient-elle les points principaux de la nôtre ?
Connectez-vous et inscrivez-vous au cours pour enregistrer vos réponses. Chaque vérification compte pour le certificat.
Récapitulatif
- Le moment de la prédiction est celui où le modèle doit répondre : ici, à la création du billet. Chaque caractéristique doit exister à ce moment.
- La cible
escalated_72h(transfert au niveau supérieur dans les 72 heures) est précise : un événementescalated(transféré au niveau supérieur) dans les 72 heures suivant la création. Les billets créés dans les 72 dernières heures avant l’instantané n’ont pas encore de cible définitive. On en retire donc 29 et on les compte. - Demandez quand chaque valeur est écrite.
priority_now(priorité actuelle),first_reply_minutes,closed_atet toutes les données des événements de résultat ne servent jamais de caractéristiques. - L’historique du client doit provenir uniquement de billets antérieurs.
prior_tickets_90d(billets antérieurs sur 90 jours) respecte cette règle; un total de tous les billets d’un client ne la respecte pas. build_features.pyécrit 1 369 lignes, dont 188 avec un transfert au niveau supérieur (13,7 %), et 10 caractéristiques.
Ensuite, vous décidez quelles lignes serviront à l’apprentissage du modèle et lesquelles serviront à le tester.
Leçon suivante : Choisir une séparation