Cours
Dans ce tutoriel, vous allez découvrir plusieurs fonctions et utilitaires simples et fréquemment utilisés dans le langage R. Vous verrez d’abord quelques fonctions mathématiques, puis des fonctions liées aux structures de données de R : manipulation de listes imbriquées, expressions régulières, gestion du temps et des dates.
Fonctions mathématiques
Observons les extraits de code suivants qui utilisent plusieurs fonctions mathématiques.
Vous allez d’abord définir deux vecteurs, x et y, qui contiennent des valeurs positives et négatives.
x <- c(1.1, -2.3, -4.5)
y <- c(2.4,-44, -2.2)
print(x)
[1] 1.1 -2.3 -4.5
print(y)
[1] 2.4 -44.0 -2.2
À partir de ces deux vecteurs x et y :
- prenez la valeur absolue de leurs éléments,
- arrondissez-les à zéro décimale,
- faites la somme de chacun, puis
- calculez enfin la moyenne des deux sommes.
mean(c(sum(round(abs(x))),sum(round(abs(y)))))
27.5
Décomposons maintenant cette ligne de code en petites étapes et regardons de près chaque fonction.
- La fonction
abs()renvoie la valeur absolue (positive) des éléments des vecteursxety.
Par exemple, en appliquant abs() à x et y, vous obtenez uniquement des valeurs positives, comme ci-dessous.
abs(x)
- 1.1
- 2.3
- 4.5
abs(y)
- 2.4
- 44
- 2.2
- Vient ensuite
round(), qui arrondit l’entrée. Elle accepte un argument supplémentaire pour préciser le nombre de décimales souhaité. Par défaut,round()arrondit à l’entier le plus proche (zéro décimale).
Par exemple, après application de round() aux vecteurs x et y, la sortie ressemble à ceci :
round(x)
- 1
- -2
- -4
round(y)
- 2
- -44
- -2
- La fonction
sum()calcule simplement la somme des éléments d’un vecteur ou d’une matrice. Si vous lui passez un vecteur ligne, elle renvoie un scalaire égal à la somme des éléments.
Ici, les vecteurs x et y sont passés à sum(). R calcule donc la somme des éléments et renvoie un scalaire.
sum(abs(round(x)))
7
sum(abs(round(y)))
48
- Enfin,
mean()(la moyenne) calcule la moyenne arithmétique : elle additionne un ensemble de valeurs numériques puis divise par le nombre de termes.
Ici, l’entrée de mean() est un vecteur de longueur 2 contenant 7 et 48. La moyenne est donc la somme de ces valeurs divisée par le nombre d’éléments, soit 2.
mean(c(7,48))
27.5
Plutôt simple, n’est-ce pas ?
Passons maintenant à la partie suivante, la plus intéressante de ce tutoriel !
Fonctions pour les structures de données
Voyons quelques structures de données comme les listes et les vecteurs : différentes manières d’opérer sur une list, inverser une list, et convertir une liste en vecteur (et inversement).
La fonction ci-dessous crée une list(), autrement dit une liste de listes (liste imbriquée). Elle agrège des éléments pouvant être logiques, numériques ou textuels.
Dans l’exemple ci-dessous, on trouve trois listes au sein d’une liste : log, ch et int_vec. Chacune correspond respectivement à des objets logiques, numériques et textuels (caractères).
list_define <- list(log = TRUE, ch = "hello_datacamp", int_vec = sort(rep(seq(8,2, by = -2), times = 2)))
list_define
- $log
- TRUE
- $ch
- 'hello_datacamp'
- $int_vec
-
- 2
- 2
- 4
- 4
- 6
- 6
- 8
- 8
logest un booléen, TRUE ou FALSEchest une chaîne de caractèreshello_datacampint_vecest une suite de valeurs numériques.
Comme log et ch sont explicites, regardons de plus près int_vec.
int_vec = sort(rep(seq(8,2, by = -2), times = 2))
int_vec
- 2
- 2
- 4
- 4
- 6
- 6
- 8
- 8
Décomposons cette expression étape par étape.
La fonction seq produit une séquence de nombres en ordre décroissant allant de 8 à 2.
La syntaxe de seq() est : seq(x1, x2, by = y)
Les deux premiers arguments x1 et x2 définissent l’intervalle de la séquence (début et fin). L’argument by précise l’incrément (ou décrément) à chaque pas.
Par exemple, la ligne suivante génère une séquence de 100 à 200 avec un pas de 20.
seq(100,200, by = 20)
- 100
- 120
- 140
- 160
- 180
- 200
Dans notre exemple, la fonction seq renvoie une séquence de 8 à 2 (inclus) avec un pas de -2, soit un vecteur de longueur 4.
a = seq(8,2, by = -2)
a
- 8
- 6
- 4
- 2
Passons à la fonction rep.
Elle répète l’argument d’entrée (souvent un vecteur ou une liste) via l’argument times, qui prend un entier et répète l’entrée autant de fois. rep prend donc deux arguments : l’entrée et le nombre de répétitions souhaité.
Appliquée à notre exemple (un vecteur de longueur 4), elle produit un vecteur de longueur 8.
b = rep(a, times = 2)
Si vous souhaitez répéter chaque élément du vecteur plutôt que le vecteur complet, utilisez l’argument each au lieu de times.
La différence entre times et each tient au motif de répétition de chaque élément.
rep(a, each = 2)
- 8
- 8
- 6
- 6
- 4
- 4
- 2
- 2
Dernière étape : sort(). C’est une fonction générique et explicite qui trie de nombreuses structures (vecteur, liste…), non seulement numériques, mais aussi logiques ou textuelles. Par défaut, l’ordre est croissant.
Appliquons sort au résultat de rep pour obtenir la sortie finale.
sort(b)
- 2
- 2
- 4
- 4
- 6
- 6
- 8
- 8
Parfait ! Vous avez ainsi décrypté l’expression int_vec présente dans la liste list_define, très simplement.
Poursuivons en inspectant le contenu de list_define avec str(). Cette fonction affiche la structure des objets R.
str(list_define)
List of 3
$ log : logi TRUE
$ ch : chr "hello_datacamp"
$ int_vec: num [1:8] 2 2 4 4 6 6 8 8
Quelques expressions R pratiques :
- Les fonctions
ispermettent de vérifier le type d’une structure de données ; elles renvoient un booléen, très utile dans des conditions.
is.list(list_define) #renvoie TRUE si l’argument est une liste.
TRUE
À l’inverse, elle renvoie FALSE si vous passez un vecteur simple, comme ci-dessous.
is.list(c(1,2,3)) #renvoie FALSE car vous avez passé un vecteur.
FALSE
- Convertir un vecteur en liste est très simple en R : utilisez
assuivi de.list()et passez le vecteur en argument. Et voilà, votre vecteur devient une liste.
vec_to_list <- as.list(c(1,2,3))
is.list(vec_to_list) #vérifiez avec is.list()
TRUE
- À l’inverse,
unlist« aplatit » une liste pour en faire un vecteur unique.
list_to_vec <- unlist(vec_to_list)
list_to_vec
- 1
- 2
- 3
Comme is.list(), vous pouvez utiliser is.vector() pour vérifier si l’argument est un vecteur.
is.vector(list_to_vec)
TRUE
Convertissons la grande liste list_define en vecteur. Notez qu’un vecteur ne peut contenir qu’un seul type de données : les valeurs logiques et numériques seront donc converties en chaînes de caractères.
unlist(list_define)
- log
- 'TRUE'
- ch
- 'hello_datacamp'
- int_vec1
- '2'
- int_vec2
- '2'
- int_vec3
- '4'
- int_vec4
- '4'
- int_vec5
- '6'
- int_vec6
- '6'
- int_vec7
- '8'
- int_vec8
- '8'
Avant de passer au sujet suivant, voyons append() et rev().
- Comme son nom l’indique,
append()permet d’ajouter (concaténer) un ou plusieurs vecteurs ou listes à un vecteur ou une liste existants (ou vers un nouvel objet).
Essayons append() sur list_define. Vous verrez que la liste comporte désormais 6 éléments au lieu de 3, puisque vous l’avez concaténée avec elle-même.
str(append(list_define, list_define))
List of 6
$ log : logi TRUE
$ ch : chr "hello_datacamp"
$ int_vec: num [1:8] 2 2 4 4 6 6 8 8
$ log : logi TRUE
$ ch : chr "hello_datacamp"
$ int_vec: num [1:8] 2 2 4 4 6 6 8 8
- Enfin, inversez l’ordre des éléments de
list_defineavecrev().
str(rev(list_define))
List of 3
$ int_vec: num [1:8] 2 2 4 4 6 6 8 8
$ ch : chr "hello_datacamp"
$ log : logi TRUE
Expressions régulières
Beaucoup trouvent les expressions régulières complexes, mais elles sont essentielles, en R comme dans d’autres langages (par exemple Python). Nombre de langages, dont R, intègrent nativement des capacités regex.
Les expressions régulières sont utiles dans de nombreuses applications, notamment pour le prétraitement de texte, et dans divers problèmes de traitement du langage naturel (NLP).
Elles sont également utilisées dans les moteurs de recherche et les éditeurs de texte.
Les expressions régulières (ou regex / regexp) sont des séquences de caractères qui définissent un motif de recherche. Ces motifs servent aux algorithmes de recherche dans les chaînes pour trouver un motif, le remplacer, ou filtrer les correspondances.
Commençons par grep() et grepl().
Pour simplifier, définissons un vecteur ligne animals_regex de longueur 5 sur lequel appliquer des motifs regex.
animals_regex <- c('cat','dog','cheetah','lion','mice')
Commençons par grepl(). Cette fonction renvoie un booléen : TRUE si la chaîne correspond au motif, FALSE sinon.
La syntaxe de grepl() est intuitive : premier argument, le motif à rechercher ; second argument, la chaîne (ou vecteur de chaînes) dans laquelle chercher. Vous pouvez ignorer les autres arguments pour l’instant. grepl(pattern, x, ignore.case = FALSE, perl = FALSE, fixed = FALSE, useBytes = FALSE) Cherchons quels animaux parmi les cinq contiennent la lettre c avec grepl().
Ici, vous cherchez les animaux qui contiennent c : le motif est donc simplement c.
grepl(pattern = 'c', x = animals_regex)
- TRUE
- FALSE
- TRUE
- FALSE
- TRUE
On observe que c apparaît dans cat, cheetah et mice : ces positions renvoient TRUE dans le vecteur animals_regex, les autres FALSE.
Trouvons maintenant les éléments qui commencent par c, et pas seulement qui contiennent la lettre.
Pour cela, placez un accent circonflexe ^ au début du motif recherché.
grepl(pattern = '^c', x = animals_regex) #seuls cat et cheetah commencent par `c`.
- TRUE
- FALSE
- TRUE
- FALSE
- FALSE
Seuls cat et cheetah commençant par c, seules ces positions renvoient TRUE.
De la même façon, le signe $ en fin de motif permet de faire correspondre les éléments qui se terminent par le motif. Pour trouver un animal qui finit par n, utilisez n suivi de $.
grepl(pattern = 'n$', x = animals_regex) #seul lion se termine par `n`.
- FALSE
- FALSE
- FALSE
- TRUE
- FALSE
Remarque : pour en savoir plus sur les expressions régulières, tapez ?regex dans une cellule Jupyter pour afficher la documentation. Vous pouvez aussi consulter cette ressource, qui propose un outil pour concevoir et tester vos motifs sur vos chaînes d’entrée.
- À l’instar de
grepl(),grep()renvoie, non pas un booléen, mais l’indice des éléments du vecteur/matrice correspondant au motif.
La syntaxe de grep() est identique à celle de grepl() : grep(pattern, x, ignore.case = FALSE, perl = FALSE, value = FALSE, fixed = FALSE, useBytes = FALSE, invert = FALSE). Reprenons l’exemple ci-dessus, mais en appliquant cette fois grep() !
grep(pattern = 'c', x = animals_regex)
- 1
- 3
- 5
Comme prévu, la sortie renvoie les indices de cat, cheetah et mice, et non des TRUE/FALSE. Voilà pour l’essentiel !
Utilisons which pour comparer grep() et grepl(). which() renvoie les indices des éléments TRUE d’un vecteur logique.
Si vous faites le lien, grepl() renvoyant un vecteur logique, il suffit de le passer à which() pour obtenir un résultat équivalent à grep().
which(grepl(pattern = 'c', x = animals_regex))
- 1
- 3
- 5
Comme grepl(), grep() gère différents motifs regex.
Si vous cherchez avec grep() les éléments de animals_regex qui se terminent par n, vous obtenez 4, car seul lion se termine par n, comme ci-dessous.
grep(pattern = 'n$', x = animals_regex)
4
Bien joué !
Vous avez vu les bases des expressions régulières pour filtrer des éléments d’un vecteur qui correspondent à un motif. Mais R ne s’arrête pas au filtrage. Il propose de nombreuses fonctions, dont sub().
sub() ne filtre pas : elle remplace les correspondances par d’autres chaînes. Voyons cela de plus près.
- La fonction
sub()prend principalement trois arguments :- pattern : le motif ou l’expression régulière à faire correspondre,
- replacement : la valeur de remplacement à insérer aux positions correspondantes,
- x : le vecteur de chaînes sur lequel appliquer la regex.
La syntaxe est : sub(pattern, replacement, x, ignore.case = FALSE, perl = FALSE, fixed = FALSE, useBytes = FALSE). Reprenons encore l’exemple ci-dessus pour comprendre son fonctionnement.
sub(pattern = 'c', replacement = 'a', x = animals_regex)
- 'aat'
- 'dog'
- 'aheetah'
- 'lion'
- 'miae'
Ici, cat devient aat, cheetah devient aheetah et mice devient miae : le motif a été trouvé et remplacé.
Notez aussi que sub() ne remplace que la première occurrence dans chaque chaîne : s’il y a deux c, seule la première est remplacée par a, la seconde reste inchangée.
Si vous souhaitez remplacer toutes les occurrences d’un motif dans chaque chaîne, utilisez plutôt gsub() (hors du périmètre de ce tutoriel).
Avant de passer à la suite, tentons une dernière expression.
Cette fois, utilisez l’opérateur | (ou) pour tenter de faire correspondre l’un des motifs définis et, en cas de correspondance, le remplacer par -. Comme vous utilisez gsub(), chaque occurrence du motif sera remplacée.
gsub(pattern = 'c|d|l', replacement = '-', x = animals_regex) #les lettres `c`,`d`,`l` sont remplacées par `-`.
- '-at'
- '-og'
- '-heetah'
- '-ion'
- 'mi-e'
Passons au dernier thème du jour : le temps et les dates !
Temps et dates
Les informations de date et d’heure sont utiles dans de nombreux scénarios. Par exemple, pour un problème de vision par ordinateur, vous pouvez vouloir mesurer les FPS (images par seconde) de votre algorithme. Dans ce cas, les objets de temps aident à estimer la vitesse de traitement. Pour des problématiques comme la prévision de séries temporelles et l’étude de la saisonnalité, le potentiel de R est particulièrement intéressant.
Pour commencer, affichons rapidement la date du jour en R via Sys.Date(). Ici, Sys renvoie l’approximation système de la date.
Sys.Date()
Simple, n’est-ce pas ?
Le temps et les dates en R relèvent de l’objet Date (le type est Date). Vous pouvez le vérifier avec la fonction class vue dans le tutoriel Data Types in R.
À l’image de la date, Sys.time() renvoie l’heure système courante, avec la date.
Sys.time()
[1] "2020-02-04 02:05:04 IST"
Créer des objets Date
Vous savez obtenir la date et l’heure courantes. Voyons comment créer d’autres dates en passant une simple chaîne en argument.
Pour créer un objet date pour le 10 mai 1993, utilisez la syntaxe suivante :
date_may <- as.Date('1993-05-10') #convertit une chaîne de caractères en objet Date
date_may
class(date_may)
'Date'
Important : par défaut, as.Date attend le format YYYY-MM-DD. Si vous intervertissez année, mois ou jour, vous obtiendrez une erreur. Essayons :
date_may <- as.Date('05-1993-10') #R suit par défaut le format ISO
Error in charToDate(x): character string is not in a standard unambiguous format
Traceback:
1. as.Date("05-1993-10")
2. as.Date.character("05-1993-10")
3. charToDate(x)
4. stop("character string is not in a standard unambiguous format")
Bonne nouvelle : vous pouvez préciser explicitement le format via l’argument format et l’adapter.
date_may <- as.Date('05-1993-10', format = '%m-%Y-%d')
as.Date() accepte différents formats en entrée, mais convertit toujours en sortie au format ISO. Vérifiez en affichant date_may.
date_may
date_may <- as.Date('05-10-1993', format = '%m-%d-%Y')
date_may
Calculs sur les dates
Serait-il possible d’appliquer des opérations comme l’addition et la soustraction aux objets Date en R ?
Ajoutons 1 à la variable date_may : vous verrez qu’elle affiche la date du lendemain.
date_may + 1
Comme on le voit ci-dessus, ajouter 1 fait passer du 10 au 11 mai 1993. De même, vous pouvez soustraire 1.
Supposons que vous vouliez calculer l’écart entre votre date de naissance et celle de votre aîné(e).
elder_sib <- as.Date('1989-03-21')
date_may - elder_sib
Time difference of 1511 days
Conclusion
Félicitations pour avoir mené ce tutoriel à bien.
Ce tutoriel constitue un excellent point de départ pour les débutants souhaitant découvrir différentes fonctions utilitaires en R. Pour aller plus loin, nous vous recommandons d’approfondir les expressions régulières, très utilisées et particulièrement puissantes pour nettoyer ou prétraiter des données textuelles.
N’hésitez pas à poser vos questions sur ce tutoriel dans les commentaires ci-dessous.
Pour en savoir plus sur R, suivez le cours Intermediate R de DataCamp et consultez notre tutoriel Using Functions in R.