Pourquoi vos données industrielles sont inexploitables et comment les remettre en ordre avec Python

Sur un projet de maintenance prédictive en aéronautique, on cherchait à prédire l’encrassement d’un filtre à partir de mesures de consommation de courant. L’idée était simple ; à mesure que le filtre s’encrasse, la pompe compense en consommant davantage. En suivant cette consommation, on devrait pouvoir anticiper le changement de filtre avant la panne.
En théorie, c’est élégant.
En pratique, on a ouvert les données et découvert quelque chose d’inexplicable : des séries qui s’arrêtaient net pendant plusieurs mois — sans aucune trace de changement de filtre dans les logs de maintenance. Puis qui reprenaient, tantôt là où elles s’étaient arrêtées, tantôt depuis un état « vierge », comme si le filtre venait d’être remplacé sans que personne ne l’ait notifié.
Impossible de savoir si c’était un capteur défaillant, un problème de transmission, un filtre changé par la maintenance ou autre chose. Les données étaient là — mais elles étaient inexploitables.
Ce projet m’a appris une chose que j’aurais voulu savoir bien plus tôt : dans l’industrie, le problème n’est presque jamais l’algorithme. C’est la donnée.
Pourquoi les données industrielles sont dans cet état
Avant de chercher à corriger, il faut comprendre pourquoi ce problème est si répandu.
La réponse tient en une phrase : les données industrielles ont été conçues pour être lues par des humains, pas traitées par des machines.
Un technicien qui ouvre un fichier Excel voit une belle mise en forme — des cellules colorées, des totaux en gras, des tableaux croisés dynamiques bien présentés. Il comprend intuitivement ce qu’il voit. Python, lui, ne comprend rien de tout ça. Il voit des cellules fusionnées qu’il ne peut pas parser, des nombres stockés en texte qu’il ne peut pas additionner, des dates en format anglais sur un système configuré en français.
Il y a aussi une deuxième raison, moins évidente : personne n’a anticipé que ces données seraient un jour analysées automatiquement. Le technicien qui a conçu la feuille de suivi en 2015 ne savait pas qu’en 2024 quelqu’un voudrait en extraire des tendances avec Python. Il a fait ce qui était logique pour lui : une présentation claire pour ses collègues, pas une structure exploitable par un algorithme.
Le résultat c’est que dans la plupart des projets industriels 60 à 80% du temps est passé à préparer les données et seulement 20 à 40% à les analyser vraiment.
Les 5 familles de problèmes — et comment les corriger
Problème 1 — Les données manquantes et les comportements inexpliqués
C’est le problème le plus sournois parce qu’il ne génère pas d’erreur visible. Votre script tourne, il produit un résultat — mais ce résultat est faux parce qu’il est calculé sur des données incomplètes.
Sur le projet filtre dont je parlais en introduction, les trous de plusieurs mois dans les séries faussaient complètement nos modèles de dégradation. On calculait une vitesse d’encrassement sur une série qui avait des « sauts » inexpliqués.
Les données manquantes prennent plusieurs formes : des trous dans les séries temporelles où la série s’arrête et reprend sans explication, des valeurs NaN ou nulles où la ligne existe mais la valeur est vide et des valeurs aberrantes qui n’ont aucune signification physique.
Comment les détecter et les quantifier :
import pandas as pd
import numpy as np
df = pd.read_csv('donnees_capteurs.csv', sep=';', parse_dates=['timestamp'])
df = df.sort_values('timestamp').reset_index(drop=True)
# Valeurs manquantes par colonne
taux_manquants = df.isnull().sum() / len(df) * 100
print("Taux de valeurs manquantes :")
print(taux_manquants[taux_manquants > 0].round(1))
# Trous dans la série temporelle
df['delta_t'] = df['timestamp'].diff()
frequence_normale = pd.Timedelta('1min') # à adapter
seuil_trou = frequence_normale * 5 # tolérance : 5x la fréquence
trous = df[df['delta_t'] > seuil_trou][['timestamp', 'delta_t']]
print(f"nNombre de trous détectés : {len(trous)}")
print(f"Durée totale manquante : {trous['delta_t'].sum()}")
print(trous)
# Codes d'erreur déguisés en valeurs — remplacer par NaN
VALEUR_MIN = 0 # à adapter selon votre capteur
VALEUR_MAX = 1000 # à adapter selon votre capteur
df['valeur'] = df['valeur'].where(
df['valeur'].between(VALEUR_MIN, VALEUR_MAX), other=np.nan
)
Comment les corriger :
# Option 1 : interpolation linéaire (trous courts)
df['valeur_interpolee'] = df['valeur'].interpolate(method='linear')
# Option 2 : exclure les séquences avec trous longs
# Ne jamais inventer des données sur plusieurs mois
df_propre = df[df['delta_t'] <= seuil_trou].copy()
# Option 3 : signaler le trou sans l'interpoler
df['donnee_fiable'] = df['delta_t'] <= seuil_trou
La règle à retenir : un trou de plusieurs mois ne s’interpole pas. On l’exclut, on le documente, et on cherche à comprendre pourquoi il existe avant d’aller plus loin.
Problème 2 — Les formats qui cassent tout à l’import
C’est l’erreur qui génère le plus de frustration au quotidien. Vous ouvrez un fichier, vous lancez votre script et vous obtenez des messages d’erreur incompréhensibles — ou pire, des calculs silencieusement faux.
Les coupables sont presque toujours les mêmes. Les dates stockées en texte : Excel affiche « 15/03/2024 » mais la cellule contient une chaîne de caractères — pandas ne peut pas calculer de durée sur du texte. Le format de date qui change selon le poste : un fichier créé sur un système en anglais (MM/DD/YYYY) ouvert en français (DD/MM/YYYY) — le 03/05/2024 devient le 5 mars au lieu du 3 mai, sans aucune erreur Python. Les séparateurs décimaux incohérents : certains fichiers utilisent la virgule (format français), d’autres le point (format anglais), parfois les deux dans le même fichier.
import pandas as pd
df = pd.read_csv('mesures.csv', sep=';')
# Diagnostic rapide des types
print("Types détectés par pandas :")
print(df.dtypes)
# Si une colonne numérique est en 'object' → problème de format
# Corriger les dates — toujours spécifier le format explicitement
df['date'] = pd.to_datetime(df['date'],
format='%d/%m/%Y',
errors='coerce')
# errors='coerce' → les dates non parsables deviennent NaT
print(f"Dates non parsées : {df['date'].isna().sum()}")
# Corriger les nombres mal formatés
df['mesure'] = (df['mesure']
.astype(str)
.str.replace(' ', '', regex=False) # espaces (séparateur milliers)
.str.replace('xa0','', regex=False) # espace insécable (fréquent Excel)
.str.replace(',', '.', regex=False) # virgule → point décimal
.pipe(pd.to_numeric, errors='coerce'))
print(f"nAprès correction :")
print(df.dtypes)
print(df.isnull().sum())
La règle à retenir : spécifiez toujours le format de date et le séparateur décimal explicitement dans votre code. Ne faites jamais confiance au parsing automatique de pandas sur des données industrielles.
Problème 3 — Le chaos des fichiers Excel
C’est le problème le plus répandu — et le plus long à corriger. Pas parce qu’il est techniquement complexe mais parce qu’il prend de nombreuses formes dans le même fichier.
Des tableaux croisés dynamiques utilisés comme source de données — leur structure est lisible pour un humain et illisible pour Python. Des cellules avec retours à la ligne invisibles — la valeur semble normale dans Excel mais Python voit "référencen" au lieu de "référence". Des données éparpillées sur plusieurs onglets sans logique documentée. Et surtout : des nombres saisis avec des points au lieu de virgules ou des virgules au lieu de points, selon l’habitude de chaque opérateur.
import pandas as pd
# Lire un fichier Excel en évitant les pièges classiques
df = pd.read_excel(
'donnees_production.xlsx',
sheet_name='Mesures', # toujours nommer l'onglet explicitement
header=0,
)
# Nettoyer toutes les colonnes texte en une seule passe
cols_texte = df.select_dtypes(include='object').columns
for col in cols_texte:
df[col] = (df[col]
.astype(str)
.str.strip() # espaces début/fin
.str.replace('n', ' ', regex=False) # retours à la ligne
.str.replace('r', '', regex=False) # retours chariot
.str.replace('xa0', '', regex=False) # espaces insécables
.replace('nan', pd.NA)) # 'nan' texte → vraie valeur manquante
# Supprimer les lignes et colonnes totalement vides
df = df.dropna(how='all').dropna(axis=1, how='all')
# Supprimer les doublons
df = df.drop_duplicates()
print(f"Dataset après nettoyage : {df.shape}")
print(df.head())
La règle à retenir : un fichier Excel destiné à être traité automatiquement doit respecter une règle simple — une ligne = une observation, une colonne = une variable, pas de cellules fusionnées, pas de totaux intermédiaires, pas de mise en forme porteuse de sens.
Problème 4 — Les unités et les noms de variables incohérents
Deux fichiers, deux capteurs de température, deux ingénieurs différents. L’un a exporté en °C, l’autre en °F. Les colonnes s’appellent toutes les deux « temperature ». Aucune erreur Python — juste des résultats faux avec une apparence parfaitement normale.
Ce problème est amplifié dans l’industrie par la durée des projets. Un système installé en 2010 utilise une convention de nommage. Un deuxième installé en 2018 en utilise une autre. Cinq ans plus tard, quelqu’un doit faire parler les deux ensembles — et personne ne se souvient de qui a décidé quoi.
import pandas as pd
df = pd.read_csv('capteurs.csv', sep=';')
# Audit des plages de valeurs
# Une température moteur en °C : entre 0 et 900
# En °F : entre 32 et 1650 — immédiatement suspect
print("Plages de valeurs par colonne :")
print(df.describe().loc[['min', 'max', 'mean']].round(1))
# Standardiser les noms de colonnes
# Convention : [grandeur]_[source]_[unité]
renommage = {
'T1' : 'temperature_moteur1_celsius',
'Temp' : 'temperature_huile_celsius',
'temp_A' : 'temperature_ambiante_celsius',
'P_ref' : 'pression_reference_bar',
}
df = df.rename(columns=renommage)
# Convertir les unités si nécessaire
if 'temperature_echappement_fahrenheit' in df.columns:
df['temperature_echappement_celsius'] = (
(df['temperature_echappement_fahrenheit'] - 32) * 5 / 9
)
df = df.drop(columns=['temperature_echappement_fahrenheit'])
La règle à retenir : chaque colonne doit avoir son unité dans son nom. Pas temperature — temperature_celsius. Cinq secondes de rigueur au moment de nommer évitent des heures de débogage.
Problème 5 — L’absence de documentation
C’est l’erreur invisible. Celle dont on ne souffre pas immédiatement — mais qui coûte le plus cher sur la durée.
Que mesure ce capteur exactement ? À quelle fréquence ? Depuis quand ? Pourquoi y a-t-il un saut brutal le 14 mars — recalibrage, remplacement, anomalie réelle ? Sur le projet filtre, personne n’avait documenté le fait que le filtre pouvait avoir été changé en dehors du planning de maintenance, par un technicien en intervention d’urgence qui aurait noté le remplacement sur un log papier, pas dans un logiciel. Cette information, si elle avait été documentée, nous aurait économisé plusieurs semaines de recherche.
import json
# Template de documentation à mettre en tête de chaque script
METADATA = {
'fichier_source' : 'mesures_filtre_encrassage_2024.csv',
'date_export' : '2024-03-15',
'systeme_origine' : 'SCADA Schneider v3.2',
'frequence' : '1 mesure par minute',
'responsable' : 'Bureau méthodes — poste 4421',
'colonnes' : {
'timestamp' : 'Horodatage UTC, format ISO 8601',
'courant_a' : 'Consommation pompe, Ampères, capteur Hall',
'pression_bar' : 'Pression différentielle filtre, bar',
'statut' : '0=normal, 1=alarme, 2=hors service',
},
'anomalies_connues' : [
'2024-01-15 : trou de 3 mois — cause inconnue, en cours investigation',
'2024-03-10 : filtre changé hors GMAO par équipe nuit',
'2024-03-14 : recalibrage capteur courant_a',
],
}
print(json.dumps(METADATA, indent=2, ensure_ascii=False))
La règle à retenir : documentez au moment où vous savez. Dans six mois vous aurez oublié. Et la personne qui reprend le projet perdra une semaine à reconstituer ce que vous avez mis cinq minutes à noter.
La méthode en 3 étapes pour remettre un dataset en ordre
Plutôt que de traiter les problèmes au fil de l’eau, voici la méthode que j’applique systématiquement sur tout nouveau dataset.
Étape 1 — Audit : savoir où on en est avant de toucher quoi que ce soit
import pandas as pd
def audit_dataset(df, nom_fichier=""):
"""
Audit rapide à lancer sur tout nouveau dataset.
À appeler avant toute transformation.
"""
print(f"{'='*50}")
print(f"AUDIT : {nom_fichier}")
print(f"{'='*50}n")
print(f"Dimensions : {df.shape[0]:,} lignes × {df.shape[1]} colonnes")
print(f"n── Types de colonnes ──")
print(df.dtypes)
print(f"n── Valeurs manquantes ──")
manquants = df.isnull().sum()
manquants_pct = (manquants / len(df) * 100).round(1)
rapport = pd.DataFrame({'count': manquants, '%': manquants_pct})
print(rapport[rapport['count'] > 0])
print(f"n── Doublons ──")
print(f"{df.duplicated().sum()} lignes dupliquées")
print(f"n── Aperçu statistique ──")
print(df.describe().round(2))
print(f"n── Premières lignes ──")
print(df.head(3))
# Utilisation — à appeler sur chaque nouveau fichier
df = pd.read_csv('votre_fichier.csv', sep=';')
audit_dataset(df, nom_fichier='votre_fichier.csv')
Étape 2 — Nettoyage : corriger dans l’ordre
def nettoyer_dataset(df):
"""
Pipeline de nettoyage standard.
À adapter selon les résultats de l'audit.
"""
df = df.copy() # ne jamais modifier le dataset original
# 1. Supprimer les lignes et colonnes vides
df = df.dropna(how='all').dropna(axis=1, how='all')
# 2. Nettoyer les chaînes de caractères
cols_texte = df.select_dtypes(include='object').columns
for col in cols_texte:
df[col] = (df[col].astype(str)
.str.strip()
.str.replace('n', ' ', regex=False)
.str.replace('xa0', '', regex=False)
.replace('nan', pd.NA))
# 3. Supprimer les doublons
df = df.drop_duplicates()
return df
df_propre = nettoyer_dataset(df)
Étape 3 — Documentation : noter ce qu’on a fait et pourquoi
import json
from datetime import date
# Sauvegarder le fichier nettoyé séparément
# Ne jamais écraser le fichier source
df_propre.to_csv('votre_fichier_nettoye.csv',
sep=';', index=False, encoding='utf-8-sig')
# Log des transformations
LOG_NETTOYAGE = {
'date' : str(date.today()),
'fichier_source' : 'votre_fichier.csv',
'fichier_sortie' : 'votre_fichier_nettoye.csv',
'transformations' : [
'Suppression 3 lignes vides',
'Correction format date colonne timestamp (texte → datetime)',
'Correction séparateur décimal colonne mesure (, → .)',
'Suppression 12 doublons',
],
'anomalies_notees' : [
'Trou de 47 jours entre le 2024-01-15 et le 2024-03-03 — cause inconnue',
],
}
print(json.dumps(LOG_NETTOYAGE, indent=2, ensure_ascii=False))
Ce qu’il faut retenir
Ces 5 familles de problèmes ont un point commun : elles sont toutes silencieuses. Elles ne font pas planter votre code. Elles produisent des résultats qui ont l’air normaux — mais qui sont faux.
La défense la plus efficace, c’est un audit systématique avant chaque analyse. Pas parce que c’est rigoureux sur le papier — mais parce que ça vous fait gagner du temps. Une heure d’audit évite souvent une semaine de débogage.
Et si vous retenez une seule chose : comprenez vos données avant de les calculer. D’où elles viennent, comment elles ont été collectées, ce qui a pu se passer entre la mesure et le fichier que vous avez en main. C’est cette compréhension — pas l’algorithme — qui fait la différence entre un projet qui aboutit et un projet qui finit dans un tiroir.
💬 Quel problème de qualité de données vous a coûté le plus de temps sur un projet réel ? Dites-le moi en commentaire.
📩 Je prépare une formation complète sur la data science industrielle appliquée.

Laisser un commentaire