10.6 Syntaxe de R
Dans cette dernière section du module (ref?)(variance2), nous revenons sur nos outils logiciels. C’est bien de connaître les techniques de visualisation et d’analyse des données, mais c’est encore mieux de pouvoir les appliquer en pratique… et pour cela il faut maîtriser un ou plusieurs logiciels. Nous avons utilisé principalement R, avec l’interface proposée par RStudio. Nous allons maintenant approfondir quelque peu nos connaissances en R.
Vous avez pu vous rendre compte que R n’est pas qu’un logiciel de science des données. Il comprend également un langage informatique du même nom57 dédié à la manipulation, la visualisation et l’analyse des données.
Les langages informatiques sont, pour la plupart, conçus autour de standards bien définis. Mais R est toujours resté volontairement très libertaire à ce niveau. Comme R permet également de presque tout redéfinir dans son langage, il est apparu au cours du temps différents styles. Ces styles co-existent et co-existeront encore longtemps, car ils ont tous des avantages et des inconvénients, ce qui mène à des choix personnels de chaque utilisateur dictés par l’usage qu’il fait de R, ses goûts, son caractère, et comment il a été formé (à quelle “école” il appartient). Nous n’entrerons pas dans les débats stériles autant que passionnés autour de ces questions de styles. Il est cependant utile de comprendre ces différentes approches au moins dans leurs grandes lignes.
Aujourd’hui, on peut distinguer principalement trois styles dans R, résumés dans un aide-mémoire :
La syntaxe de base ou syntaxe dollar est celle héritée du langage S. Elle fait la part belle aux instructions d’indiçage comme
v[i]
oudf[i, j]
, et à l’opérateur dollar$
pour extraire, par exemple la variablex
du data framedf
à l’aide dedf$x
, d’où son nom. Une instruction type en R de base serafun(df$x, df$y)
. L’objet R central pour les statistiques est ledata.frame
qui est conçu pour contenir un tableau de données de type cas par variables.La syntaxe formule qui utilise une formule (objet ressemblant à une équation mathématique et utilisant le “tilde”
~
pour séparer le membre de gauche et le membre de droite). Nous avons utilisé des formules dans le cadre de graphiques réalisés à l’aide dechart()
ou pour nos ANOVAs, par exemple. Une instruction se présente typiquement commefun(y ~ x, data = df)
, même si nous préférons dans SciViews::R inverser les deux arguments et écrirefun(data = df, y ~ x)
. La syntaxe formule est souvent associée également à un data.frame (l’argumentdata =
), même si une liste, un tibble (voir ci-dessous) ou tout autre objet similaire (comme un data.table) peut aussi souvent être utilisé.La syntaxe “tidyverse” qui vise à produire des instructions aussi lisibles que possible (lecture proche d’un langage naturel humain). Cette syntaxe utilise quelques astuces de programmation pour rendre les instructions plus digestes et s’affranchir du
df$x
pour pouvoir écrire uniquementx
à la place. Elle fait également la part belle au chaînage des instructions (opérateur de “pipe”) que nous avons étudié à la fin du module 4. Une instruction type seradf %>% fun(x, y)
, même si dans SciViews::R nous préférons l’opérateur plus explicite%>.%
qui donnedf %>.% fun(., x, y)
. Tidyverse est constitué d’un ensemble de packages R qui se conforment à un style bien défini autour d’une version spéciale de data frame appelée tibble.
Dans le cadre de ce cours, nous utilisons un style propre à SciViews::R Il est associé à une série de packages chargés à partir de l’instruction SciViews::R
. Ce style tente de rendre l’utilisation de R plus cohérente et plus facile en reprenant le meilleur des trois styles précédents, et en y ajoutant une touche personnelle élaborée pour éliminer autant que possible les erreurs fréquentes observées lors de l’apprentissage ou de l’utilisation de R. Dans la suite de cette section, nous allons comparer quelques instructions équivalentes, mais rédigées dans différents styles pour nous familiariser avec eux et pour comprendre leurs atouts respectifs. Assurez-vous de conserver à proximité l’aide-mémoire sur les différentes syntaxes de R pour vous aider. Mais avant toute chose, un petit complément concernant l’indiçage dans R est nécessaire.
10.6.1 Indiçage dans R
Après l’opérateur particulier <-
d’assignation (associer une valeur à un nom dans un langage informatique), les diverses variantes de l’indiçage de vecteurs, matrices et data frames sont caractéristiques de R. Elles sont puissantes, mais nécessitent de s’y attarder un peu pour bien les comprendre.
Les données et les calculs dans R sont vectorisés. Cela signifie que l’élément de base est un vecteur. Un vecteur est un ensemble d’éléments rangés dans un ordre bien défini, et éventuellement nommés. La longueur du vecteur s’obtient avec length()
, et il est possible de spécifier un ou plusieurs éléments du vecteur à l’aide de l’opérateur []
.
# Un vecteur contenant 4 valeurs numériques nommées a, b, c et d
v <- c(a = 2.6, b = 7.1, c = 4.9, d = 5.0)
# Le second élément du vecteur
v[2]
# b
# 7.1
# a c
# 2.6 4.9
# a b c
# 2.6 7.1 4.9
Nous venons d’indicer notre vecteur v
à l’aide de la première forme possible qui consiste à utiliser des entiers positifs pour indiquer la position des éléments que nous souhaitons retenir.
La seconde forme utilise des entiers négatifs pour éliminer les vecteurs aux positions correspondantes.
# a c d
# 2.6 4.9 5.0
# a d
# 2.6 5.0
# a b c
# 2.6 7.1 4.9
La troisième forme d’indiçage nécessite que le vecteur soit nommé, comme c’est le cas pour v
. Nous pouvons alors indicer en utilisant des chaînes de caractères correspondant aux noms des différents éléments.
# a
# 2.6
# b d
# 7.1 5.0
Enfin, la quatrième forme d’indiçage utilise un vecteur booléen (TRUE
ou FALSE
; on dit logical en R) de même longueur que le vecteur, sinon les valeurs sont recyclées à concurrence de la longueur du vecteur. On ne garde que les éléments correspondants à TRUE
.
# a d
# 2.6 5.0
# a c
# 2.6 4.9
La dernière instruction mérite une petite explication supplémentaire. Le vecteur logical d’indiçage utilisé ne contient que deux éléments alors que le vecteur v
qui est indicé en contient quatre. Les valeurs logiques sont alors recyclées comme suit. Lorsqu’on arrive la fin, on reprend au début. Donc, TRUE
, on garde le premier, FALSE
on élimine le second, et puis… retour au début : TRUE
on garde le troisième, FALSE
on jette le quatrième, et ainsi de suite si v
était plus long. Donc, un indiçage avec c(TRUE, FALSE)
permet de ne garder que les éléments d’ordre impair quel que soit la longueur de v
, et c(FALSE, TRUE)
ne gardera que les éléments d’ordre pair.
La puissance de l’indiçage par valeur booléenne est immense, car nous pouvons aussi utiliser une expression qui renvoie de telles valeurs. C’est le cas notamment de toutes les instructions de comparaison (opérateurs égal à ==
, différent de !=
, plus grand que >
, plus petit que <
, plus grand ou égal >=
ou plus petit ou égal <=
). Par exemple pour ne garder que les valeurs plus grandes que 3, on fera :
# a b c d
# FALSE TRUE TRUE TRUE
# b c d
# 7.1 4.9 5.0
Les instructions de comparaison peuvent être combinées entre elles à l’aide des opérateurs “et” (&
) ou “ou” (|
). Donc, pour récupérer les éléments qui sont plus grands que 3 et plus petits ou égaux à 5, on fera :
# c d
# 4.9 5.0
Les indiçages fonctionnent aussi pour des objets bi- or multidimensionnels. Dans ce cas, nous utiliserons deux ou plusieurs instructions d’indiçage à l’intérieur des []
, séparées par un virgule. Pour un tableau à deux dimensions comme une matrice ou un data frame, le premier élément sélectionne les lignes et le second les colonnes.
# x y z
# <num> <num> <num>
# 1: 1 2 3
# 2: 4 5 6
# y z
# <num> <num>
# 1: 2 3
Pour conserver toutes les lignes et/ou toutes les colonnes, il suffit de laisser la position correspondante vide.
# x y z
# <num> <num> <num>
# 1: 4 5 6
# y
# <num>
# 1: 2
# 2: 5
# x y z
# <num> <num> <num>
# 1: 1 2 3
# 2: 4 5 6
Les autres formes d’indiçage fonctionnent aussi.
# Lignes pour lesquelles x est plus grand que 3 et colonnes nommée 'y' et 'z'
df[df$x > 3, c('y', 'z')]
# y z
# <num> <num>
# 1: 5 6
Notez bien que nous n’avons pas écrit, df[x > 3, ]
mais df[df$x > 3, ]
. La première forme n’aurait pas utilisé la variable x
du data frame df
(notée df$x
), mais aurait tenté d’utiliser un vecteur x
directement. Ce qui nous amène à l’extraction d’un élément d’un tableau ou d’une liste à l’aide des opérateurs [[]]
ou $
. Pour extraire la colonne y
sous forme d’un vecteur de df
, nous pourrons faire :
# [1] 2 5
# [1] 2 5
# [1] 2 5
Pour finir, l’indiçage peut aussi être réalisé à la gauche de l’opérateur d’assignation <-
. Dans ce cas, la partie concernée du vecteur, de la matrice ou du data frame est remplacée par la ou les valeurs de droite.
# x y z
# <num> <num> <num>
# 1: 1 2 -10
# 2: 4 5 -15
# x y z
# <num> <num> <num>
# 1: 1 2 -10
# 2: 4 5 -15
Maintenant que nous sommes familiarisés avec les différents modes d’indiçage dans R de base, nous pouvons les comparer à d’autres styles.
10.6.2 Comparaison de styles
Nous allons réaliser quelques opérations simples sur un jeu de données cas par variables. Nous allons créer un tableau de contingence à une entrée, sélectionner des cas et restreindre les variables du tableau, calculer une nouvelle variable, pour finir avec une représentation graphique simple. Nous ferons le même travail en utilisant les différents styles de R à des fins de comparaison.
Prenons le jeu de données zooplankton
qui contient 19 mesures (variables numériques) effectuées sur des images de zooplancton, ainsi que le groupe taxonomique auquel les organismes appartiennent (variable facteur class
). Nous avons toujours utilisé la fonction read()
pour charger ce type de données. Cette fonction fait partie de SciViews::R
.
Name | zoo |
Number of rows | 1262 |
Number of columns | 20 |
Key | NULL |
_______________________ | |
Column type frequency: | |
factor | 1 |
numeric | 19 |
________________________ | |
Group variables | None |
Variable type: factor
skim_variable | n_missing | complete_rate | ordered | n_unique | top_counts |
---|---|---|---|---|---|
class | 0 | 1 | FALSE | 17 | Cal: 288, Poe: 158, Déc: 126, Mal: 121 |
Variable type: numeric
skim_variable | n_missing | complete_rate | mean | sd | p0 | p25 | p50 | p75 | p100 | hist |
---|---|---|---|---|---|---|---|---|---|---|
ecd | 0 | 1 | 0.81 | 0.51 | 0.28 | 0.54 | 0.67 | 0.88 | 7.25 | ▇▁▁▁▁ |
area | 0 | 1 | 0.72 | 1.74 | 0.06 | 0.23 | 0.35 | 0.61 | 41.27 | ▇▁▁▁▁ |
perimeter | 0 | 1 | 6.45 | 6.31 | 0.95 | 2.82 | 4.33 | 7.81 | 89.26 | ▇▁▁▁▁ |
feret | 0 | 1 | 1.81 | 1.55 | 0.31 | 0.93 | 1.34 | 2.05 | 10.59 | ▇▁▁▁▁ |
major | 0 | 1 | 1.33 | 1.28 | 0.29 | 0.74 | 0.91 | 1.38 | 10.01 | ▇▁▁▁▁ |
minor | 0 | 1 | 0.56 | 0.37 | 0.18 | 0.36 | 0.48 | 0.63 | 5.91 | ▇▁▁▁▁ |
mean | 0 | 1 | 0.21 | 0.12 | 0.02 | 0.13 | 0.20 | 0.27 | 0.78 | ▆▇▂▁▁ |
mode | 0 | 1 | 0.07 | 0.20 | 0.00 | 0.01 | 0.02 | 0.03 | 1.02 | ▇▁▁▁▁ |
min | 0 | 1 | 0.01 | 0.00 | 0.00 | 0.00 | 0.00 | 0.01 | 0.03 | ▇▁▁▁▁ |
max | 0 | 1 | 0.70 | 0.22 | 0.07 | 0.54 | 0.68 | 0.89 | 1.02 | ▁▃▇▇▇ |
std_dev | 0 | 1 | 0.17 | 0.07 | 0.01 | 0.12 | 0.17 | 0.22 | 0.42 | ▃▇▆▂▁ |
range | 0 | 1 | 0.69 | 0.22 | 0.06 | 0.53 | 0.68 | 0.88 | 1.02 | ▁▃▇▇▇ |
size | 0 | 1 | 0.94 | 0.73 | 0.28 | 0.59 | 0.71 | 1.02 | 7.40 | ▇▁▁▁▁ |
aspect | 0 | 1 | 0.54 | 0.24 | 0.06 | 0.35 | 0.52 | 0.74 | 1.00 | ▃▇▇▆▅ |
elongation | 0 | 1 | 17.44 | 17.17 | 1.00 | 5.19 | 11.93 | 24.25 | 134.36 | ▇▂▁▁▁ |
compactness | 0 | 1 | 6.24 | 5.43 | 1.10 | 2.35 | 4.46 | 8.37 | 43.41 | ▇▂▁▁▁ |
transparency | 0 | 1 | 0.09 | 0.11 | 0.00 | 0.01 | 0.05 | 0.12 | 0.54 | ▇▂▁▁▁ |
circularity | 0 | 1 | 0.31 | 0.24 | 0.02 | 0.12 | 0.22 | 0.43 | 0.91 | ▇▅▂▁▂ |
density | 0 | 1 | 0.13 | 0.25 | 0.00 | 0.04 | 0.07 | 0.15 | 5.74 | ▇▁▁▁▁ |
Voici comment se distribuent les organismes en fonction de class
, en utilisant la syntaxe de base :
#
# Annélide Appendiculaire Calanoïde Chaetognathe
# 50 36 288 51
# Cirripède Cladocère Cnidaire Cyclopoïde
# 22 50 22 50
# Décapode Oeuf_allongé Oeuf_rond Poisson
# 126 50 49 50
# Gastéropode Harpacticoïde Malacostracé Poecilostomatoïde
# 50 39 121 158
# Protiste
# 50
La fonction table()
crée un objet du même nom qui se comporte de manière différente d’un data frame. Ainsi, l’impression de l’objet se présente comme un ensemble de valeurs nommées par le niveau dénombré pour un tableau de contingence à une seule entrée.
Si vous voulez réaliser la même opération à l’aide d’une formule, vous pouvez utiliser la fonction tally()
depuis le package {mosaic}. Vous pouvez charger ce package à l’aide de l’instruction library(mosaic)
, et ensuite utiliser tally()
comme si de rien n’était, ou alors vous spécifiez complètement la fonction à l’aide de mosaic::tally()
(littéralement, “la fonction tally()
du package {mosaic}”). Cette dernière approche est favorisée par SciViews::R, car elle permet de comprendre immédiatement d’où vient la fonction et d’éviter aussi d’appeler malencontreusement une fonction du même nom qui serait définie dans un autre package.
# Registered S3 method overwritten by 'mosaic':
# method from
# fortify.SpatialPolygonsDataFrame ggplot2
# class
# Annélide Appendiculaire Calanoïde Chaetognathe
# 50 36 288 51
# Cirripède Cladocère Cnidaire Cyclopoïde
# 22 50 22 50
# Décapode Oeuf_allongé Oeuf_rond Poisson
# 126 50 49 50
# Gastéropode Harpacticoïde Malacostracé Poecilostomatoïde
# 50 39 121 158
# Protiste
# 50
Tidyverse favorise l’assemblage d’un petit nombre de fonctions (des “verbes”) pour obtenir les mêmes résultats que des fonctions plus spécialisées dans les autres styles. Ainsi, ses instructions seront souvent plus verbeuses (inconvénient), mais aussi beaucoup plus lisibles et compréhensibles par un humain (immense avantage). La réalisation d’un tableau de contingence consiste en fait à regrouper les données en fonction de la variable class
, et ensuite à compter (contingenter) les observations dans chaque classe. Nous pouvons écrire une instruction qui réalise exactement ce traitement de manière explicite (sachant que la fonction n()
sert à dénombrer) :
# # A tibble: 17 × 2
# class `n()`
# <fct> <int>
# 1 Annélide 50
# 2 Appendiculaire 36
# 3 Calanoïde 288
# 4 Chaetognathe 51
# 5 Cirripède 22
# 6 Cladocère 50
# 7 Cnidaire 22
# 8 Cyclopoïde 50
# 9 Décapode 126
# 10 Oeuf_allongé 50
# 11 Oeuf_rond 49
# 12 Poisson 50
# 13 Gastéropode 50
# 14 Harpacticoïde 39
# 15 Malacostracé 121
# 16 Poecilostomatoïde 158
# 17 Protiste 50
Attention : rappelez-vous ici que sgroup_by()
et ssummarise()
ne sont pas compatibles avec n()
.
Nous obtenons un objet tibble, et non pas un objet spécifique au traitement réalisé. C’est dans la philosophie de Tidyverse que d’utiliser et réutiliser autant que possible un tibble qui permet de contenir des données “bien rangées” (ou “tidy data” en anglais, d’où le nom de ce style, tidyverse pour “univers bien rangé”).
Comme contingenter des observations est une opération fréquente, il existe exceptionnellement une fonction dédiée qui fait le travail en une seule opération : count()
.
# class n
# <fctr> <int>
# 1: Annélide 50
# 2: Appendiculaire 36
# 3: Calanoïde 288
# 4: Chaetognathe 51
# 5: Cirripède 22
# 6: Cladocère 50
# 7: Cnidaire 22
# 8: Cyclopoïde 50
# 9: Décapode 126
# 10: Oeuf_allongé 50
# 11: Oeuf_rond 49
# 12: Poisson 50
# 13: Gastéropode 50
# 14: Harpacticoïde 39
# 15: Malacostracé 121
# 16: Poecilostomatoïde 158
# 17: Protiste 50
Le résultat est le même. Comparons maintenant la fonction table()
de base et count()
de tidyverse du point de vue des arguments. table()
prends un vecteur comme argument. À nous de l’extraire du data frame à l’aide de zoo$class
, ce qui donne table(zoo$class)
. Par contre, count()
comme toute fonction tidyverse qui se respecte, prend comme premier argument un tibble, un data.table ou un data.frame, bref un tableau cas par variables. C’est ensuite au niveau du second argument que l’on spécifie la variable que nous souhaitons utiliser à partir de ce tableau. Ici, plus besoin d’indiquer que c’est une variable qui vient du tableau zoo
, car count()
le sait déjà. Bien que ce ne soit pas évident au premier coup d’œil, count()
ne respecte pas la syntaxe de base de R et évalue class
de manière particulière58. Au final, l’appel à table()
nécessite de comprendre ce que fait l’opérateur $
. Au contraire, l’instruction tidyverse count(zoo, class)
se lit et se comprend très bien presque comme si c’était écrit en anglais. Vous lisez en effet “compte dans zoo la classe” (avantage), mais le coût en est une évaluation non standard de ses arguments (inconvénient qui ne peut pas apparaître à ce stade, mais que vous constaterez plus tard quand vous ferez des choses plus évoluées avec ces instructions).
Le style de SciViews::R accepte à la fois la syntaxe de base et celle de tidyverse, avec une préférence pour cette dernière lorsque la lisibilité des instructions est primordiale. Il propose même sa propre version des fonctions “tidy”, sous forme de fonctions “speedy” dont le nom commence par ‘s’ est sont souvent plus rapides. De plus, le style formule est également abondamment utilisé dès qu’il s’agit de réaliser un graphique ou un modèle statistique (les deux étant d’ailleurs souvent associés).
Bien. Admettons maintenant que nous voulons représenter la forme (ratio d’aspect, rapport largeur / longueur) des œufs en fonction de leur taille sur un graphique (en utilisant les variables aspect
et area
) présents dans notre échantillon de zooplancton. Deux niveaux de la variable class
les contiennent : "Oeuf_allongé"
et "Oeuf_rond"
. Nous voulons donc filtrer les données du tableau zoo
pour ne garder que ces deux catégories, et éventuellement, nous voulons aussi restreindre le tableau aux trois variables aspect
, area
et class
puisque nous n’avons pas besoin des autres variables. En R de base cela peut se faire en une seule étape à l’aide de l’opérateur d’indiçage []
comme nous avons vu plus haut.
zoo2 <- zoo[zoo$class == "Oeuf_allongé" | zoo$class == "Oeuf_rond",
c("aspect", "area", "class")]
zoo2
# aspect area class
# <num> <num> <fctr>
# 1: 0.9654882 0.3853 Oeuf_rond
# 2: 0.9762261 6.0352 Oeuf_rond
# 3: 0.9640408 0.2707 Oeuf_rond
# 4: 0.9113587 0.2588 Oeuf_rond
# 5: 0.9497946 0.3223 Oeuf_rond
# 6: 0.9590398 0.3346 Oeuf_rond
# 7: 0.9757848 0.3430 Oeuf_rond
# 8: 0.9751285 1.1143 Oeuf_rond
# 9: 0.4486249 0.4951 Oeuf_allongé
# 10: 0.9869350 2.0217 Oeuf_rond
# 11: 0.9753539 0.4795 Oeuf_rond
# 12: 0.9507730 0.4882 Oeuf_rond
# 13: 0.9271179 0.3496 Oeuf_rond
# 14: 0.8964930 0.3492 Oeuf_rond
# 15: 0.9565761 0.4798 Oeuf_rond
# 16: 0.4387639 0.5183 Oeuf_allongé
# 17: 0.9749170 0.5065 Oeuf_rond
# 18: 0.4279144 0.4805 Oeuf_allongé
# 19: 0.9198379 0.1425 Oeuf_rond
# 20: 0.8558559 0.5569 Oeuf_rond
# 21: 0.9369791 0.3442 Oeuf_rond
# 22: 0.9693467 1.8668 Oeuf_rond
# 23: 0.9854697 0.1953 Oeuf_rond
# 24: 0.9466777 0.5319 Oeuf_rond
# 25: 0.4257993 0.5288 Oeuf_allongé
# 26: 0.4899826 0.5072 Oeuf_allongé
# 27: 0.9394750 0.4545 Oeuf_rond
# 28: 0.9784003 0.6071 Oeuf_rond
# 29: 0.2777371 0.5857 Oeuf_allongé
# 30: 0.9545853 0.3516 Oeuf_rond
# 31: 0.3612644 0.6114 Oeuf_allongé
# 32: 0.2994636 0.5905 Oeuf_allongé
# 33: 0.3219424 0.6129 Oeuf_allongé
# 34: 0.9336704 0.3316 Oeuf_rond
# 35: 0.2627007 0.6318 Oeuf_allongé
# 36: 0.2184878 0.6718 Oeuf_allongé
# 37: 0.4372139 0.5138 Oeuf_allongé
# 38: 0.3285164 0.4698 Oeuf_allongé
# 39: 0.3454093 0.4489 Oeuf_allongé
# 40: 0.9650048 0.2969 Oeuf_rond
# 41: 0.9501603 0.2906 Oeuf_rond
# 42: 0.3210640 0.4542 Oeuf_allongé
# 43: 0.3373548 0.4660 Oeuf_allongé
# 44: 0.9481635 0.2945 Oeuf_rond
# 45: 0.3487381 0.4240 Oeuf_allongé
# 46: 0.3274175 0.4471 Oeuf_allongé
# 47: 0.9386473 0.2843 Oeuf_rond
# 48: 0.3335866 0.4539 Oeuf_allongé
# 49: 0.2978034 0.4509 Oeuf_allongé
# 50: 0.3186029 0.4629 Oeuf_allongé
# 51: 0.3064432 0.4297 Oeuf_allongé
# 52: 0.3570850 0.5165 Oeuf_allongé
# 53: 0.3732885 0.5010 Oeuf_allongé
# 54: 0.9931990 11.6653 Oeuf_rond
# 55: 0.3602833 0.5199 Oeuf_allongé
# 56: 0.3109456 0.4948 Oeuf_allongé
# 57: 0.9650028 0.8609 Oeuf_rond
# 58: 0.3101570 0.4742 Oeuf_allongé
# 59: 0.2904637 0.5842 Oeuf_allongé
# 60: 0.9419192 0.3352 Oeuf_rond
# 61: 0.3225311 0.4734 Oeuf_allongé
# 62: 0.2820963 0.6477 Oeuf_allongé
# 63: 0.3399323 0.4711 Oeuf_allongé
# 64: 0.9704379 4.9321 Oeuf_rond
# 65: 0.3465926 0.4832 Oeuf_allongé
# 66: 0.3257476 0.4809 Oeuf_allongé
# 67: 0.3479142 0.4854 Oeuf_allongé
# 68: 0.3439809 0.4850 Oeuf_allongé
# 69: 0.9467196 0.3703 Oeuf_rond
# 70: 0.9729108 0.4680 Oeuf_rond
# 71: 0.9180085 0.2671 Oeuf_rond
# 72: 0.4510975 0.5440 Oeuf_allongé
# 73: 0.9315295 0.2688 Oeuf_rond
# 74: 0.4079905 0.5120 Oeuf_allongé
# 75: 0.8806804 0.4293 Oeuf_rond
# 76: 0.3537854 0.5395 Oeuf_allongé
# 77: 0.4033031 0.4645 Oeuf_allongé
# 78: 0.9218535 0.3096 Oeuf_rond
# 79: 0.9878641 0.2581 Oeuf_rond
# 80: 0.3447649 0.4725 Oeuf_allongé
# 81: 0.3925493 0.5204 Oeuf_allongé
# 82: 0.8531379 0.9116 Oeuf_rond
# 83: 0.4355121 0.4908 Oeuf_allongé
# 84: 0.3284783 0.4913 Oeuf_allongé
# 85: 0.3485931 0.5367 Oeuf_allongé
# 86: 0.9392282 0.3022 Oeuf_rond
# 87: 0.3728826 0.5213 Oeuf_allongé
# 88: 0.8876390 0.4463 Oeuf_rond
# 89: 0.9880823 0.4231 Oeuf_rond
# 90: 0.9248456 0.4208 Oeuf_rond
# 91: 0.9719091 0.8940 Oeuf_rond
# 92: 0.3775218 0.5510 Oeuf_allongé
# 93: 0.9441065 0.2744 Oeuf_rond
# 94: 0.3640709 0.5288 Oeuf_allongé
# 95: 0.3375137 0.5644 Oeuf_allongé
# 96: 0.3393921 0.4803 Oeuf_allongé
# 97: 0.3668896 0.4121 Oeuf_allongé
# 98: 0.9517998 0.4920 Oeuf_rond
# 99: 0.9663462 0.3155 Oeuf_rond
# aspect area class
En tidyverse, les deux opérations (filtrage des lignes et sélection des variables en colonnes) restent deux opérations successives distinctes dans le code. Notez au passage que nous repassons à l’opérateur de chaînage %>.%
de SciViews::R que nous avons l’habitude d’utiliser à la place de l’opérateur correspondant de tidyverse %>%
.
zoo %>.%
filter(., class == "Oeuf_allongé" | class == "Oeuf_rond") %>.%
dplyr::select(., aspect, area, class) ->
zoo2
zoo2
# aspect area class
# <num> <num> <fctr>
# 1: 0.9654882 0.3853 Oeuf_rond
# 2: 0.9762261 6.0352 Oeuf_rond
# 3: 0.9640408 0.2707 Oeuf_rond
# 4: 0.9113587 0.2588 Oeuf_rond
# 5: 0.9497946 0.3223 Oeuf_rond
# 6: 0.9590398 0.3346 Oeuf_rond
# 7: 0.9757848 0.3430 Oeuf_rond
# 8: 0.9751285 1.1143 Oeuf_rond
# 9: 0.4486249 0.4951 Oeuf_allongé
# 10: 0.9869350 2.0217 Oeuf_rond
# 11: 0.9753539 0.4795 Oeuf_rond
# 12: 0.9507730 0.4882 Oeuf_rond
# 13: 0.9271179 0.3496 Oeuf_rond
# 14: 0.8964930 0.3492 Oeuf_rond
# 15: 0.9565761 0.4798 Oeuf_rond
# 16: 0.4387639 0.5183 Oeuf_allongé
# 17: 0.9749170 0.5065 Oeuf_rond
# 18: 0.4279144 0.4805 Oeuf_allongé
# 19: 0.9198379 0.1425 Oeuf_rond
# 20: 0.8558559 0.5569 Oeuf_rond
# 21: 0.9369791 0.3442 Oeuf_rond
# 22: 0.9693467 1.8668 Oeuf_rond
# 23: 0.9854697 0.1953 Oeuf_rond
# 24: 0.9466777 0.5319 Oeuf_rond
# 25: 0.4257993 0.5288 Oeuf_allongé
# 26: 0.4899826 0.5072 Oeuf_allongé
# 27: 0.9394750 0.4545 Oeuf_rond
# 28: 0.9784003 0.6071 Oeuf_rond
# 29: 0.2777371 0.5857 Oeuf_allongé
# 30: 0.9545853 0.3516 Oeuf_rond
# 31: 0.3612644 0.6114 Oeuf_allongé
# 32: 0.2994636 0.5905 Oeuf_allongé
# 33: 0.3219424 0.6129 Oeuf_allongé
# 34: 0.9336704 0.3316 Oeuf_rond
# 35: 0.2627007 0.6318 Oeuf_allongé
# 36: 0.2184878 0.6718 Oeuf_allongé
# 37: 0.4372139 0.5138 Oeuf_allongé
# 38: 0.3285164 0.4698 Oeuf_allongé
# 39: 0.3454093 0.4489 Oeuf_allongé
# 40: 0.9650048 0.2969 Oeuf_rond
# 41: 0.9501603 0.2906 Oeuf_rond
# 42: 0.3210640 0.4542 Oeuf_allongé
# 43: 0.3373548 0.4660 Oeuf_allongé
# 44: 0.9481635 0.2945 Oeuf_rond
# 45: 0.3487381 0.4240 Oeuf_allongé
# 46: 0.3274175 0.4471 Oeuf_allongé
# 47: 0.9386473 0.2843 Oeuf_rond
# 48: 0.3335866 0.4539 Oeuf_allongé
# 49: 0.2978034 0.4509 Oeuf_allongé
# 50: 0.3186029 0.4629 Oeuf_allongé
# 51: 0.3064432 0.4297 Oeuf_allongé
# 52: 0.3570850 0.5165 Oeuf_allongé
# 53: 0.3732885 0.5010 Oeuf_allongé
# 54: 0.9931990 11.6653 Oeuf_rond
# 55: 0.3602833 0.5199 Oeuf_allongé
# 56: 0.3109456 0.4948 Oeuf_allongé
# 57: 0.9650028 0.8609 Oeuf_rond
# 58: 0.3101570 0.4742 Oeuf_allongé
# 59: 0.2904637 0.5842 Oeuf_allongé
# 60: 0.9419192 0.3352 Oeuf_rond
# 61: 0.3225311 0.4734 Oeuf_allongé
# 62: 0.2820963 0.6477 Oeuf_allongé
# 63: 0.3399323 0.4711 Oeuf_allongé
# 64: 0.9704379 4.9321 Oeuf_rond
# 65: 0.3465926 0.4832 Oeuf_allongé
# 66: 0.3257476 0.4809 Oeuf_allongé
# 67: 0.3479142 0.4854 Oeuf_allongé
# 68: 0.3439809 0.4850 Oeuf_allongé
# 69: 0.9467196 0.3703 Oeuf_rond
# 70: 0.9729108 0.4680 Oeuf_rond
# 71: 0.9180085 0.2671 Oeuf_rond
# 72: 0.4510975 0.5440 Oeuf_allongé
# 73: 0.9315295 0.2688 Oeuf_rond
# 74: 0.4079905 0.5120 Oeuf_allongé
# 75: 0.8806804 0.4293 Oeuf_rond
# 76: 0.3537854 0.5395 Oeuf_allongé
# 77: 0.4033031 0.4645 Oeuf_allongé
# 78: 0.9218535 0.3096 Oeuf_rond
# 79: 0.9878641 0.2581 Oeuf_rond
# 80: 0.3447649 0.4725 Oeuf_allongé
# 81: 0.3925493 0.5204 Oeuf_allongé
# 82: 0.8531379 0.9116 Oeuf_rond
# 83: 0.4355121 0.4908 Oeuf_allongé
# 84: 0.3284783 0.4913 Oeuf_allongé
# 85: 0.3485931 0.5367 Oeuf_allongé
# 86: 0.9392282 0.3022 Oeuf_rond
# 87: 0.3728826 0.5213 Oeuf_allongé
# 88: 0.8876390 0.4463 Oeuf_rond
# 89: 0.9880823 0.4231 Oeuf_rond
# 90: 0.9248456 0.4208 Oeuf_rond
# 91: 0.9719091 0.8940 Oeuf_rond
# 92: 0.3775218 0.5510 Oeuf_allongé
# 93: 0.9441065 0.2744 Oeuf_rond
# 94: 0.3640709 0.5288 Oeuf_allongé
# 95: 0.3375137 0.5644 Oeuf_allongé
# 96: 0.3393921 0.4803 Oeuf_allongé
# 97: 0.3668896 0.4121 Oeuf_allongé
# 98: 0.9517998 0.4920 Oeuf_rond
# 99: 0.9663462 0.3155 Oeuf_rond
# aspect area class
Notez que nous avons précisé ici dplyr::select()
pour éviter toute confusion avec une autre fonction, MASS::select()
qui réalise tout autre chose !
Le résultat est le même qu’avec le code R de base, mais la syntaxe est très différente. Notez que les variables dans la syntaxe de base sont complètement qualifiées (zoo$class
), ce qui nécessite de répéter plusieurs fois le nom du jeu de données zoo
(inconvénient), mais lève toute ambiguïté (avantage). La version de tidyverse est plus “propre” (avantage), mais cela implique d’utiliser une évaluation non standard de class
qui n’est pas une variable existante dans l’environnement où le code est évalué (inconvénient). La sélection des variables est également différente. Dans R de base, des chaînes de caractères doivent être compilées dans un vecteur d’indiçage à l’aide de c()
, alors que select()
de tidyverse permet de spécifier simplement les noms des variables sans autres fioritures (mais cela doit être évalué de manière non standard, encore une fois).
À vous de jouer !
Pour calculer une nouvelle variable, par exemple le logarithme en base 10 de l’aire dans log_area
, nous ferons comme ceci en R de base :
# aspect area class log_area
# <num> <num> <fctr> <num>
# 1: 0.9654882 0.3853 Oeuf_rond -0.4142010
# 2: 0.9762261 6.0352 Oeuf_rond 0.7806917
# 3: 0.9640408 0.2707 Oeuf_rond -0.5675117
# 4: 0.9113587 0.2588 Oeuf_rond -0.5870357
# 5: 0.9497946 0.3223 Oeuf_rond -0.4917397
# 6: 0.9590398 0.3346 Oeuf_rond -0.4754741
Avec tidyverse, nous savons déjà que mutate()
est le verbe à employer pour cette opération.
# aspect area class log_area
# <num> <num> <fctr> <num>
# 1: 0.9654882 0.3853 Oeuf_rond -0.4142010
# 2: 0.9762261 6.0352 Oeuf_rond 0.7806917
# 3: 0.9640408 0.2707 Oeuf_rond -0.5675117
# 4: 0.9113587 0.2588 Oeuf_rond -0.5870357
# 5: 0.9497946 0.3223 Oeuf_rond -0.4917397
# 6: 0.9590398 0.3346 Oeuf_rond -0.4754741
Vous pouvez aussi utiliser la fonction “speedy” smutate()
de SciViews::R bien sûr :
# aspect area class log_area
# <num> <num> <fctr> <num>
# 1: 0.9654882 0.3853 Oeuf_rond -0.4142010
# 2: 0.9762261 6.0352 Oeuf_rond 0.7806917
# 3: 0.9640408 0.2707 Oeuf_rond -0.5675117
# 4: 0.9113587 0.2588 Oeuf_rond -0.5870357
# 5: 0.9497946 0.3223 Oeuf_rond -0.4917397
# 6: 0.9590398 0.3346 Oeuf_rond -0.4754741
En résumé, la syntaxe de tidyverse se lit mieux et est plus propre (avantage), mais elle nécessite pour y arriver une évaluation non standard de area
, ce qui est un inconvénient par rapport à la syntaxe R de base.
Pour finir, revenons sur les différents moteurs graphiques pour faire un nuage de points en utilisant différents styles. Une petite précaution supplémentaire est nécessaire. Pour class
, nous devons préalablement laisser tomber les niveaux non utilisés à l’aide de droplevels()
.
# [1] "Annélide" "Appendiculaire" "Calanoïde"
# [4] "Chaetognathe" "Cirripède" "Cladocère"
# [7] "Cnidaire" "Cyclopoïde" "Décapode"
# [10] "Oeuf_allongé" "Oeuf_rond" "Poisson"
# [13] "Gastéropode" "Harpacticoïde" "Malacostracé"
# [16] "Poecilostomatoïde" "Protiste"
# Ne retenir que les niveaux relatifs aux œufs
zoo2$class <- droplevels(zoo2$class)
# C'est mieux
levels(zoo2$class)
# [1] "Oeuf_allongé" "Oeuf_rond"
Voici un graphe de base… avec également la syntaxe de base :
plot(zoo2$log_area, zoo2$aspect, col = zoo2$class)
legend("bottomright", legend = c("Oeuf allongé", "Oeuf rond"), col = 1:2, pch = 1)
Le même graphique, mais en utilisant l’interface formule alternative avec plot()
:
plot(data = zoo2, aspect ~ log_area, col = class)
legend("bottomright", legend = c("Oeuf allongé", "Oeuf rond"), col = 1:2, pch = 1)
L’interface formule est également employée avec le moteur {lattice} via la fonction xyplot()
. Ici, nous utilisons la version chart()
en appelant chart$xyplot()
.
Dans tidyverse, c’est le moteur graphique {ggplot2} qui est utilisé, avec sa syntaxe propre :
Dans SciViews::R, chart()
utilise aussi par défaut le moteur graphique {ggplot2}, mais il est plus flexible et permet soit d’utiliser aes()
comme ggplot()
, soit une interface formule élargie (c’est-à-dire qu’il est possible d’y inclure d’autres “aesthetics” à l’aide des opérateurs %aes=%
) :
# chart() avec une formule élargie
chart(data = zoo2, aspect ~ log_area %col=% class) +
geom_point()
Il y aurait encore beaucoup à dire sur les différents styles de syntaxe dans R, mais nous venons de discuter les éléments essentiels. SciViews::R propose d’utiliser un ensemble cohérent d’instructions qui est soigneusement choisi pour rendre l’utilisation de R plus facile (sur base de nos observations des difficultés et erreurs d’apprentissage principales). Il se base sur tidyverse avec une pincée de R de base et une bonne dose de formules là où elles se montrent utiles. Des fonctions et des opérateurs originaux sont ajoutés dans le but d’homogénéiser et/ou clarifier la syntaxe.
De votre côté, vous êtes libre d’utiliser le style que vous préférez. si la curiosité vous pousse à essayer autre chose et à adopter un autre style que SciViews::R, nous en serons ravis. R est ouvert, il offre beaucoup et c’est à vous maintenant de créer votre propre boite à outils taillée réellement à votre mesure !
Pour finir, il parait que les Belges sont forts en autodérision. La caricature suivante devrait vous faire sourire :
À vous de jouer !
Effectuez maintenant les exercices du tutoriel A10Lc_syntaxr (Syntaxes dans R).
BioDataScience1::run("A10Lc_syntaxr")
Pour en savoir plus
Swirl vous permet d’apprendre la syntaxe de base de R de manière conviviale et interactive. Le site R maintient une page de documents et tutoriels ici (descendez jusqu’à la section concernant les documents en français si vous préférez travailler dans cette langue). Enfin, les manuels de R sont un peu techniques, mais ils décrivent dans le détail la syntaxe de base.
Mosaic est une initiative américaine qui vise en partie un objectif assez similaire à celui de SciViews::R : homogénéiser l’interface de R et en faciliter l’apprentissage. A student’s guide to R est un ouvrage en ligne qui vous apprendra à utiliser R selon le style mosaic qui fait la part belle à l’interface formule.
La littérature concernant le tidyverse est abondante. Commencez par le site web qui pointe également vers R for Data Science, ou mieux, voyez la seconde édition, que nous conseillons comme première source pour apprendre R à la sauce tidyverse (une version en français au format papier est également disponible). Voyez ensuite la page “learn the tidyverse” pour divers ouvrages et autres matériels d’apprentissage.
À vous de jouer !
Réalisez en groupe le travail A07Ga_human_health, partie IV.
Travail en groupe de 4 pour les étudiants inscrits au cours de Science des Données Biologiques I : inférence à l’UMONS à terminer avant le 2025-05-19 23:59:59.
Initiez votre projet GitHub Classroom
Voyez les explications dans le fichier README.md
, partie IV.
Historiquement, ce langage s’appelait S à l’origine dans les années 1970 alors qu’il a été inventé par John Chambers et ses collègues aux laboratoires Bell. R est une implémentation open source de S écrite dans les années 1990 par Ross Ihaka et Robert Gentleman. Ensuite R a pris de l’importance à tel point qu’on parle maintenant du langage R (sachant bien qu’il s’agit d’un dialecte du langage S).↩︎
Cette évaluation particulière s’appelle le “tidyeval”. Son explication est hors de propos dans cette introduction à la science des données, mais si vous êtes curieux, vous pouvez toujours lire ceci.↩︎