3  Du catalogue à l’échantillon analysable

Télécharger les données Présentation HTML Présentation PDF

3.1 Introduction

Cette séance ouvre le bloc consacré aux statistiques univariées. Nous poursuivons l’introduction à pandas commencée en semaine 2 avec un nouveau catalogue de données: les tsunamis déclenchés par des glissements de terrain, associés à une synthèse récente publiée dans Natural Hazards (Dohmen et al. 2025b; Dohmen et al. 2025a). Ces événements sont rares à l’échelle globale, mais ils peuvent produire des hauteurs d’eau considérables dans les fjords, les lacs et les réservoirs. L’introduction du bloc décrit la source, la structure et les limites des données.

Avant d’analyser aveuglément un nouveau jeu de données, il faut réaliser une analyse exploratoire qui a plusieurs objectifs:

  1. inspecter la structure du fichier;
  2. identifier ce que représente une ligne (par exemple glissements vs tsunamis);
  3. examiner les catégories, les valeurs manquantes et les valeurs extrêmes;
  4. construire les échantillons utilisés pendant la suite du bloc.

3.1.1 Questions fil rouge

La question technique est:

  • Comment préparer et clarifier la structure d’un jeu de données pour en préparer l’analyse?

La question scientifique est:

  • Quelle est la complétude d’enregistrement des volumes associés aux glissements de terrain dans le catalogue?

3.1.2 Objectifs d’apprentissage

À la fin de cette séance, vous serez capables de:

  • identifier ce que représentent les lignes et les colonnes d’un jeu de données;
  • distinguer l’événement scientifique observé de son enregistrement dans un tableau;
  • sélectionner les variables pertinentes pour répondre à une question scientifique;
  • repérer les valeurs manquantes, les doublons et les observations invalides;
  • construire puis sauvegarder un échantillon cohérent pour les analyses suivantes;
  • expliquer comment les choix de préparation limitent la portée des conclusions.

3.2 Exercise

3.2.1 Charger et inspecter le catalogue

Après avoir chargé les données, la première étape est d’inspecter le tableau et de comprendre sa structure. Ici, une ligne représente un glissement de terrain documenté; plusieurs lignes peuvent donc être associées au même tsunami. pd.read_csv() (Section 2.2.1) lit le fichier CSV et construit le tableau df.

Listing 3.1: Charger le catalogue des glissements ayant déclenché un tsunami.
import pandas as pd

df = pd.read_csv("data/Dohmen_et-al_landslides_clean.csv")
1
Importe la bibliothèque pandas sous l’abréviation conventionnelle pd.
2
Lit le fichier CSV et stocke le tableau dans le DataFrame df.

Question 3.1  

QuestionContrôler le tableau

À l’aide des méthodes rencontrées en semaine 2 (Section 2.2.2), affichez:

  • les cinq premières lignes
  • la taille du tableau
  • les noms des colonnes
  • les informations sur leurs types et valeurs disponibles.

Combien de valeurs non manquantes contient la colonne landslide_distance_m? L’utiliseriez-vous comme une variable d’un modèle décrivant le catalogue entier?

Utilisez head(), shape, columns.tolist() et info() pour réaliser ces contrôles.

Astuce 3.1: Raisonnement scientifique

On observe que toutes les variables ne sont pas renseignées avec la même complétude. Certaines sont faciles à contraindre, comme country ou continent. D’autres sont plus difficiles à quantifier et estimer pour des événements passés, comme landslide_distance_m ou max_inundation_distance_m. Si le but de la recherche est de développer un modèle pouvant capturer et décrire les relations entre toutes les variables, celles avec un grand nombre de valeurs manquantes devraient sûrement être omises.

3.2.2 Sélectionner les variables utiles

Le catalogue contient davantage de colonnes que nécessaire pour notre première exploration. En sélectionner quelques-unes facilite leur contextualisation dans la question à investiguer.

Question 3.2  

QuestionConstruire un sous-tableau lisible

À partir de la liste colonnes, créez un nouveau DataFrame nommé dfs, puis affichez ses dix premières lignes. La sélection des colonnes a été vue en semaine 2 (Section 2.2.3.1). head() contrôle le résultat.

colonnes = [
    "event_label", "landslide_id", "tsunami_id", "event_year",
    "country", "water_body", "landslide_cause", "landslide_type",
    "landslide_volume_m3", "max_water_height_m", "status_clean",
]
1
Définit explicitement les variables jugées utiles pour l’investigation. Les variables sont listées dans une liste (Tip 2.2)

3.2.3 Identifier l’unité d’analyse

Le catalogue contient une ligne par glissement, mais plusieurs glissements peuvent être associés au même tsunami. Une fréquence calculée par ligne, par glissement ou par tsunami répond donc à trois questions différentes. nunique() compte le nombre de valeurs distinctes d’une colonne, alors que len() compte les lignes. print() permet d’afficher chaque quantité avec une étiquette explicite.

Question 3.3  

QuestionCompter les objets distincts

Comparez le nombre de lignes, de landslide_id distincts et de tsunami_id distincts. Expliquez pourquoi ces trois nombres ne sont pas identiques.

Question 3.4  

QuestionQuels tsunamis ont été causés par plusieurs glissements?

Filtrez les lignes pour lesquelles is_multiple_landslide_tsunami vaut True (Section 2.2.4), puis comptez les tsunami_id distincts. Pourquoi faut-il compter les identifiants plutôt que les lignes?

Question 3.5  

QuestionChoisir l’unité qui répond à la question

Vous voulez estimer la proportion de tsunamis ayant atteint une hauteur d’eau supérieure à 10 m. Quelle table faut-il utiliser?

Astuce 3.2: Raisonnement scientifique

Les propriétés d’un tsunami multiple ne doivent pas être attribuées arbitrairement à un seul glissement. Le choix de l’unité d’analyse doit suivre la question: mécanisme du glissement, caractéristiques du tsunami ou événement historique.

3.2.4 Examiner les catégories documentées

Combien de catégories sont représentées dans une colonne? Listing 3.2 compte le nombre de catégories contenues dans la colonne status_clean. Notez qu’il est possible d’enchaîner plusieurs fonctions à la suite. value_counts() compte les occurrences de chaque catégorie. L’argument dropna=False conserve les valeurs manquantes dans le comptage. reset_index() replace ensuite les catégories de l’index dans une colonne ordinaire et nomme la colonne d’effectif avec name="n".

Listing 3.2: Compter les statuts présents dans le catalogue.
df[["status_clean"]].value_counts(dropna=False)
df[["status_clean"]].value_counts(dropna=False).reset_index(name="n")
1
Compte tous les statuts en conservant les valeurs manquantes. value_counts retourne le nombre de valeurs dans l’index (Section 2.1.5).
2
Pour extraire les valeurs de l’index dans une colonne plus facile à interroger, on utilise reset_index(). L’argument name permet d’assigner un nom à la colonne (→ n)
Astuce 3.3: Argument dropna

dropna est un argument que vous retrouverez dans de nombreuses fonctions pandas. Il signifie:

  • drop: supprimer, abandonner
  • na: non-available - ou pas disponible

Dans (tsunamis-preparation-statuts?), dropna contrôle le comportement de la fonction.

  • dropna=True: La fonction applique son comportement en ignorant les valeurs non disponibles
  • dropna=False: La fonction les garde.

Dans le cas de Listing 3.2, dropna=False permet de quantifier combien de valeurs sont manquantes, ce qui, dans ce cas, révèle que près de 50% des lignes ont une valeur de status_clean manquante.

Question 3.6  

QuestionQuels types de glissements sont représentés?

À partir de la colonne landslide_type, comptez le nombre de types distincts, affichez leur effectif en conservant les valeurs manquantes et identifiez le type le plus documenté.

3.2.5 Construire deux tables cohérentes

Dans df, la colonne booléenne is_valid_entry identifie les entrées jugées valides et pouvant être utilisées sans retenue dans une analyse. Comme vu en semaine 2 (Section 2.2.4), nous pouvons l’utiliser pour extraire un sous-ensemble de df ne contenant que les entrées valide: copy() isole les lignes valides, et len() avec print() affiche l’effet du filtre.

Listing 3.3: Conserver les glissements valides à partir du catalogue déjà chargé.
ls = df[df["is_valid_entry"]].copy()

print("Lignes initiales :", len(df))
print("Glissements valides :", len(ls))
1
Conserve les entrées valides dans une copie indépendante nommée ls.
2
Compare le nombre d’entrées avant et après cette sélection.
Astuce 3.4: Pourquoi utiliser copy()?

Lorsque l’on prévoit de modifier un sous-ensemble, .copy() crée un tableau indépendant et évite de modifier involontairement les données d’origine.

Pour les questions portant sur les tsunamis, nous voulons une seule ligne par tsunami_id. drop_duplicates() garde une ligne pour chaque identifiant distinct.

Question 3.7  

QuestionConstruire la table des tsunamis

Triez ls avec sort_values() (Section 2.2.2.4), puis gardez une seule ligne par tsunami_id avec drop_duplicates(). copy(), len() et print() créent un résultat indépendant et en comparent les effectifs. Nommez-le tsunami.

Avertissement 3.1: Quelles variables conserver?

La table tsunami n’a uniquement du sense pour les colonnes dont les valeurs sont identiques dans toutes les lignes associées à un tsunami. Les propriétés propres aux glissements — cause, matériau ou volume — doivent être analysées dans ls.

3.2.5.1 Sauvegarder la table réutilisée

La semaine 4 réutilisera l’ensemble des glissements valides pour étudier plusieurs variables. Plutôt que de répéter le filtre is_valid_entry, nous enregistrons donc ls avec to_csv(). L’argument index=False évite d’ajouter au fichier une colonne contenant l’index du DataFrame.

Listing 3.4: Enregistrer la table des glissements valides pour la semaine suivante.
ls.to_csv(
    "data/Dohmen_et-al_landslides_valid.csv",
    index=False,
)
1
Enregistre la table préparée sans modifier ls.
2
Donne au fichier un nom qui explicite le critère appliqué.
3
N’exporte pas l’index de pandas.

Nous ne sauvegardons pas tsunami ici, car aucune séance suivante ne réutilise cette table. Un fichier intermédiaire n’est utile que s’il évite réellement de répéter une préparation.

3.2.6 Décrire les catégories dans la bonne table

Le type de plan d’eau décrit le contexte du tsunami: nous le comptons donc dans tsunami utilisant la colonne water_body (Listing 3.5). La cause décrit le glissement: nous la comptons dans ls. value_counts() et reset_index() construisent les effectifs; sum() fournit le total et round() (Section 2.2.5) simplifie les pourcentages affichés.

Astuce 3.5: Essayez et expérimentez!

Encore une fois, n’imaginez pas écrire la bonne “phrase” du premier coup: essayez les fonctions, expérimentez avec la documentation et analysez le résultat avant de complexifier votre requête.

Listing 3.5: Compter les plans d’eau et calculer leur proportion.
eau = tsunami[["water_body"]].value_counts(dropna=False).reset_index(name="n")
eau["pourcentage"] = (100 * eau["n"] / eau["n"].sum()).round(1)
eau
1
Compte chaque type de plan d’eau, y compris les valeurs manquantes.
2
Convertit les effectifs en pourcentages du total.
3
Affiche le tableau construit.

Question 3.8  

QuestionQuelles causes dominent dans le catalogue?

Reproduisez la logique de Listing 3.5 pour landslide_cause dans la table ls. Créez un tableau causes contenant les effectifs et les pourcentages, puis expliquez pourquoi ces pourcentages ne sont pas nécessairement des fréquences naturelles.

3.2.7 Évaluer la disponibilité des données

Avant de conduire une analyse quantitative, il faut mesurer quelles variables sont suffisamment renseignées. notna() renvoie True lorsqu’une valeur est présente. Comme True vaut 1 et False vaut 0, mean() donne la fraction de données disponibles. sort_values() et round() servent ensuite à ordonner et présenter les résultats.

Listing 3.6: Calculer la proportion de hauteurs d’eau disponibles.
ls["max_water_height_m"].notna().mean() * 100
1
Transforme présence/absence en True/False, puis leur moyenne en pourcentage disponible.

Question 3.9  

QuestionComparer la complétude des variables quantitatives

Calculez le pourcentage de valeurs disponibles pour les colonnes de variables, puis classez-les de la moins complète à la plus complète.

variables = [
    "landslide_height_m", "landslide_distance_m", "landslide_width_m",
    "landslide_volume_m3", "trigger_magnitude", "max_water_height_m",
    "max_inundation_distance_m", "fatalities",
]
1
Regroupe les variables quantitatives dont la complétude doit être comparée.

3.2.8 Les données manquantes sont-elles distribuées aléatoirement?

Identifier si les valeurs manquantes sont distribuées de façon aléatoire ou structurée est important dans le choix des variables utilisables. Par exemple, certains mécanismes peuvent être plus difficiles à observer ou à mesurer. Nous examinons donc la disponibilité du volume séparément pour chaque cause. notna() identifie la présence de valeurs valides, groupby() forme les groupes, puis mean(), mul(), sort_values() et round() produisent des pourcentages lisibles.

Listing 3.7: Comparer la disponibilité du volume selon la cause du glissement.
volume_disponible = ls["landslide_volume_m3"].notna()

volume_par_cause = (
    volume_disponible.groupby(ls["landslide_cause"])
    .mean().mul(100)
    .sort_values()
)

volume_par_cause.round(1)
1
Identifie les lignes pour lesquelles la colonne landslide_volume_m3 possède une valeur disponible. Cela retourne une série booléenne.
2
Construit le résumé par enchaînement d’opérations.
3
Regroupe les indicateurs de disponibilité selon la cause.
4
Convertit les moyennes en pourcentages et les classe.
5
Classe les valeurs.
Astuce 3.6: Regrouper avant de calculer

La méthode groupby() sépare les lignes d’un tableau selon les catégories d’une variable. Elle ne produit généralement pas un résultat final à elle seule: elle doit être suivie d’une fonction indiquant l’opération à effectuer dans chaque groupe. Par exemple, pour calculer le volume moyen par cause de glissement:

df.groupby("landslide_cause")["landslide_volume_m3"].mean()

Ici, groupby() forme les groupes et mean() calcule une moyenne dans chacun d’eux. On peut également utiliser median(), size(), sum() ou agg(), selon la question scientifique.

groupby() indique “par quel groupe?”; la fonction suivante indique “quel calcul effectuer?”.

Question 3.10  

QuestionRelier complétude et effectif

Pourquoi faut-il connaître l’effectif total de chaque cause avant de comparer ces pourcentages? Ajoutez ce comptage avec groupby() et size(), réunissez les séries dans un pd.DataFrame(), puis utilisez sort_values() (Tip 3.7).

Astuce 3.7: Comment créer un nouveau DataFrame?

En Python, un dictionnaire s’écrit entre accolades {}. Chaque paire clé-valeur est séparée par un deux-points :, et les paires sont séparées par des virgules ,. La clé est généralement une chaîne de caractères (entre guillemets). La valeur peut être n’importe quoi: une variable, une liste, un nombre, etc. Par exemple:

{
    "n_glissements": effectif_par_cause,
    "volume_disponible_pct": volume_par_cause,
}

Pour créer un nouveau DataFrame, on peut simplement passe un dictionnaire à la fonction pd.DataFrame():

pd.DataFrame({
    "n_glissements": effectif_par_cause,
    "volume_disponible_pct": volume_par_cause,
})

Cela crée un nouveau tableau avec deux colonnes nommées n_glissements et volume_disponible_pct.

Note 3.1: Conséquence scientifique

Si le volume est mieux renseigné pour certaines causes, l’échantillon des volumes peut modifier la composition du catalogue. Comparer ensuite les causes sans documenter cette sélection risquerait de confondre différences naturelles et différences de documentation.

3.2.9 Construire l’échantillon des semaines suivantes

Nous étudierons la distribution des volumes. Une valeur absente ne peut pas être représentée, et une valeur nulle n’est physiquement pas réelle.

Question 3.11  

QuestionPréparer une série de volumes analysables

À partir de ls, sélectionnez landslide_volume_m3, retirez les valeurs absentes avec dropna(), puis conservez uniquement les volumes strictement positifs. Utilisez len() et print() pour afficher le nombre de valeurs retenues et exclues.

3.2.10 Mini-investigation

Question 3.12  

QuestionLe sous-échantillon des volumes représente-t-il également les différents milieux aquatiques?

Le catalogue contient des glissements survenus en milieu marin ouvert, en milieu marin fermé et dans des eaux continentales. Cependant, mesurer le volume d’un glissement sous-marin peut être plus difficile que mesurer celui d’un glissement émergé et accessible.

Déterminez si la disponibilité des volumes varie selon le type de plan d’eau.

Pour répondre:

  1. réutilisez la table ls contenant les entrées valides;
  2. comptez les glissements distincts associés à chaque type de plan d’eau;
  3. utilisez notna() pour identifier les volumes disponibles;
  4. utilisez groupby() puis mean() pour calculer leur proportion dans chaque milieu;
  5. classez les résultats par proportion décroissante;
  6. formulez une observation, une interprétation et une limite.

3.3 Questions de recherche supplémentaires

  1. La proportion de volumes documentés varie-t-elle selon la cause du glissement?
  2. Les tsunamis associés à plusieurs glissements sont-ils concentrés dans certains types de plans d’eau?
  3. La période de l’événement influence-t-elle la complétude des variables quantitatives?
  4. Quelles conclusions changeraient si l’unité d’analyse était le tsunami plutôt que le glissement?

3.4 Conclusion

3.4.1 Synthèse scientifique

  1. La taille d’un tableau compte des lignes, pas nécessairement des phénomènes indépendants.
  2. Les identifiants permettent de relier chaque ligne à l’objet scientifique réellement étudié.
  3. Les exclusions, doublons et valeurs manquantes définissent la portée de l’échantillon.
  4. La complétude d’une variable doit être évaluée avant de formuler une question qui en dépend.
  5. Un échantillon analysable est le résultat documenté d’une suite de décisions scientifiques.

3.4.2 Conclusion de la question fil rouge

Le catalogue contient des informations à plusieurs niveaux: une ligne décrit un glissement, tandis qu’un tsunami peut être associé à plusieurs glissements. Après avoir rendu cette structure explicite, contrôlé les entrées et évalué les valeurs manquantes, nous pouvons construire une série de volumes positifs documentés. La prochaine séance demandera ce que sa distribution révèle et comment la résumer sans masquer son asymétrie.

3.4.3 Aide-mémoire

Besoin scientifique Code simple
inspecter un tableau df.head(), df.shape, df.info()
compter des objets distincts s.nunique()
compter des catégories s.value_counts(dropna=False)
créer une copie indépendante df[condition].copy()
conserver une ligne par objet df.drop_duplicates(...)
retirer les valeurs manquantes s.dropna()
résumer par groupe df.groupby(...)