L’objectif de ce TP est de pratiquer les quelques commandes essentiels de la bagarre avec les données dans le tidyverse (Wickham, Çetinkaya-Rundel, et Grolemund 2023).
L’inventaire de la parcelle 6 de Paracou est fourni. C’est un tableau qui contient une ligne par arbre mesuré sur le terrain, avec son identification botanique et ses coordonnées géographiques et sa taille.
C’est un fichier texte au format CSV latin: le séparateur décimal est
la virgule. Pour le lire, on utilise la fonction
read_csv2()
du tidyverse, plus efficace que
read.csv2
de R base: le résultat est un tibble, qui est un
dataframe amélioré.
library("tidyverse")
read_csv2("data/Paracou6.csv")
## # A tibble: 3,541 × 10
## SubPlot idTree Xfield Yfield Family spName Genus
## <dbl> <dbl> <dbl> <dbl> <chr> <chr> <chr>
## 1 1 100655 7.5 180. Perac… Pogon… Pogo…
## 2 1 100657 8 184. Perac… Pogon… Pogo…
## 3 1 100658 5.5 182. Chrys… Lican… Lica…
## 4 1 100659 1.5 186 Eupho… Sandw… Sand…
## 5 1 100660 0.5 190 Fabac… Eperu… Eper…
## # ℹ 3,536 more rows
## # ℹ 3 more variables: Species <chr>,
## # CircCorr <dbl>, species <chr>
Les colonnes sont la sous-parcelle (SubPlot, sans intérêt ici), l’identifiant de l’arbre (idTree, unique), sa position (XField et YField, dans le repère de la parcelle), son identification botanique (Family, Genus, Species et spName qui regroupe genre et espèce) et sa taille (CircCorr, circonférence à hauteur de poitrine, corrigée si l’arbre n’est pas rond).
Les wapas (Eperua) sont un genre abondant dont la
distribution des deux espèces présentes à Paracou a été très étudiée.
Nous allons en faire une carte. Pour cela, nous allons utiliser les
commandes classiques du tidyverse, enchâinées grâce au pipeline
%>%
. Chaque étape est ajoutée à la précédente quand
celle-ci fonctionne correctement.
Pour ne retenir que certaines lignes, on utilise la fonction
filter()
: on dit qu’on filtre les lignes, et on
évite de parler de sélection des lignes, la fonction
select()
servant à sélectionner des colonnes.
# Lecture des données
read_csv2("data/Paracou6.csv") %>%
# Filtrage des wapas
filter(Genus == "Eperua")
## # A tibble: 333 × 10
## SubPlot idTree Xfield Yfield Family spName Genus
## <dbl> <dbl> <dbl> <dbl> <chr> <chr> <chr>
## 1 1 100660 0.5 190 Fabac… Eperu… Eper…
## 2 1 100665 2.5 206 Fabac… Eperu… Eper…
## 3 1 100676 9 222 Fabac… Eperu… Eper…
## 4 1 100677 7 226 Fabac… Eperu… Eper…
## 5 1 100691 4 247 Fabac… Eperu… Eper…
## # ℹ 328 more rows
## # ℹ 3 more variables: Species <chr>,
## # CircCorr <dbl>, species <chr>
Le code équivalent en R classique est:
# Lecture des données
paracou6 <- read.csv2("data/Paracou6.csv")
# Quels sont les wapas ?
est_wapa <- paracou6$Genus == "Eperua"
# Filtrage des lignes par le vecteur logique
paracou6_wapa <- paracou6[est_wapa, ]
# Affichage des premières lignes
head(paracou6_wapa)
## SubPlot idTree Xfield Yfield Family
## 5 1 100660 0.5 190.0 Fabaceae
## 9 1 100665 2.5 206.0 Fabaceae
## 19 1 100676 9.0 222.0 Fabaceae
## 20 1 100677 7.0 226.0 Fabaceae
## 32 1 100691 4.0 247.0 Fabaceae
## 33 1 100692 9.5 249.5 Fabaceae
## spName Genus Species CircCorr species
## 5 Eperua_falcata Eperua falcata 77.0 falcata
## 9 Eperua_falcata Eperua falcata 167.0 falcata
## 19 Eperua_falcata Eperua falcata 133.0 falcata
## 20 Eperua_falcata Eperua falcata 123.5 falcata
## 32 Eperua_falcata Eperua falcata 150.0 falcata
## 33 Eperua_falcata Eperua falcata 98.0 falcata
La syntaxe classique est plus difficile à lire et nécessite de nombreuses variables intermédiaires. En pratique, un pipeline est beaucoup plus efficace. D’autre part, l’affichage à l’écran des tibbles est bien plus lisible que celui des dataframes.
Il reste à créer un graphique avec ggplot()
. La
géométrie définit le type de graphique: ici, des points avec
geom_point()
. L’esthétique (fonction aes()
)
consiste à décrire les caractéristiques de ces points:
x
et y
,size
et leur couleur
color
.# Lecture des données
read_csv2("data/Paracou6.csv") %>%
# Filtrage des wapas
filter(Genus == "Eperua") %>%
# Graphique. Les éléments du graphique sont ajoutés avec l'opérateur +
ggplot() +
# Un point par arbre
geom_point(aes(x = Xfield, y = Yfield, size = CircCorr, color = Species)) +
# Même échelle pour les abscisses et ordonnées pour ne pas déformer la carte
coord_fixed() +
# Texte des axes et de la légende
labs(x = NULL, y = NULL, size = "Circonférence", color = "Espèce")
L’esthétique est héritable: elle peut être déclarée dans chaque
géométrie ou au niveau global de ggplot()
pour s’appliquer
à toutes les géométries s’il y en a plusieurs. Le graphique suivant
affiche la carte des très gros arbres (plus de 250cm de circonférence)
avec leur identifiant. Les positions (esthétique x
et
y
) sont communes aux deux géométries (points et texte),
mais chacune des géométries a sa propre esthétique en complément: la
taille et la couleur des points et l’étiquette.
# Lecture des données
read_csv2("data/Paracou6.csv") %>%
# Filtrage des très gros arbres
filter(CircCorr > 250) %>%
# Graphique. Les éléments du graphique sont ajoutés avec l'opérateur +
ggplot(aes(x = Xfield, y = Yfield)) +
# Un point par arbre
geom_point(aes(size = CircCorr, color = Family)) +
# Etiquettes. Taille du texte et décalage au dessus du point
geom_text(aes(label = idTree), size = 2, nudge_y = 5) +
# Même échelle pour les abscisses et ordonnées pour ne pas déformer la carte
coord_fixed() +
# Texte des axes et de la légende
labs(x = NULL, y = NULL, size = "Circonférence", color = "Famille")
Des calculs peuvent être réalisés à partir des données du tableau:
mutate()
,L’objectif est maintenant de lister les espèces les plus abondantes dans la parcelle en calculant leur effectif et leur surface terrière totale.
La première étape consiste à sélectionner les colonnes utiles. Elle est rarement indispensable mais permet de mieux voir les données. Ici, on conserve le nom de l’espèce et la circonférence.
# Lecture des données
read_csv2("data/Paracou6.csv") %>%
# Sélection des colonnes utiles
select(spName, CircCorr)
## # A tibble: 3,541 × 2
## spName CircCorr
## <chr> <dbl>
## 1 Pogonophora_schomburgkiana 44
## 2 Pogonophora_schomburgkiana 43.5
## 3 Licania_membranacea 53.5
## 4 Sandwithia_guyanensis 38.5
## 5 Eperua_falcata 77
## # ℹ 3,536 more rows
La surface terrière (en m2) est calculée à partir de la circonférence (en cm).
# Lecture des données
read_csv2("data/Paracou6.csv") %>%
# Sélection des colonnes utiles
select(spName, CircCorr) %>%
# Calcul de la surface terrière
mutate(G = CircCorr^2 / 4 / pi / 10000)
## # A tibble: 3,541 × 3
## spName CircCorr G
## <chr> <dbl> <dbl>
## 1 Pogonophora_schomburgkiana 44 0.0154
## 2 Pogonophora_schomburgkiana 43.5 0.0151
## 3 Licania_membranacea 53.5 0.0228
## 4 Sandwithia_guyanensis 38.5 0.0118
## 5 Eperua_falcata 77 0.0472
## # ℹ 3,536 more rows
On regroupe (group_by()
) les individus par espèce et on
calcule (summarize()
) leur nombre et la somme des surfaces
terrières.
# Lecture des données
read_csv2("data/Paracou6.csv") %>%
# Sélection des colonnes utiles
select(spName, CircCorr) %>%
# Calcul de la surface terrière
mutate(G = CircCorr^2 / 4 / pi / 10000) %>%
# Grouper par espèce
group_by(spName) %>%
# Calculer le nombre de tiges et la surface terrière par ha
summarize(Abondance = n(), Surface = sum(G) / 6.25)
## # A tibble: 335 × 3
## spName Abondance Surface
## <chr> <int> <dbl>
## 1 Abarema_jupunba 10 0.166
## 2 Abarema_mataybifolia 4 0.0214
## 3 Albizia_pedicellaris 3 0.109
## 4 Amaioua_guianensis 2 0.00471
## 5 Amanoa_congesta 1 0.00258
## # ℹ 330 more rows
La fonction n()
compte les lignes de chaque groupe. Les
colonnes du tableau qui n’ont pas servi au regroupement sont éliminées:
c’est la raison pour laquelle la sélection préalable des colonnes utiles
select()
est en général inutile.
Il reste à trier (arrange()
) les espèces par surface
terrière décroissante (appliquer la fonction desc()
à la
colonne).
# Lecture des données
read_csv2("data/Paracou6.csv") %>%
# Sélection des colonnes utiles
select(spName, CircCorr) %>%
# Calcul de la surface terrière
mutate(G = CircCorr^2 / 4 / pi / 10000) %>%
# Grouper par espèce
group_by(spName) %>%
# Calculer le nombre de tiges et la surface terrière par ha
summarize(Abondance = n(), G_ha = sum(G) / 6.25) %>%
# Tri
arrange(desc(G_ha))
## # A tibble: 335 × 3
## spName Abondance G_ha
## <chr> <int> <dbl>
## 1 Eperua_falcata 266 5.68
## 2 Eschweilera_sagotiana 151 1.69
## 3 Eperua_grandiflora 67 1.50
## 4 Vouacapoua_americana 91 1.44
## 5 Tapura_capitulifera 63 1.13
## # ℹ 330 more rows
La surface de la parcelle est 6,25ha: la surface terrière totale est donc divisée par 6,25 pour obtenir sa valeur par hectare. L’espèce la plus abondante est le wacapou (Eperua falcata).
Le code complet ci-dessous enregistre le tableau final dans une variable.
# Lecture des données
read_csv2("data/Paracou6.csv") %>%
# Sélection des colonnes utiles
select(spName, CircCorr) %>%
# Calcul de la surface terrière
mutate(G = CircCorr^2 / 4 / pi / 10000) %>%
# Grouper par espèce
group_by(spName) %>%
# Calculer le nombre de tiges et la surface terrière par ha
summarize(Abondance = n(), G_ha = sum(G) / 6.25) %>%
# Tri
arrange(desc(G_ha)) ->
# Variable de stockage du résultat
paracou6_G_espece
La syntaxe la plus naturelle pour affecter le tableau à une variable utilise la flèche vers la droite à la fin du pipeline, dans le sens de la progression des données.
Souvent, une valeur unique est attendue plutôt qu’un tableau.
Nous calculons maintenant le nombre d’arbres et la surface terrière par hectare toutes essences confondues. Le code est similaire au précédent avec des simplifications:
# Lecture des données
read_csv2("data/Paracou6.csv") %>%
# Calcul de la surface terrière
mutate(G = CircCorr^2 / 4 / pi / 10000) %>%
# Calcul du nombre de tiges et la surface terrière par ha
summarize(Densite = n() / 6.25, G_ha = sum(G) / 6.25)
## # A tibble: 1 × 2
## Densite G_ha
## <dbl> <dbl>
## 1 567. 31.7
Pour extraire la surface terrière du tableau final et la placer dans
une variable numérique (un vecteur à un seul élément), on utile la
fonction pluck()
. Attention:
select()
.# Lecture des données
read_csv2("data/Paracou6.csv") %>%
# Calcul de la surface terrière
mutate(G = CircCorr^2 / 4 / pi / 10000) %>%
# Calculer la surface terrière par ha
summarize(G_ha = sum(G) / 6.25) %>%
# Extraire la valeur de G_ha
pluck("G_ha") ->
# Affectation à une variable numérique
G_ha
# Affichage
G_ha
## [1] 31.68715
La valeur étant sauvegardée dans une variable, elle peut être incluse dans le texte d’un rapport: la surface terrière de la parcelle 6 de Paracou est égale à 31.7 m2/ha.