Analyse de données sur la biodiversité des parcs nationaux américains#

Introduction#

L’objectif de ce TP est d’étudier la biodiversité au sein de parcs nationaux. Pour cela nous utiliserons des données d’observations de plusieurs espèces dans différents lieux.

En science des données vous devrez préparer les données, les analyser (statistiquement) et produire des figures pertinentes dans l’objectif de répondre à différentes questions.

Sources

Les fichiers Observations.csv et Species_info.csv sont issus originellement d’un projet de Kaggle.

Remarques: les données pour ce projet sont inventées bien qu”inspirées par des données réelles.

Objectifs du projet#

Vous êtes deux analystes de la biodiversité pour le service des parcs nationaux. Le service veut assurer la survie des espèces en péril et maintenir le niveau de biodiversité au sein de leurs parcs. Par conséquent, vos principaux objectifs seront de comprendre les caractéristiques des espèces et leur état de conservation, ainsi que ces espèces et leurs relations avec les parcs nationaux. Quelques questions qui se posent :

  • Quel animal est le plus répandu ? Quel parc possède le plus d’espèces ?

  • Quelle est la répartition des statuts de conservation des espèces ?

  • Certains types d’espèces sont-ils plus susceptibles d’être menacés ?

Chargement des données#

Ce TP contient deux ensembles de données. Le premier fichier CSV (comma separated values) contient des informations sur chaque espèce et un autre contient des observations d’espèces avec des emplacements de parc. Ces données seront utilisées pour répondre aux questions ci-dessus.

Analyse des données#

Des statistiques descriptives et des techniques de visualisation des données seront utilisées pour mieux comprendre les données. L’inférence statistique sera également utilisée pour tester si les valeurs observées sont statistiquement significatives. Certaines des mesures clés qui seront calculées incluent :

  1. distributions,

  2. comptage,

  3. relation entre les espèces,

  4. état de conservation des espèces.

Évaluation et conclusion#

Enfin, nous reviendrons aux questions posées. A-t-on pu répondre à toutes les questions? Peut-on aller plus loin? Nous réfléchirons aux limites et nous verrons si l’une des analyses aurait pu être effectuée à l’aide de méthodes différentes.

Chargement des données#

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline

Chargez les fichiers media/species_info.csv et media/observations.csv sous forme de tables (data frames) appelées species et observations respectivement.

Indication: La fonction .head() permet d’avoir un apercu du contenu de chaque table.

### BEGIN SOLUTION
species = pd.read_csv("media/species_info.csv") 
### END SOLUTION

species.head()
### BEGIN SOLUTION
observations = pd.read_csv("media/observations.csv")
### END SOLUTION

observations.head()
assert isinstance(observations, pd.DataFrame)
assert isinstance(species, pd.DataFrame)
assert observations.shape == (23296, 3)
assert species.shape == (5824, 4)
assert (observations.isna()).any(axis=None)

Caractéristiques des jeux de données#

Quelles sont les dimensions des jeux de données?

Consigne

Vous utiliserez la cellule de code ci-dessous pour mener les calculs dont vous aurez besoin, puis vous rédigerez votre réponse dans la cellule de texte qui suit, sous forme de phrase complète explicitant les nombres de lignes et de colonnes.

Vous procéderez de même dans tout le reste du TP.

### BEGIN SOLUTION
print(f"Species Shape: {species.shape}")
print(f"Observations Shape: {observations.shape}")
### END SOLUTION

BEGIN SOLUTION

Barème: 1 point pour le code et 1 point pour la réponse correcte et rédigée.

Il y a 5824 lignes et 4 colonnes pour species. Il y a 23296 lignes et 3 colonnes pour observations.

END SOLUTION

Jeu de données species#

Il est temps d’explorer un peu plus en profondeur la table species.

  1. Répondez aux questions suivantes :

    • Combien y a-t-il d’espèces différentes?

    • Ce nombre est-il égal aux nombre de lignes? Pourquoi?

    • Proposez des hypothèses permettant d’expliquer cette observation.

    todo

    reprendre la notion de unique et les aider a trouver ou le voir en cours!

### BEGIN SOLUTION
print(f"No of lines: {species.scientific_name.dropna().size}")
print(f"No of unique species: {species.scientific_name.dropna().nunique()}")
### END SOLUTION

BEGIN SOLUTION

Barême sur 4 points:

  • 1 point le code

  • 1 point pour le bon nombre

  • 1 point pour dire qu’il y a moins d’espèces que de lignes

  • 1 point hypothèses pertinentes

Il y a 5541 noms d’espèces différentes et 5824 lignes. Il n’y a pas de données manquantes (NA).

On retrouve moins d’espèces différentes que de lignes : certaines espèces comme le Wapiti ont plusieurs noms communs (common name), ce qui fait qu’on retrouve des redondances; d’autres comme le Loup ont plusieurs statuts de conservation.

  • 1ère hypothèse : On sait que le jeu de données regroupe des données sur plusieurs parcs. On peut supposer qu’en fonction de la localisation on n’appelle pas une espèce de la même manière. De plus, les différents parcs peuvent être très éloignés ce qui peut expliquer des variations de statut de conservations.

  • 2ème hypothèse : Le jeu de données s’est fait dans la durée, ce qui expliquerait les différences de statut de conservation. C’est un peu tiré par les cheveux car il faudrait que le jeu de données se soit fait sur des années.

END SOLUTION

  1. Calculez dans la variable ncat le nombre de catégories présentes dans la table. À quoi cette colonne correspond-t-elle?

### BEGIN SOLUTION
ncat = species.category.nunique()
ncat
### END SOLUTION

BEGIN SOLUTION

Cela correspond aux différents groupes phylogénétiques d’animaux ou de plantes.

END SOLUTION

assert ncat**2+32 == 81
  1. Calculez dans l’objet species_cat le nombre d’espèces par catégorie. Vous utiliserez la méthode groupby vue en cours. Faites un barplot pour représenter ce résultat. Quelle catégorie a le plus d’espèces? Est-ce surprenant?

Remarque

Les Vascular Plant correspondent aux Trachéophytes et regroupent les plantes à fleurs Angiospermes. Les Nonvascular plant correspondent aux plantes non-vasculaires*

### BEGIN SOLUTION
species_cat = species.groupby('category')['scientific_name'].nunique()

species_cat.plot(kind='bar'),
plt.title("Nombre d'espèces par catégorie"),
plt.xlabel("Catégories"),
plt.ylabel("Nombre d'espèces"),
plt.show()

#3 points pour la figure uniquement ! L'objet species_cat est noté avec des asserts:
# 1 point si barplot correct
# 1 point axes x et y correct
# 1 point titre correct

### END SOLUTION
assert isinstance(species_cat, pd.Series)
assert species_cat.size == 7
assert species_cat['Bird']>20

BEGIN SOLUTION

C’est la catégorie des Vascular Plant qui a le plus d’espèces. Ce n’est pas étonnant qu’il y en ai plus que de reptiles qui est un petit groupe ou de mammifères ou amphibiens, mais je me serai attendue a ce qu’il y ait plus d’oiseaux ou de poissons. Il y a vraiment BEAUCOUP plus de trachéophytes!

END SOLUTION

  1. Créer la variable species_statusqui contient les différents statuts possibles de ces espèces. Dans un paragraphe de texte, décrivez chacune de ces catégories. A votre avis, que signifie une valeur nan?

### BEGIN SOLUTION
species_status = species['conservation_status'].unique()
print(f"Les statuts possibles des espèces sont {species_status}")
### END SOLUTION
import hashlib
assert hashlib.md5(species_status[1].encode("utf-8")).hexdigest() == '5b98e09fa16ca9ffb8a4e6481fab1ef7'
assert hashlib.md5(species_status[2].encode("utf-8")).hexdigest() == 'e8ffc938d2592b28a666523cc1c80a5a'
assert hashlib.md5(species_status[3].encode("utf-8")).hexdigest() == '667cebca285ad56866f34c25309d99f3'
assert hashlib.md5(species_status[4].encode("utf-8")).hexdigest() == 'dd283e78058345d5e2ad72b7c7769579'

BEGIN SOLUTION

La colonne conservation_status a plusieurs valeurs possibles :

  • Species of Concern: «Espèce préoccupante», en déclin ou qui semblent avoir besoin d’être conservée.

  • Threatened: «Espèce menacée», vulnérable à une mise en danger dans un avenir proche.

  • Endangered: «Espèce en danger», gravement menacées d’extinction.

  • In Recovery: «Espèce en rétablissement», qui n’est plus en danger d’extinction dans l’ensemble ou dans une part importante de son aire de répartition.

END SOLUTION

Jeu de données observations#

On passe à l’observation de l’autre table, observations.

observations.describe(include="all")
  1. À partir de la commande ci-dessus répondez aux questions suivantes :

- Décrivez le contenu de la colonne `observations`.
- Combien y a-t-il de données manquantes dans la table `observations`?
- Combien d'espèces ont été vues au Yosemite?

Rappel: utilisez systématiquement des phrases complètes.

BEGIN SOLUTION

  • Une espèce est vue en moyenne 142 fois avec un écart type de 69,9. Une espèce est vue au minimum 9 fois et au maximum 321 fois.

  • Il y a quatre données manquantes.

  • 5824 espèces ont été vues au Yosemite.

END SOLUTION

  1. Indiquez dans npark le nombre de parcs étudiés. Où se situent-ils (faites une recherche internet)?

### BEGIN SOLUTION 
npark = observations.park_name.nunique()
print(f"Parks: {observations.park_name.unique()}")
npark
### END SOLUTION
assert npark**2+93 == 109

BEGIN SOLUTION

Ils se situent tous aux USA.

END SOLUTION

  1. Indiquez dans speciesMax le nom scientifique de l’espèce la plus observée. Quel est son nom dans le langage courant?

### BEGIN SOLUTION

speciesMax = observations.groupby('scientific_name')['observations'].sum().idxmax()
speciesMax

### END SOLUTION
assert hashlib.md5(speciesMax.encode("utf-8")).hexdigest() == 'eb0f1d26ae3ad8053d8291c2c24ad349'

BEGIN SOLUTION

C’est une espèce de tourterelle.

END SOLUTION

  1. Mettez dans l’objet parkMax le nom du parc dans lequel on trouve le plus d’observations.

### BEGIN SOLUTION
parkMax=observations.groupby(["park_name"])["observations"].sum().idxmax()
parkMax
### END SOLUTION
assert hashlib.md5(parkMax.encode("utf-8")).hexdigest() == '5702641a382396a92985fd8020739b63'

Analyse des données#

La première étape est de nettoyer et préparer les données.

  1. Y a-t-il des valeurs manquantes dans la table observations? Supprimez les lignes avec des données manquantes et stockez le résultat dans observations_cleaned

### BEGIN SOLUTION
print(f"Observation dimension {observations.shape}")
print(f"Observation without NA dimension {observations.dropna().shape}")
observations_cleaned = observations.dropna()
### END SOLUTION
assert observations_cleaned.shape == (23291, 3)
assert (observations_cleaned.notna()).all(axis=None)
  1. Dans la colonne conservation_status de la table species, remplacez les valeurs NaN par No Intervention. En effet, NaN signifie qu’il n’y a pas de spécification de conservation.

### BEGIN SOLUTION
species['conservation_status'] = species['conservation_status'].fillna("No Intervention")
### END SOLUTION

species = observations.groupby("scientific_name")["observations"].sum()

species = species.sort_values(ascending = False).reset_index()
species
assert (species.notna()).all(axis=None)

On calcule ensuite, sous la forme d’un tableau, le nombre d’espèces pour chaque catégorie et chaque statut de conservation dans l’objet group_status. Pour cela, on utilise entre autres les fonctions groupby() et unstack().

group_status = species.groupby('category')['conservation_status'].value_counts().unstack()
  1. ♣ Représentez ces données sous forme de carte de chaleur (heatmap).

### BEGIN SOLUTION
group_status.style.background_gradient(cmap='Greens', axis=None)
#plt.title("Répartition des catégories dans chaque statut de conservation")
#plt.xlabel("Statuts de conservation")
#plt.ylabel("Catégories"),
#plt.show()
### END SOLUTION
  1. ♣ Pareil avec Seaborn et sous forme d’une figure avec titre, etc.

### BEGIN SOLUTION
# Variante avec Seaborn et inclu dans une figure
sns.heatmap(group_status, annot=True, cmap= 'Greens')
plt.title("Répartition des catégories dans chaque statut de conservation")
plt.xlabel("Statuts de conservation")
plt.ylabel("Catégories"),
plt.show()
### END SOLUTION
assert isinstance(group_status, pd.DataFrame)
assert group_status.shape == (7,5)
  1. À quoi sert l’opération unstack?

BEGIN SOLUTION

Unstack permet de transformer le résultat en un tableau à double entrées avec le statut de conservation en colonnes et les groupes d’espèces en lignes.

END SOLUTION

  1. ♣ Dans la pratique, la plupart des espèces sont sans intervention, notamment pour les plantes. Refaites la figure en éliminant les espèces sans intervention. Gardez le nombre d’espèces par catégorie et par statut de conservation dans l’objet group_status_conserv.

### BEGIN SOLUTION

group_status_conserv = species[species.conservation_status != "No Intervention"].groupby('category')['conservation_status'].value_counts().unstack()

sns.heatmap(group_status_conserv, annot=True, cmap= 'Greens')
plt.title("Répartition des catégories dans chaque statut de conservation")
plt.xlabel("Statuts de conservation")
plt.ylabel("Catégories"),
plt.show()
### END SOLUTION
assert isinstance(group_status_conserv, pd.DataFrame)
assert group_status_conserv.shape == (7,4)
  1. ♣ Faites une nouvelle figure à partir de group_status_conserv de type barplot avec l’option stacked=True.

### BEGIN SOLUTION

fig = group_status_conserv.plot(kind="bar", figsize=(8,6), stacked=True)
fig.set_xlabel("Statut de conservation")
fig.set_ylabel("Nombre d'espèces");
## END SOLUTION
  1. A l’aide des analyses précédentes, répondez aux questions initiales en quelques phrases:

    • Quelle est la répartition des statuts de conservation des espèces?

    • Quel type d’être vivant est particulièrement en danger?

Commentez vos figures.

BEGIN SOLUTION

Barême sur 4 points:

  • 1 point : surtout pas de statut

  • 1 point : chaque catégorie a sa propre dynamique

  • 1 point : commentaires faits pour les figures (description d’au moins une figure de facon pertinente)

  • 1 point : commentaire croisé entre les figures avec/sans intervention : les oiseaux sont pas mal préoccupants.

On retrouve une inégalité écrasante quant au nombre d’espèces par catégorie et le danger qui les touche.

La carte de chaleur nous montre la répartition des catégories pour chaque statuts, on remarque que les oiseaux représentent la majorité dans les espèces préocupantes (envion 51%), suivi des Vascular Plant, puis des mammifères. On remarque d’ailleurs que sur une quinzaine d’espèces en danger, on a 7 mamifères. L’histogramme nous montre que dans le jeu de données species, on a plus de 75% qui sont des Vascular Plant, contre environ 3% pour les mammifères et 8% pour les oiseaux par exemple. Il nous montre que la très grande majorité des espèces sont préocupantes, et qu’il n y a qu’une petite minorité en rétablissement qui sont 3 fois moins que celles en danger (qui est l’étape précédente).

Finalement, on voit que ce ne sont pas les espèces les plus présentes qui demandent le plus d’attention; en effet 16% des oiseaux dans notre jeu de données sont des espèces préocupantes. Ces différentes figures nous montrent par le biais du grand nombre d’espèces préocupantes, la nécessité d’une surveillance accrue pour éviter qu’elles soient en danger étant donné la faible probabilité d’être ensuite en récupération.

END SOLUTION

Conservation#

On passe maintenant à la question : quelles sont les espèces plus susceptibles d’être suivies dans le cadre de la conservation?

  • Créez une nouvelle colonne is_protected qui vaut False pour toutes les espèces de statut No Intervention et True pour les autres.

### BEGIN SOLUTION
species['is_protected'] = np.where(species['conservation_status'] == 'No Intervention', False, True)
### END SOLUTION
assert species.shape == (5824, 5)
assert species['is_protected'].mean() < 0.033

Pour chaque catégorie calculez la proportion d’espèces protégées et mettez le resultat dans la variable prop_cat. Observez les résultats.

### BEGIN SOLUTION
prop_cat = species.groupby('category')["is_protected"].mean()
print((prop_cat*100).sort_values())
### END SOLUTION
assert prop_cat.mean() == 0.08455896094419532
assert prop_cat.max() == 0.17757009345794392

Évaluation#

Nous avons fini cette première partie de ce cours consacré aux analyses de données, avec un accent mis sur la [VI]sualisation des données. La semaine prochaine et jusqu’à fin du cours nous nous concentrerons sur la classification d’image par apprentissage statistiques, avec le schema d’analyse complet: VI-MÉ-BA-BAR.

Ce TP a permis d’analyser la composition en être vivants de quatre parcs nationaux.

  • Répondez de facon succinte aux questions du début du TP:

    • Quel animal est le plus répandu ? Quel parc possède le plus d’espèces ?

    • Quelle est la répartition des statuts de conservation des espèces ?

    • Certains types d’espèces sont-ils plus susceptibles d’être menacés ?

BEGIN SOLUTION

  • La majorité des espèces sont sans statut de conservation (5,633 vs 191).

  • Les mammifères et les oiseaux ont la plus grande proportion d’espèces à protéger. Anthropomorphisme (ce sont les espèces qu’on définit comme telle le plus facilement) ou bien espèces plus fragiles?

END SOLUTION

Obtenez votre score

Bravo, vous avez fini le TP.

Depuis le tableau de bord :

  1. Déposez votre travail

  2. Vérifiez que votre binôme est bien configuré, et notamment que le dépôt principal, marqué par une étoile, est le bon. Au besoin, consultez la page web
    Rappel: nous ne corrigerons que votre dépôt principal, tel que vous l’avez configuré!

  3. Consultez votre score.
    Rappel: le calcul du score peut prendre quelques minutes. Vous devez relancer le tableau de bord, ou consultez le dépôt pour le voir. Cliquez sur le badge avec le score pour avoir les détails et les commentaires. Les commentaires et donc le score total sera mis à jour seulement après correction par votre enseignant ou enseignante.