Retour à la leçon·Leçon 3 sur 8·Faire entrer l'export
CSV, Excel et largeur fixe, lus sans dommage
Le même diaporama que les téléchargements, rendu sous forme de page. Lancez le diaporama pour le présenter en plein écran — les flèches ou un clic avancent d'une diapositive, Échap quitte.
Ce que couvre cette leçon
- Ce que cette leçon suppose
- Le CSV n'est pas un format unique
- Excel
- Fichiers à largeur fixe
- Vérifier la lecture avant d'en faire quoi que ce soit
- Lire un gros fichier
- Ce qui vient ensuite
Notes du présentateur
Encodages, séparateurs, classeurs multi-feuilles, lignes d'en-tête fusionnées et spécifications de colonnes — les pièges propres à chaque format, qui corrompent un fichier avant même que vous n'ayez regardé une seule valeur.Ce que cette leçon suppose
- Fondamentaux de l'analyse de données couvre le principe : déclarez vos types, déclarez vos sentinelles, et ne laissez jamais un lecteur en inférer l'un ou l'autre.
Notes du présentateur
Fondamentaux de l'analyse de données couvre le principe : déclarez vos types, déclarez vos sentinelles, et ne laissez jamais un lecteur en inférer l'un ou l'autre. Cette leçon le tient pour acquis et entre dans les formats eux-mêmes, car chacun échoue différemment et les défaillances ne se voient plus dans les données ensuite.Le CSV n'est pas un format unique
- Le séparateur
Notes du présentateur
read_csvcompte une cinquantaine de paramètres. Quatre d'entre eux expliquent l'essentiel des dégâts. Un fichier produit sur une machine Windows française ou espagnole est très souvent séparé par des points-virgules, car la virgule y est le séparateur décimal.Le CSV n'est pas un format unique — En Python
import pandas as pd # Faux : tout atterrit dans une colonne unique nommee d'apres l'en-tete entier. wrong = pd.read_csv("export.csv") print(wrong.shape) # (2736, 1) right = pd.read_csv("export.csv", sep=";", decimal=",") print(right.shape) # (2736, 7)Le CSV n'est pas un format unique
- L'encodage
Notes du présentateur
Le symptôme est sans ambiguïté une fois connu : un DataFrame à exactement une colonne. Vérifiez.shapeimmédiatement après chaque lecture. Les caractères accentués dans les noms de communes — Gonaïves, L'Estère, Anse-Rouge — sont l'endroit où cela mord.Le CSV n'est pas un format unique — En Python
# UnicodeDecodeError, ou pire, silencieusement abime : "Gona\xefves" muac = pd.read_csv(path) muac = pd.read_csv(path, encoding="utf-8") # ce que vous voulez muac = pd.read_csv(path, encoding="latin-1") # ce qu'Excel produit souventLe CSV n'est pas un format unique
- Les séparateurs de milliers transforment les nombres en texte
Notes du présentateur
latin-1ne lève jamais d'erreur, car tout octet est un caractère latin-1 valide. Cela en fait un mauvais diagnostic et un repli correct : si un fichier lu enlatin-1afficheGonaïves, il était en UTF-8 depuis le début et vous avez dit le contraire au lecteur.Le CSV n'est pas un format unique — En Python
# target_population arrive en "1,480" et pandas le lit comme une chaine. epi = pd.read_csv(path, thousands=",")Le CSV n'est pas un format unique
- Les zéros initiaux
Notes du présentateur
Sansthousands, cette colonne est de type objet et toute opération arithmétique dessus échoue ou concatène. Vérifiez.dtypesaprès lecture, à chaque fois. Le réglage par défaut le plus coûteux de ce secteur.Le CSV n'est pas un format unique — En Python
# facility_id "007" devient l'entier 7 ; la jointure a la liste des formations # echoue exactement pour celles dont le code portait un zero initial. epi = pd.read_csv(path) epi = pd.read_csv(path, dtype={"facility_id": "string"})Le CSV n'est pas un format unique — En Python
# Tout lire en texte d'abord, regarder, puis convertir deliberement. peek = pd.read_csv(path, dtype="string", nrows=200) print(peek.head()) print(peek.columns.tolist())Notes du présentateur
La règle se généralise : si vous n'allez jamais faire d'arithmétique dessus, ce n'est pas un nombre. Codes de formations sanitaires, numéros de téléphone, identifiants de grappes, numéros de ménages et codes administratifs sont du texte qui s'écrit avec des chiffres. Une habitude défensive pour un fichier dont vous ne connaissez pas encore les colonnes : Deux cents lignes suffisent à voir la forme et coûtent peu sur un gros fichier.Excel — En Python
book = pd.ExcelFile(path) print(book.sheet_names) # ['Cover', 'Data', 'Codebook', 'Sheet3'] data = pd.read_excel(path, sheet_name="Data")Excel — En Python
sheets = pd.read_excel(path, sheet_name=None) monthly = pd.concat(sheets, names=["sheet"]).reset_index(level="sheet")Notes du présentateur
read_excelsanssheet_namerenvoie la première feuille, qui dans un classeur de programme est le plus souvent une page de garde. Listez toujours les feuilles d'abord.sheet_name=Nonerenvoie un dictionnaire de toutes les feuilles, ce qui permet de traiter un classeur à une feuille par mois :Excel
- L'en-tête n'est pas en ligne 1
Notes du présentateur
Les classeurs de programme portent couramment un titre, une ligne de logo et une ligne vide au-dessus du véritable en-tête.Excel
- Les cellules fusionnées produisent des valeurs manquantes
Notes du présentateur
Le symptôme, ce sont des noms de colonnes commeUnnamed: 0,Unnamed: 1. Si vous les voyez, la ligne d'en-tête est ailleurs. Une cellule fusionnée porte sa valeur en haut à gauche et rien dans le reste. Quand un nom de district est fusionné sur ses formations sanitaires, seule la première ligne de chaque district en porte un.Excel
- Les dates Excel
Notes du présentateur
ffillest correct ici et dangereux en général : il n'est juste que parce que les blancs proviennent d'une fusion, non d'une non-réponse. Ne l'appliquez jamais à une colonne où un blanc pourrait signifier « non renseigné ». Excel stocke les dates comme un nombre de jours depuis le 30/12/1899.read_excelles convertit généralement, mais une colonne typée en texte dans le classeur arrive sous forme de numéro de série brut.Excel — En Python
# 45306 correspond au 15/01/2024 data["screening_date"] = pd.to_datetime( data["screening_date"], unit="D", origin="1899-12-30" )Notes du présentateur
Si une colonne de dates arrive en entiers à cinq chiffres, voilà pourquoi.Fichiers à largeur fixe — Exemple
CH00854Terre-Neuve 2024-01-15022m133false CH01207Gonaives 2024-01-15034f118falseNotes du présentateur
Encore courants depuis les anciens systèmes d'information sanitaire et depuis les extractions ministérielles. Il n'y a pas de séparateur ; chaque champ occupe une plage fixe de caractères.Fichiers à largeur fixe — En Python
COLSPECS = [(0, 7), (7, 22), (22, 32), (32, 35), (35, 36), (36, 39), (39, 44)] NAMES = ["child_id", "commune", "screening_date", "age_months", "sex", "muac_mm", "oedema"] muac = pd.read_fwf( path, colspecs=COLSPECS, names=NAMES, dtype={"child_id": "string", "commune": "string"}, ) muac["commune"] = muac["commune"].str.strip()Fichiers à largeur fixe
- Les plages sont semi-ouvertes, comme les tranches Python :
(0, 7)couvre les caractères 0 à 6. Une erreur d'un… - Retirez le remplissage. Les champs à largeur fixe sont complétés par des espaces :
"Terre-Neuve "ne sera pas… - Prenez la spécification dans la documentation, pas en comptant à l'écran.
read_fwfsait inférercolspecs, et il…
Notes du présentateur
Trois remarques :- Les plages sont semi-ouvertes, comme les tranches Python :
Vérifier la lecture avant d'en faire quoi que ce soit — En Python
def check(df, expected_rows=None): print("forme ", df.shape) print("types ", df.dtypes.value_counts().to_dict()) print("manquants ", df.isna().sum().to_dict()) print("1re ligne ", df.iloc[0].to_dict()) if expected_rows is not None: assert len(df) == expected_rows, f"attendu {expected_rows}, obtenu {len(df)}" muac = pd.read_csv( RAW / "muac-screening-artibonite-2024.v1.csv", dtype={"child_id": "string", "commune": "string", "sex": "string"}, na_values={"muac_mm": ["-99"]}, ) check(muac, expected_rows=4218)Notes du présentateur
Chaque lecture devrait être suivie des quatre mêmes contrôles. Ensemble ils prennent une minute et attrapent presque tout ce qui précède.Vérifier la lecture avant d'en faire quoi que ce soit
- la forme attrape le mauvais séparateur et un téléchargement tronqué.
- les types attrapent les zéros initiaux perdus, les séparateurs de milliers et une colonne numérique lue comme du…
- les manquants attrapent un mauvais encodage et une sentinelle non déclarée.
- la première ligne attrape un décalage d'en-tête — si elle ressemble à un en-tête, c'en était un.
Notes du présentateur
L'assertion sur le nombre de lignes est celle qu'on saute. Un fichier qui arrive avec 4 190 lignes au lieu de 4 218 a perdu quelque chose entre le serveur et vous, et le script doit le dire plutôt que de rapporter discrètement une charge de cas plus faible.Lire un gros fichier — En Python
COLUMNS = ["student_id", "attendance_date", "present"] attendance = pd.read_csv(path, usecols=COLUMNS, dtype={"student_id": "string"})Notes du présentateur
Si un fichier ne tient pas confortablement en mémoire, lisez les colonnes nécessaires plutôt que toutes :Lire un gros fichier — En Python
totals = [] for chunk in pd.read_csv(path, chunksize=100_000, dtype={"student_id": "string"}): totals.append(chunk.groupby("student_id")["present"].sum()) per_student = pd.concat(totals).groupby(level=0).sum()Notes du présentateur
usecolséconomise beaucoup sur un export large. Au-delà,chunksizerenvoie un itérateur de morceaux que vous agrégez au fil de l'eau : Le fichier de présence de 70 000 lignes n'en a pas besoin. Une extraction DHIS2 pluriannuelle, si.Ce qui vient ensuite
- Le fichier est en mémoire, forme et types intacts.
Notes du présentateur
Le fichier est en mémoire, forme et types intacts. La leçon suivante traite de ce qui est écrit à l'intérieur des colonnes : codes sentinelles, vocabulaires catégoriels, valeurs booléennes saisies de cinq façons différentes, et les étiquettes de valeurs qu'un fichier Stata porte et qu'un CSV jette.