R, l'application universelle de statistiques
LE logiciel R est un logiciel libre d'analyse statistique de données, qui contient énormément d'extensions (bibliothèques) à des fins très diverses. Cette page est écrite en vue de faciliter la prise en main pour une personne n'ayant aucune connaissance de programmation. En cas de besoin urgent de fréquences et de tableaux croisés à partir d'une table de données existante, voyez plutôt le logiciel libre PSPP, après un éventuel détour par le chapitre Importation et exportation des données, que PSPP gère moins bien.
Page commencée en août 2018 – ajouts sporadiques.
0. Prise en main
0.1 En mode console
0.2 Interface graphique
1. Syntaxe et structures
1.1 Syntaxe
1.2 Booléens et opérateurs logiques
1.3 Conditions if et switch
1.4 Boucles while, repeat et for
1.5 Fonctions-utilisateurs
2. Variables, types et opérateurs
2.1 Nombres
2.2 Chaînes
2.3 Expressions régulières (regex)
2.4 Listes
3. Vecteurs et distributions
3.1 Vecteurs
3.2 Génération de vecteurs
3.3 Modification de vecteurs
3.4 Facteurs
3.5 Distributions
4. Matrices
5. Tables de données
6. Entrées et sorties
6.1 Clavier et console
6.2 Fichiers de simple texte
6.3 Tables textes (csv et tsv)
6.4 Tables binaires (rds et rda)
6.5 Importation et exportation
7. Divers
7.1 système de fichiers
8. Sortie graphique
8.1 plot()
8.2 ggplot() + geom_…()
9. Bibliothèques
0. Prise en main
Pour disposer de R sur un système UNIX, il faut installer le paquet r-base, qui installera les paquets complémentaires. Sur GNU/Linux Debian10-Buster, 76 nouveaux paquets, 107Mo téléchargés et 321 installés.
Sur un système Unix, de la documentation (en anglais) est disponible en Unix, sept fichiers HTML (totalisant 3Mo) sont installés à l'adresse /usr/share/doc/r-doc-html/manual/ et /usr/share/R/doc/manual.
0.1 En mode console
En Unix, le mode interactif de R est lancé par la commande R (nécessairement en majuscule) dans une console. On en sort avec la commande q()
help.start() affiche dans un navigateur le fichier R-intro.html du répertoire /usr/share/R/doc/manual.
En mode interactif, l'invite > apparaît, écrire et saisir avec [Enter] inscrit une réponse sur la ou les ligne(s) suivante(s), ou un message d'erreur :
>
2+2 ; 2+"2" [1] 4 Error in "2" + 2 : argument non numérique pour un opérateur binaire
…ce qui signifie qu'il est interdit d'additionner le caractère "2" à la valeur numérique 2.
Le mode console peut être utile pour tester une fonction, effectuer un calcul ou réaliser une tâche simple (importation d'un fichier pour l'exporter dans une autre format), mais est peu pratique pour des tâches complexes ou répétitives.
On quitte le mode interactif avec quit()
L'autre façon d'utiliser R est d'éditer un fichier de commandes (un script) dans un éditeur de fichier (notepad++, atom, gedit, kedit, kwrite, pluma…) et le lancer dans une console. Il faut veiller à ce que le script soit lancé à son adresse réelle : en UNIX, si le script essai.r est sauvegardé à l'adresse /home/toto/R/script/, il sera lancé dans une console par :
$ Rscript /home/toto/R/script/essai.r
Il faut évidemment que les éventuels fichiers de données appelés par le script et que toutes les bibliothèques nécessaires soient présentes sur le système et correctement libellés.
Pour automatiser le lancement en Unix et dérivés (double clic sur fichier, ./monfichier.R ou chemin/monfichier hors du répertoire), indiquer #! /usr/bin/Rscript sur la premier ligne de monfichier.R (ou toute autre adresse où se trouve Rscript, chercher avec whereis Rscript dans une console):
#! /usr/bin/Rscript exp(3)
En mode console, le résultat sera [1] 20.08554
Les éventuels arguments passés par ./Rscript.R 3 seront récupérés sous forme d'un vecteur de chaînes de caractères par commandArgs(TRUE), nécessitant éventuellement as.numeric() pour les transformer en nombres :
#! /usr/bin/Rscript arguments <- commandArgs(TRUE) exp(as.numeric(arguments[1])) # 1 désigne le premier ou l'unique argument
0.2 Interface graphique
Plusieurs interfaces graphiques existent en UNIX, Windows ou Mac, comme Rcmdr (paquet r-cran-cmdr dans la distribution GNU/Linux Debian). Pour débuter, Rcmdr semble plus simple. Sur GNU/Linux Debian10-Buster, 168 nouveaux paquets, 119Mo téléchargés et 350 installés.
Pour la première fois, il est peut-être nécessaire de lancer R dans une console en mode super-utilisateur :
#REn mode superutilisateur :
su + mot de passe
Une fois dans R, frapper la commande suivante et [Enter] :
>
library(Rcmdr)
Les bibliothèques (library) dont Rcmdr a besoin seront demandées. Soit vous en disposez dans un répertoire particulier, auquel cas vous pouvez fournir le nom du répertoire dans une boîte de dialogue, soit elles seront téléchargées et installées avec les droits de superutilisateur.
Une dépendance, gdl, refuse d'être installée (configure: error: missing required header GL/gl.h, problème récurrent en Debian 9 et 10). L'installation sur le système des paquets r-cran-rgl et libglu1-mesa-dev devrait résoudre le problème.
Rcmdr présente deux fenêtres : celle du haut permet la saisie de commande ou de calcul (Rscript), le bouton Soumettre interprète la ligne où se trouve le curseur ou la partie surlignée à la souris et en donne la solution dans la fenêtre du bas. Un fichier Rmarkdown est généré, visualisable dans la fenêtre du haut.
Par défaut, seuls les données sous la forme Rdata, rda… Pour d'autres formats de fichiers, il faut passer par une importation, voir la bibliothèque foreign.
Il y a aussi Rstudio (Affero GPL, entre 120 et 150Mo selon la distribution GNU/Linux).
1. Structures
1.1 Syntaxe
Tout langage a ses règles. Voici les principales du langage R.
> représente l'invite (prompt, attente de commande) de R dans une console ou dans la fenêtre interactive de Rstudio. Il est représenté en bleu dans les exemples ; vous ne devez jamais saisir ce signe vous-même dans une console ni les utiliser dans les scripts.
# permet un commentaire : tout ce qui se trouve à droite du croisillon (hashtag) ne sera pas pris en compte par R dans sa lecture du script.
- «Commenter» une ligne, placer un croisillon à son début, permet de rendre (momentanément) une commande inopérante, plutôt que de l'effacer et d'éventuellement avoir à la réécrire par la suite
- «Décommenter» une ligne signifie enlever le croisillon écrit à son début et donc rendre opérantes les commandes qu'elle contient. Il s'agit souvent d'une option laissée par l'auteur d'un script à son utilisateur
Est une expression numérique tout agrégat de chiffres, éventuellement précédé du signe - et pouvant contenir un signe . avant son éventuelle partie décimale, un e ou E avant un éventuel ordre de grandeur (exposant de 10), et i comme suffixe de la partie imaginaire ; ou toute expression algébrique valable ou résultat valide d'une fonction arithmétique. Exemples : -443, 2 +5 *(3 -2), 9 ^3, sqrt (43), 3.14, 7.8e9 (7 800 000 000), 7 -i5
Est une chaîne tout agrégat de caractères (chiffres ou non) entourés de guillemets "doubles" ou 'simples', ou résultat valide d'une fonction retournant des chaînes de caractères.
- exemple : "mot", 'autre', "ensemble de mots, voire un texte", toString(12)
- les guillemets doubles permettent l'inclusion de guillemets simples : "L'informatique" et les guillemets simples les guillemets doubles : 'la "chaîne"'. Une autre possibilité est d'«échapper» (protéger) un guillemet double avec une barre inverse (antislash) :
cat(c("Une \"chaîne\" comprenant des guillemets doubles", "\n"))
Est une variable tout agrégat de lettres, de chiffres et soulignés _ mais commençant toujours par une lettre, ou une fonction si l'agrégat est suivi de parenthèses. Contrairement aux autres langages de programmation, le signe préconisé pour affecter une valeur à une variable ou du code à une fonction est <- (le signe = fonctionne également, mais est déconseillé).
- les variables servent à stocker un contenu, qui peut être un nombre, une chaîne de caractères, une liste, un vecteur, une matrice, une table de données…
- go, go90, g9o_0 sont des exemples de variables
- certaines variables, comme pi, existent déjà dans R, mais peuvent être redéfinies : pi ; pi <- 3.14 ; pi
- 3.14 -> var est également valable, la flèche doit être orientée vers la variable
- les fonctions peuvent être définies par l'utilisateur. Ces appels de fonction contiennent le plus souvent un ou plusieurs paramètres entre les parenthèses, séparés par des virgules.
- go(), go90 (), g9o_0() sont des exemples de fonctions
- une fonction de R peut être réécrite : sqrt(4) ; sqrt <- function(x) { c(x**.5, -x**.5) } ; sqrt(4)
Note :
- go, Go, GO et gO sont des variables différentes, et go(), Go(), GO() et gO() des fonctions différentes.
- Il est permis d'utiliser des lettres accentuées, d'autres alphabets, katakanas, idéogrammes… mais cela rend le script moins partageable
- R accepte pour ses noms de variable n'importe quels caractères entourés de `guillemets inversés` : `(8:)`, `+-*/`, `☮`, `{_}`()…
, la virgule sépare les paramètres dans les fonctions et les données dans les variables composées.
; sépare opérations ou commandes sur une même ligne.
( ) les parenthèses sont utilisées dans les expressions algébriques, elle contiennent également les paramètres des fonctions écrites par l'utilisateur, des conditions et boucles. Les paramètres nommés utilisent le signe = comme dans l'expression sep="-" de l'exemple cat(c("a", "b"), sep="-").
[ ] les crochets contiennent le rang d'une valeur d'un vecteur ou la ligne, la rangée ou la cellule d'une matrice ou d'une table de données.
{ } les accolades contiennent le code des structures : les fonctions écrites par l'utilisateur, les boucles et conditions.
1.2 Booléens et opérateurs logiques
L'algèbre booléenne étant essentiellement utile pour les conditions et les boucles, elle est présentée avant celles-ci.
TRUE (ou T) et FALSE (ou F) sont les valeurs «booléennes» VRAI et FAUX. class=() et is() permettent de s'assurer qu'une expression est booléenne :
>
boo <- 5 !=4 ; class(boo) ; is(boo) [1] "logical" [1] "logical" "vector"
Tout nombre non nul est vrai, et 0 est faux, mais une chaîne vide ou non ne peut servir de booléen comme c'est souvent le cas dans d'autres langages.
Ces valeurs sont générées par les opérateurs suivants (x et y représentent des nombres ou des chaînes) :
x == y retourne TRUE si x et y sont égaux ; FALSE sinon
x != y retourne TRUE si x et y sont différents ; FALSE sinon
x < y retourne TRUE si x est strictement inférieur à y ; FALSE sinon
x > y retourne TRUE si x est strictement supérieur à y ; FALSE sinon
x <= y retourne TRUE si x est inférieur ou égal à y ; FALSE sinon
x >= y retourne TRUE si x est supérieur ou égal à y ; FALSE sinon
x %in% y retourne TRUE si la chaîne ou le nombre x est un élément du vecteur y ; FALSE sinon
Notes :
- ne pas confondre %in% avec in de la boucle for.
- %in% ne permet pas de tester la présence d'une portion de chaîne dans une autre, voir plutôt strstrip().
x & y ou x && y : «ET logique» : retourne TRUE si x et y sont tous les deux vrais ; FALSE sinon
x | y ou x || y : «OU logique» : retourne TRUE si au moins l'un des deux de x ou y sont vrais ; FALSE sinon
xor(x, y) : «OU exclusif» un seul TRUE donne TRUE ; deux TRUE ou deux FALSE donnent FALSE
! x inversion logique : ! T est FALSE et ! F est TRUE
Ces opérateurs permettent des compositions, parfois avec des parenthèses :
3 == 3 | 2 > 3 # TRUE ou FALSE : vrai ! (3 == 3 | 2 > 3) # l'inverse de TRUE ou FALSE : faux
1.3 Conditions if et switch
Les conditions et les boucles sont des structures qui permettent d'exécuter un code ou des portions de code selon l'évaluation d'une expression logique (une condition). Les conditions sont écrites (entre parenthèses) après le mot-clé de la structure (if, while, for…), le code est écrit { entre accolades }.
Condition if
La première structure est la condition. Seul le if (condition) { code } est indispensable. L'éventuel else if (condition) { code } est une condition alternative (il peut y en avoir plusieurs) qui ne sera testée que si celle du if n'a pas été rencontrée. L'éventuel else { code } (sans condition) vaut pour tous les autres cas, c'est-à-dire si aucune des conditions de if ou else if n'est remplie.
n <- 3 if (n < 5) { print("moins que 5") } else if (n > 7) { print("plus que 7") } else { print("égal à 5, 6 ou 7") }
Notes
- if et else if doivent être suivies de conditions entre parenthèses, else ne peut l'être
- les séquences else if et else doivent être précédées de l'accolade fermante de la condition précédente sur la même ligne de code : } else if et } else ; l'emplacement des accolades ouvrantes est libre.
Fonction switch
Permet de choisir dans une liste l'item qui correspond à une valeur, numérique ou non (contrairement aux autres structures il n'y a ni condition entre parenthèses ou code entre accolades, la condition est ici plus implicite, il s'agit d'une concordance entre une chaîne et sa position). Dans l'exemple suivant, c'est un nombre qui désigne l'index de la chaîne à renvoyer (1 pour la deuxième position, 2 pour la troisième…)
>
lequel <- 2 ; switch(lequel, "rouge", "vert", "bleu") [1] "vert"
La position ne doit pas nécessairement être une expression numérique, mais peut être une étiquette arbitraire sous forme de (courte) chaîne (l'appel par position reste possible) :
>
quoi <- "C" ; switch(quoi, "M"="magenta", "J"="Jaune", "C"="cyan") [1] "cyan"
Un appel à une fonction est également possible :
>
>
carmin <- function() { print("OK") } lql <- "c" ; switch(lql, switch("c", "m" ="mauve", "g" ="gris", "c" =carmin()) [1] "OK"
1.4 Boucles while, repeat et for
Boucle while
Une boucle while est une portion de code parcourue et répétée tant que la condition d'entrée est maintenue.
n <- 0 while (n < 7) { print(n) n <- n +1 }
Il n'est cependant pas interdit de prévoir une condition de sortie prématurée avec break (l'exemple donne la suite de Fibonacci limitée à 1 000) :
n0 <- 1 ; n1 <- 1 while (TRUE) { print(n0) n <- n0 +n1 ; n0 <- n1 ; n1 <- n if (n1 >1000) { break } }
Il est possible d'éviter une partie de la boucle avec next, qui renvoie directement en début de boucle. Dans cet exemple, next permet d'éviter l'expression 1 /0 (Inf), qui peut se révéler problématique.
n <- -4 while (n < 3) { n <- n +1 if (n ==0) { next } print(1 /n) }
Boucle repeat
Une boucle repeat est une boucle éternelle dont on ne peut sortir qu'avec break, souvent déclenché selon une condition. Cette boucle s'arrêtera au premier nombre divisible par 7 et 13 (voir l'opérateur modulo)
n <-0 repeat { n <- n +1 print(n) if (n %%7 ==0 & n %%13 ==0) { break } }
Note :
- l'emploi de next est également possible, voir la boucle while
- cette structure s'apparente à while(), mais cette dernière définit généralement une condition préalable tandis que repeat() contient le plus souvent sa condition de sortie à l'intérieur de sa définition, comme le ferait while(TRUE).
Boucle for
La boucle for se base sur une itération, la récursion d'une collection d'objets représentés successivement par la même variable. L'exemple suivant affiche quatre mots joignant les initiales A, g, p et t à rès.
for (x in c("A", "g", "p", "t")) { print(paste(x, "rès", sep="")) }
Cette boucle peut également utiliser une séquence de nombres :
for (i in 0:10) { print(i ^2) }
Il est possible d'imbriquer plusieurs boucles. La nom de la variable de récursion de la boucle incluse doit être différente du nom de la première :
for (i in 1:10) { print(paste("Table de", i, ":")) for (j in 1:10) { print(paste(i, "x", j, "=", i*j)) } }
Notes
- ne pas confondre in permettant de parcourir une collection ou une séquence avec l'opérateur logique «élément de» %in%
- pour l'utilisation de break et next, voir la boucle while
- i est la variable traditionnellement utilisée pour une itération ou une incrémentation, mais n'importe quel nom valable de variable fait l'affaire. On réserve en général i, j, k… pour les boucles. Deux boucles successives (non imbriquées) peuvent avoir la même variable de récursion.
1.5 Fonctions «utilisateurs»
Une fonction-utilisateur est une portion de code écrit et que l'on peut appeler d'un ou de plusieurs endroits du script. Cela peut économiser de la place ou simplement décharger le script de calculs fastidieux et le rendre plus clair. Les fonctions peuvent même être sauvegardées dans un autre fichier, chargé en cas de besoin avec la commande source("chemin/vos_fonctions.R").
Supposons que l'on ait besoin de calculer l'hypoténuse d'un triangle rectangle à partir de la longueur des deux autres côtés (formule h² = a² + b²) :
# définition de la fonction hypotenuse <- function (x, y) { return (sqrt (x^2 + y^2)) # l'hypoténuse est la racine carrée de la somme des carrés des deux autres côtés } # appels de la fonction x <- 37 ; y < 41 print(hypotenuse (3, 4)) print(hypotenuse (12, 5)) # interrogation des valeurs de x et y print (x) ; print (y)
Explications et notes :
- hypotenuse() est défini comme une fonction nécessitant deux nombres à passer en paramètres, réceptionnés dans l'ordre par les variables x et y (noms arbitraires, pourrait être premier_cote et second_cote, ou cote1 et cote2… l'important est de s'y tenir à l'intérieur de votre fonction
- à partir de ces deux nombres, la fonction calcule la racine carrée de la somme de leurs carrés (formule du calcul de l'hypothénuse)
- return() indique que le résultat doit être renvoyé à l'expression appelante (même s'il n'est pas toujours indispensable : la dernière expression de la fonction non assignée à une variable est renvoyée par défaut)
- print(x) ; print(y) sont là pour montrer que les variables x et y définies avant l'appel à la fonction n'ont pas été modifiées par les variables «locales» de la fonction, qui portent pourtant le même nom. Cela permet d'écrire des fonctions qui pourront servir dans d'autres scripts sans s'inquiéter des homonymes
- le script étant lu de haut en bas, la fonction doit avoir été définie avant tout appel
Une fonction ne renvoie pas nécessairement de valeurs, mais peut s'occuper (en autres choses) de leur affichage, ou de leur sauvegarde dans un fichier :
hypotenuse <- function(x, y) { cat("L'hypoténuse d'un triangle rectangle de côtés", x, "et", y, "vaut", sqrt(x^2+y^2), "\n") } hypotenuse(3, 4) hypotenuse(12, 5)
Les deux variances
Comme la fonction var() de R est la «variance non biaisée» d'un échantillon, la somme des écarts à la moyenne au carré est divisée par n-1 et non par n. En cas de besoin récurrent de la variance «empirique» (celle d'une population), il est possible de la calculer soi-même par une fonction utilisateur. Ceci à titre d'exemple, car il suffit de multiplier la variance non biaisée par (n-1)/n pour trouver la variance empirique.
var_n <- function(x) { moyenne <- sum(x) / length(x) # calcul de la moyenne acc <- 0 # initialisation de la variable d'accumulation des carrés des distances for (i in x) { acc <- acc + (i-moyenne)^2 # écarts à la moyenne au carré pour chaque valeur } acc /length(x) # division par n # sans return : cette dernière expression est renvoyée } dist <-c(1, 5, 6, 2, 4, 5) print(var_n(dist)) # variance "n" pour un groupe complet print(var(dist)) # variance "n-1" en cas d'échantillon
Une fonction peut en appeler une autre
Le but des fonctions étant d'organiser et de raccourcir un script, une fonction écrite par l'utilisateur peut faire appel à une autre de ces fonctions :
# première fonction, songez à documenter ce que vous faites! var_n <- function(x) { moyenne <- sum(x) / length(x) # calcul de la moyenne acc <- 0 # initialisation de la variable d'accumulation for (i in x) { acc <- acc + (i-moyenne)^2 # écarts à la moyenne au carré pour chaque valeur } acc / length(x) # division par n } # deuxième fonction, appelant la première sd_n <- function(x){ sqrt(var_n(x)) # l'écart type (standard deviation) est la racine carrée de la variance } dist <-c(1, 5, 6, 2, 4, 5, 2, 7) print(sd_n(dist)) # écart-type d'une population print(sd(dist)) # écart-type d'un échantillon
Récursivité
Une fonction peut s'appeler elle-même (récursivité), à condition de prévoir une condition de sortie :
factorielle <- function (x) { if (x > 1) { # si le nombre est plus grand que 1 x *factorielle (x -1) # il faut le multiplier à la factorielle x-1 } else { 1 # en fin de compte, le calcul sera : x*(x-1)*(x-2)*…*1 } } for (i in 0:10) { cat (paste (i, "!", sep=""), "=", factorielle (i), "\n") }
Il est possible de sauvegarder les fonctions qu'on a écrites dans un fichier, à importer dans un script avec source() :
source("/home/toto/R/mesfonctions.R") sd_n(c(2, 3, 5, 5, 6, 2, 4, 3))
Opérateurs binaires «utilisateur»
Il est possible de définir de nouveaux opérateurs binaires, nécessairement entourés de %. Pour définir %~% comme opérateur «presqu'égal» (c'est-à-dire que leur différence ne peut dépasser, par exemple, le dixième de la quantité du plus grand) :
"%~%" <- function(a, b){ if (abs(a-b) /max(a, b) <= 0.1) { return(TRUE) } else { return(FALSE) } } 8 %~% 9 ; 9 %~% 10
- le nouvel opérateur doit être écrit entre guillemets pour la définition de la fonction (pas pour son utilisation)
- abs() renvoie la valeur absolue : abs(2 -3) et abs(3 -2) valent tous les deux 1 : une distance ne peut être négative
- max() choisit la plus grande des deux valeurs, ce qui est arbitraire : on aurait pu utiliser leur moyenne arithmétique (a+b)/2 ou géométrique sqrt(a*b)
- le résultat du calcul ne peut dépasser 0.1 (un dixième), à changer selon les besoins
- cet opérateur n'a pas été défini pour la comparaison de chaînes, qui ne connaissent pas l'opérateur abs(), la soustraction ni la division et déclenchent donc un message d'erreur
2. Variables, types et opérateurs
En R, les variables peuvent être :
- des nombres : integer (entiers négatifs, nul ou positifs), double (non entiers) ou numeric (l'un ou l'autre)
- des booléens : logical, comme TRUE, FALSE et NA (non available, valeur manquante)
- des chaînes : character, comme "cinq", "", "43"
- des matrices : matrix, tableaux en deux dimensions
- des vecteurs : vector, ensemble de données, comme 13 52 5 24
- des facteurs : factor, index couplés à un vecteur de rang d'index
class() et is() permettent de connaître le type d'une variable.
2.1 Nombres
Voir 2. Variables pour les généralités sur les variables.
L'assignation d'une valeur à une variable se fait par <- :
x <- 43 affecte la valeur numérique 43 à la variable x
x <- 43L précise qu'il s'agit d'un nombre entier
a <- 12.3e-8 est la notation scientifique : le «réel» 12,3 multiplié par 10-8
x <- 4 + 3i permet l'affectation d'un nombre complexe
>
>
>
x <- 3 ; class(x) ; is(x) [1] "numeric" [1] "numeric" "vector" y <- 4L ; class(y) ; is(y) [1] "integer" [1] "integer" "numeric" "vector" [4] "data.frameRowLabels" z <- 5 +6i ; class(z) ; is(z) [1] "complex" [1] "complex" "vector"
as.numeric() transforme une expression (éventuellement sous forme de chaîne) en nombre
as.double() semble un synonyme de as.numeric()
as.integer() transforme une expression (éventuellement sous forme de chaîne) en nombre entier
Les trois fonctions précédentes ne gardent pas la partie imaginaire d'une expression numérique et transforme une chaîne imaginaire en NA. Pour traiter valablement les nombres complexes :
>
as.complex("4 +3i") 4+3i
+, -, *, / s'organisent entre eux comme appris à l'école. Pour changer l'ordre de préséance entre les opérateurs, il faut utiliser les parenthèses : 3*5-7/4 n'égale pas 3*(5-7)/4
^ ou ** est l'opérateur exposant : 7 **3 donne 343
sqrt() donne la racine carrée d'une expression numérique :
>
sqrt(141) [1] 11.87434
43 valant 2 *17 +9,
- x %/% y est le résultat de la division entière de x par y : 43 %/% 17 donne 2
- x %% y est le résultat de l'opération modulo, reste de la division entière de x par y : 43 %% 17 donne 9
Inf (et -Inf), majuscule obligatoire! est le réponse à certains calculs, comme 1 /0, mais pas tan(pi /2) qui vaut 1.633124e+16 à cause de l'imprécision sur pi
NA est la réponse à certaine fonctions as.numeric("4 +3i")
NaN est la réponse à certains calculs, comme sqrt(-141), ou aux indéterminées comme -Inf /Inf, Inf -Inf, 0 /0 et 0 *Inf
Pour R, 0 **0 égale 1.
abs(n) retourne la valeur absolue (abrogation du signe négatif)
sign(n) retourne 1 ou -1 selon le signe de n, 0 si n ==0
min(x, y, z) retourne la valeur minimale entre deux ou plusieurs valeurs
max(x, y, z) retourne la valeur maximale entre deux et plusieurs valeurs
floor() arrondit par défaut
ceiling() arrondit par excès
round(reel) arrondit au nombre entier le plus proche, au nombre entier pair le plus proche s'il se termine par .5
>
round(2.5) ; round(3.5) [1] 2 [1] 4
round(reel, n) arrondi à n décimales si n est positif, à 10abs(n) près s'il est négatif :
>
round(3.14159, 4) ; round(73826, -3) [1] 3.1416 [1] 74000
exp(n) retourne la valeur de e (environ 2.718282) exposant n
log(n) retourne le logarithme naturel/népérien du nombre n
log1p(n) retourne le logarithme népérien du nombre n+1
log10(n) et log2(n) retournent les logarithmes en base 10 et 2.
pi contient la valeur 3.141593
cos(n) retourne la valeur du cosinus d'un angle exprimé en radian
sin(n) retourne la valeur du sinus d'un angle exprimé en radian
tan(n) retourne la valeur de la tangente d'un angle exprimé en radian
Pour exprimer une valeur en degrés, la multiplier par pi/180 :
>
cos(60 *pi/180) [1] 0.5
2.2 Chaînes de caractères
Tout agrégat de caractères écrit entre guillemets est une chaîne de caractères. Si les guillemets entourant sont simples, la chaîne peut contenir des guillemets doubles et vice-versa. Il est encore possible, dans une chaîne entourée de guillemets doubles, d'écrire d'autres guillemets doubles en les précédant d'une barre inverse :
ch <- "C'est une chaîne de caractères" uneautre <- 'Encore une telle "chaîne"!' lamême <- "Encore une telle \"chaîne\"!"
Notes
- "Une chaîne" -> varch la syntaxe inversée est possible
- les guillemets «typographiques» et les apostrophes ’typographique’ sont des caractères comme les autres
class() renvoie le type de donnée d'une variable :
>
class("darla") ; is("dirladada") [1] "caracter" [1] "character" "vector" "data.frameRowLabels" [4] "SuperClassMethod"
is.character("Lundi") retourne TRUE puisque "Lundi" est une chaîne.
as.character(43) transforme le nombre 43 en chaîne de caractères "43"
nchar("Lundi") retourne le nombre de caractères d'une chaîne (et non length()!)
min("bn", "jh") retourne "bn", la chaîne arrivant en premier selon le classement alphabétique parmi deux ou plusieurs chaînes
max("bn", "zb", "jh") retourne "zb", la chaîne arrivant en dernier selon le classement alphabétique parmi deux ou plusieurs chaînes
C'est l'ordre ASCII qui prévaut (" ", "!", "+"…) mais les lettres accentuées sont égales aux non accentuées, sauf en cas d'égalité pour le reste des deux chaînes :
min("bex", "bépo") retourne "bépo" ("e" et "é" équivalents : "p" avant "x")
max("besicles", "bésicles") retourne "besicles" (égalité pour les autres)
"bex" < "bépo" retourne FALSE puisqu'arrivant après selon l'ordre alphabétique
paste()
paste("dirla", "dada") concatène deux (ou plusieurs) chaînes, avec espace intercalaire (par défaut) : "dirla dada"
paste("dirla", "dada", sep="-") concatène deux (ou plusieurs) chaînes, avec une expressions intercalaire : "dirla-dada"
paste("dirla", "dada", sep="") ou paste0("dirla", "dada") concatène deux (ou plusieurs) chaînes, sans espace intercalaire : "dirladada"
paste(4, "2", 1, sep ="") renvoie la chaîne "421", les nombres étant convertis en chaînes
Notes : paste() ne sert pas à assembler les éléments d'un vecteur en une seule chaîne, mais à assembler chaque élément du vecteur avec autre chose :
>
vec <- c("z", "a", "d") ; ch <- paste(vec, "bis") ; print(ch) ; nchar(ch) [1] "z bis" "a bis" "d bis" [1] 5 5 5
Il est possible de concaténer un à un les éléments de deux vecteurs. S'ils ont différentes longueurs, le plus court est recouru à nouveau jusqu'à atteindre la fin du plus long :
>
vec1 <- c("a", "b", "c") ; vec2 <- 1:5 ; paste(vec1, vec2) [1] "a 1" "b 2" "c 3" "a 4" "b 5"
Pour obtenir une vraie chaîne (d'un seul tenant) à partir d'un vecteur, il faut utiliser str_flatten() de la librairie stringr :
>
library(stringr) ; vec <- c("z", "a", "d") ; ch <- str_flatten(vec) ; print(ch) ; nchar(ch) [1] "zad" [1] 3
Vecteurs utiles pour les chaînes
letters[n] donne la nième minuscule de l'alphabet
LETTERS[n] donne la nième majuscule de l'alphabet
LETTERS[18:20] retourne "R" "S" "T" (de la 18e lettre : "R", à la 20e : "T" de l'alphabet latin majuscule
letters[10:12] retourne de la même manière "l" "j" "k"
toupper() renvoie une chaîne en majuscules
tolower() renvoie une chaîne en minuscule
abbreviate("Organisation Nations Unies") retourne "ONU"
substr(chaîne, n1, n2) retourne une partie de la chaîne d'origine, d'un rang à un autre :
>
substr("socialisme", 3, 5) [1] cia
Rechercher
grep() recherche une chaîne de caractères ou une liste de chaînes :
grep("é", c("un", "tramway", "nommé", "désir")) renvoie 3 4, soit le rang des éléments du vecteur dans lesquels se trouve un é .
grepl("é", c("désir", "intense")) renvoie True False puisque le caractère é se trouve dans la première chaîne et non dans la seconde. Le vecteur peut être remplacé par une chaîne.
regexpr("é", "désir") renvoie le premier rang de la chaîne où commence l'expression é, 2 en l'occurrence ; -1 dans le cas négatif.
gregexpr("a", "abracadabra") est plus complexe, renvoyant une liste composite. unlist(gregexpr("a", "abracadabra")) renvoie 1 4 6 8 11 , soit un vecteur des rangs de la chaîne occurrences de "a" ou NULL si aucune occurrence
unlist(regexec(motif, chaine)) est similaire à regexpr(), renvoyant le rang de la première occurrence du motif dans chaine ; -1 sinon
Remplacer
gsub(ch1, ch2, chaine, fixed=True) dans une chaîne, remplace systématiquement ch1 par ch2 :
>
gsub("r", "ch", "rats roux") [1] "chats choux"
sub() ne s'occupe que de la première occurrence de la sous-chaîne :
>
sub("r", "ch", "rats roux") [1] "chats roux"
Note : (parfois!) la chaîne à rechercher pour gsub est considérée comme une expression régulière. Pour la recherche d'une simple chaîne de caractères, terminer avec fixed=TRUE.
Découper
strsplit("les sanglots longs des violons de l'automne, " ") découpe la chaîne à chaque espace :
[1] "les" "sanglots" "longs" "des"
[5] "violons" "de" "l'automne"
Attention : cette fonction produit une liste, qui a pour longueur 1. Pour produire un vecteur, il faut passer par unlist() :
>
vec <- unlist(strsplit("abracadabra", "cada")) ; vec ; length(vec) [1] "abra" "bra" [1] 2
strsplit("abracadabra", "") détache chaque lettre (il y a un vide entre chaque lettre)
strsplit("Oui. Non. Peut-être", ".", fixed=T) à essayer sans fixed=T!
Attention : si le motif de découpe est situé en début de la chaîne à découper, le premier élément du vecteur généré est une chaîne vide ; s'il est situé en fin de chaîne, aucun élément vide n'est généré :
>
strsplit("rêver", "r") [1] "" "êve"
2.3 Expressions régulières (regex)
Les expressions rationnelles, ou régulières, permettent de raffiner les recherches et remplacements de (groupes) de lettres dans une chaîne. Il s'agit d'une amélioration du système des jokers ? et * utilisés dans les recherches de fichiers. D'autres pages de ce site en parlent également, mais il faut savoir que chaque langage peut présenter des variantes et des lacunes. Un exemple simple d'une expression régulière est de séparer une chaîne à chaque chiffre ("\\d") :
ch <- "nouvelle5chanson13française" ; if (regexpr("\\d", ch) > -1) { unlist(strsplit(ch, "\\d")) ; } [1] "nouvelle" "chanson" "" "française"
Par défaut, sub(), gsub(), strsplit(), grep(), grepl, regexpr et gregexpr utilisent les expressions régulières dans les chaînes de recherche. Il faut spécifier fixed=T pour que les caractères de la chaîne soient pris tels quels.
. (un point) désigne n'importe quel caractère :
- b.s vaut pour bas, bAs, bbs, bBs, bcs, bçs, bCs, bÇs … b_s, b$s …
^ début de phrase (mais également exclusion dans une expression [], voir juste ci-après)
$ fin de phrase
[] permet plusieurs choix pour un seul caractère :
- b[aiu]s vaut pour bas, bis et bus
- [a-z] une lettre parmi les minuscules (mais pas les accentuées, à ajouter)
- b[l-o]s sélectionne bls, bms , bns et bos
- [a-n^dj] une lettre de a à n, en excluant d et j
() permet de choisir (avec |) entre deux ou plusieurs (groupes de) caractères ou de considérer un groupe de caractères (également utile pour les quantificateurs ?, + , * et {}) :
- (ni|là|où) désigne aussi bien ni ou là que où
? rend optionnel le dernier (groupe de) caractère(s) :
- dés? désigne aussi bien "dé" que "dés"
- (ah)? permet "" et "ah"
+ permet une répétition indéfinie du dernier (groupe de) caractère(s) :
- (da)+ désigne aussi bien "da" que "dada", "dadada", "dadadada"…
* combine ? et + : rien, 1 ou une répétition indéfinie du dernier (groupe de) caractère(s) :
Par exemple, rou(dou)* désigne aussi bien "rou" que "roudou", "roudoudou"…
{n} permet la répétition exacte n fois d'un (groupe de) caractère(s). Comparer :
- strsplit("ananas", 'na') qui renvoie "a" "" "s" (chaîne vide entre les deux na)
- strsplit("ananas", '(na){2}' qui renvoie "a" "s" (le séparateur est anan)
- {n, m} permet la répétition entre n et m fois d'un (groupe de) caractère(s).
En ajoutant ? après ? + * {} , la demande devient plus parcimonieuse (non greedy) :
- strsplit("Ouahahah!", "(ah)+a") retourne "Ou" "h!" , prenant autant de "ah" que possible suivi de "a" (ahaha) comme chaîne de séparation ;
- strsplit("Ouahahah!", "(ah)+?a") retourne "Ou" "hah!" , prenant le minimum possible de "ah" suivi de "a" (aha) comme chaîne de séparation.
\\ permet à un caractère normalement utilisé pour le codage de conserver sa valeur initiale, ainsi que de coder des types de caractères :
- \\. pour le point (il code sinon tout caractère)
- \\[ et \\] pour les crochets
- \\( et \\) pour les parenthèses
- \\{ et \\} pour les accolades
- \\?, \\* et \\+ pour le point d'interrogation, l'étoile et le signe plus
- \\d tout chiffre, équivalent à [0-9]
- \\D tout ce qui n'est pas chiffre
- \\w minuscule, majuscule ou chiffre
- \\W ni minuscule ni majuscule ni chiffre
- \\n pour le retour à la ligne UNIX et MacOSX
- \\t pour la tabulation
- \\b début ou fin de mot
- \\B ne peut être ni début ni fin de mot
- \\s tout espace, tabulation et saut de ligne
- \\S ne peut être un espace
Notes : dans les autres langages, l'antislash n'est pas redoublé : c'est une spécificité de R.
Remplacement dans une chaîne
sub("[a-e]", "b", "ssessascs") retourne "ssbssascs", à savoir remplace par "b" la première lettre "a", "b", "c", "d" ou "e" trouvée dans la chaîne "ssessass" par "b".
gsub("[a-e]", "b", "ssessass") retourne "ssbssbsbs", à savoir remplace par "b" toutes les lettres "a", "b", "c", "d" ou "e" trouvée dans la chaîne "ssessass".
Pour éviter que la chaîne de recherche soit interprétée comme une expression régulière dans les fonctions sub(), gsub(), strsplit(), grep()… il faut introduire fixed=T :
Découpage de chaîne
strsplit("fichier.txt", ".") retourne "" "" "" "" "" "" "" "" "" "" "" (chaque lettre occasionne une coupure : il n'y a que du vide entre elles)
strsplit("fichier.txt", ".", fixed=T) retourne "fichier" "txt"
strsplit("fichier.txt", "\\.") fonctionne également
semaine <- c("Lun", "Mar", "Mer", "Jeu", "Ven", "Sam", "Dim") ; charmatch("Jeu", semaine) retourne 4
unique(c("a", "b", "a", "a", "b", "c", "a")) supprime les doublons : "a" "b" "c"
make.unique(c("a", "b", "a", "a", "b", "c", "a")) retourne "a" "b" "a.1" "a.2" "b.1" "c" "a.3" : différence est faite entre les différentes entrées de même valeur.
table(c("a", "b", "a", "a", "b", "c", "a")) renvoie un vecteur associant chaque chaîne à son nombre d'occurrences :
a b c 4 2 1
2.4 Listes
S'il est bien un concept singulier en R, c'est celui de liste. Autrement dit, si vous avez quelques problèmes avec les listes, veuillez lire cette section jusqu'au bout. Il s'agit d'une collection d'objets, pas nécessairement de mêmes classes. On peut en construire avec la fonction list() :
>
>
>
L <- list(1, 2, "ahah", c(5, 6, 7)) class(L) [1] "list" length(L) [1] 4
Chaque objet peut être appelé selon sa position dans la liste :
>
L[[3]] ; L[[4]] [[1]] [1] "ahah" [[1]] [1] 5 6 7
Notons que L[3] et L[4] fonctionnent également, mais pas si l'on veut appeler un sous-élément (ici, le second élément du quatrième objet) :
>
>
L[[4]][[2]] [1] 6 L[4][2] <NA> NULL
L[2] <- 43 affecte une nouvelle valeur au deuxième élément
L[] <- 17 affecte une même valeur à tous les éléments de la liste
L[length(L) +1] <- 24 ajoute une valeur en fin de liste
L[2:3] ou L[c(1, 3, 5)] sélectionne des éléments selon la séquence ou le vecteur
>
L <- list("a", "b", "c", "d", "e") ; L[c(4,3,1)] [[1]] [1] "d" [[2]] [1] "c" [[3]] [1] "a"
Si le rang de la nouvelle valeur est plus élevé que la longueur de la liste, des valeurs nulles intermédiaires sont créées :
>
>
>
maliste <- list(5, 6) maliste[4] <- 43 maliste [[1]] [1] 5 [[2]] [1] 6 [[3]] NULL [[4]] [1] 43
C'est ce même NULL qui permet d'enlever un élément :
>
maliste[1] <- NULL ; maliste [[1]] [1] 6 [[2]] NULL [[3]] [1] 43
Pour coller deux listes, utiliser la fonction c() (voir chapitre suivant) :
>
liste1 <- list(4, 3) liste2 <- list("d", "c") nv <- c(liste1, liste2) ; nv [[1]] [1] 4 [[2]] [1] 3 [[3]] [1] "d" [[4]] [1] "c"
Nommer les éléments
Il existe également un type de liste où chaque élément est nommé. Il est possible d'appeler un de ces éléments par leur nom :
>
>
>
L <- list("a" =1, "b" =2, "c" ="ahah", "d" =c(1,2,3)) L[["c"]] [1] "ahah" L["d"] ; L$d ; L$d[2] $d [1] 5 6 7 [1] 5 6 7 [1] 6
Il est possible de nommer une liste après coup avec names() :
>
>
>
carres <- list(1, 4, 9, 16, 25) names(carres) <- c("1^2", "2^2", "3^2", "4^2", "5^2") carres $`1^2` [1] 1 $`2^2` [1] 4 $`3^2` [1] 9 $`4^2` [1] 16 $`5^2` [1] 25
Note : les `guillemets inversés` apparaissent et doivent être utilisés lorsqu'un nom de colonne n'est pas conforme à la nomenclature des noms de variable.
Délister une liste
Certaines fonctions renvoient des listes, comme celles qui découpent une chaîne par une sous-chaîne :
>
>
>
ch <- "Les sanglots longs des violons" lst <- strsplit(ch, " ") lst ; class(lst) ; length(lst) [1] "Les" "sanglots" "longs" "des" "violons" [1] "list" [1] 1
Cette liste (indiquée comme telle) ne possèdant qu'un élément ; chaque mot ne peut donc être appelé selon un quelconque rang dans la liste.
>
lst[[2]] Error in lst[[2]] : indice hors limites
Il y a peut-être une raison à cela, mais elle ne tombe pas sous le sens. Pour obtenir une collection manipulable de chaînes issues d'une telle découpe, il faut traiter la «liste» par la fonction unlist() :
>
>
unl <- unlist(lst) unl ; unl[[2]] [1] "Les" "sanglots" "longs" "des" "violons" [1] "sanglots"
Le résultat obtenu est un vecteur, les collections sont éclatées, et une seule chaîne transforme tous les éléments en chaînes :
>
>
>
liste <- list(9, 8, "k", list(7, 6)) vect <- unlist(liste) vect [1] "9" "8" "k" "7" "6"
3. Vecteurs et distributions
3.1 Vecteurs
c() «combine» fabrique une variable «vecteur», ensemble ordonné d'éléments de même classe. Le [1] (et non [0] comme dans la majorité des langages informatiques) de la réponse indique que la valeur suivante est la première d'une série : pour les longs vecteurs dont les valeurs sont listées sur plusieurs lignes, l'index de la valeur suivante est répété à chaque nouvelle ligne.
>
>
>
a <- c(1, 5, 4, 6, 2, 1, 3, 4, 5, 5) ; a [1] 1 5 4 6 2 1 3 4 5 5 class(a) ; is(a) ; is.vector(a) [1] "numeric" [1] "numeric" "vector" [1] TRUE length(a) [1] 10
class() et is() renvoient des informations sur une variable
is.vector(var) retourne TRUE si var est un vecteur, FALSE sinon
length(a) renvoie la longueur du vecteur, à savoir le nombre d'éléments qu'il contient
+ sert à additionner les éléments terme à terme de deux vecteurs) :
>
>
vec1 <- c(1, 2, 3) ; vec2 <- c(7, 8, 9) print(vec1 + vec2) [1] 8 10 12
c() permet également de prolonger une vecteur par un autre vecteur ou d'autres valeurs
>
>
vec1 <- c(1, 2, 3) ; vec2 <- c(7, 8, 9) vec <- c(vec1, 5, vec2) ; vec [1] 1 2 3 5 7 8 9
Attention! Dans le cas d'un vecteur contenant au moins une chaîne de caractères, tout nombre est transformé en chaîne :
>
>
a <- c(1, 4, "3", 2, 5) a ; class(a) [1] "1" "4" "3" "2" "5" [1] "character"
Voyez scan() pour la saisie de valeurs numériques dans un vecteur.
Les opérations sur des vecteurs sont réalisées sur chacun de leurs éléments :
>
>
n <- c(10, 100, 1000) ; n + 5 ; n * 3 [1] 15 105 1005 [1] 30 300 3000 ch <- c("a", "b", "c", "d") ; paste(ch, "bis") [1] "a bis" "b bis" "c bis" "d bis"
a[3] désigne le troisième élément du vecteur a, qui contient dans l'exemple plus haut le nombre 4
a[3:5] renvoie un vecteur formé des valeurs des positions 3 à 5 (comprise) du vecteur a
a[c(2, 3, 5)] renvoie un vecteur fait des deuxième, troisième et cinquième valeurs du vecteurs a
a[-3] retourne tout le vecteur a diminué de son troisième élément. Cette expression ne modifie pas le vecteur lui-même, sauf dans l'expression a <- a[-3]
a[c(-2, -3, -5)] ou a[-c(2, 3, 5)] retourne le vecteur a diminué de ses deuxième, troisième et cinquième éléments.
which() retourne les index des éléments d'un vecteur contenant une valeur particulière :
>
vec =c(1, 3, 5, 4, 3, 2) ; which(vec ==3) [1] 2 5
3.2 Génération de vecteurs
letters et LETTERS sont deux vecteurs tout faits comprenant les 26 lettres minuscules et majuscules non accentuées.
letters[5:10] renvoie [1] "e" "f" "g" "h" "i" "j"
Il est possible de générer une séquence de nombre de x à y (inclus) avec l'expression x:y :
>
var <- 13:19 ; var [1] 13 14 15 16 17 18 19
seq(debut, fin, by =pas) retourne un vecteur rassemblant les nombres entre debut et fin (avec un éventuel pas, qui peut être négatif) :
>
>
>
>
seq(-4, 3) [1] -4 -3 -2 -1 0 1 2 3 seq(-4, 3, 0.5) [1] -4.0 -3.5 -3.0 -2.5 -2.0 -1.5 -1.0 -0.5 0.0 0.5 1.0 1.5 2.0 2.5 3.0 seq(4, -3, -1) [1] 4 3 2 1 0 -1 -2 -3 seq(4) [1] 1 2 3 4
Notes
- contrairement à beaucoup de langages de programmation, le nombre de fin est compris dans le résultat (si le pas le permet).
- comme le dernier exemple le montre, un seul nombre en paramètre sous-entend que le vecteur commence à 1 (et non à zéro comme dans la majorité des langages)
rep(qqch, n) répète n fois un vecteur :
>
rep(c(1,2,3,4,5), 3) [1] 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5
each permet de répéter chaque élément un à un :
>
rep(c(1,2,3,4,5), each=3) [1] 1 1 1 2 2 2 3 3 3 4 4 4 5 5 5
sample(vect, n) retourne un vecteur de n valeurs au hasard choisies dans le vecteur vect (tirage sans remise : n ne peut dépasser la longueur du vecteur) :
>
sample(1:6, 3) [1] 5 1 2
sample(vect, n, replace=TRUE) permet un tirage pseudo-aléatoire avec remise et donc un nombre plus grand que la longueur du vecteur (rep=T est un équivalent) :
>
sample(c("P", "F"), 5, rep=T) [1] "F" "P" "P" "F" "P"
Note : les deux réponses ci-dessus sont susceptibles d'être différentes à chaque «tirage».
3.3 Modifications (d'éléments) de vecteur
a[3] <- 43 affecte une valeur au troisième élément d'un vecteur comprenant au moins 3 éléments
a[] <- 43 affecte une même valeur à tous les éléments d'un vecteur existant
a[3:5] <- c(3,5,8) permet un remplacement d'une série de valeur par une autre, à condition que la séquence 3:5 soit de même longueur que le vecteur qui la remplace
a[c()] <- c() remplace quelques valeurs désignées selon leur rang du vecteur a par un même nombre de valeurs contenues dans un autre vecteur :
>
>
a <- c(1, 2, 3, 4, 5, 6, 7, 8, 9) a[c(2,4,7)] <- c("x", "y", "z") ; a [1] "1" "x" "3" "y" "5" "6" "z" "8" "9"
Il est possible de rechercher et modifier une valeur à plusieurs endroits d'un vecteur :
>
>
>
nbr <- c(1, 5, 4, 6, 2, 1, 4, 2, 1) nbr[nbr ==1] <- 43 nbr [1] 43 5 4 6 2 43 4 2 43
… dans le vecteur nbr, chaque élément (symbolisé à l'intérieur des crochets par nbr) égal à 1 doit à présent valoir 43
La condition ne se limite pas à l'égalité, mais peut utiliser toute sorte de conditions logiques (> < !=…). Pour agir sur les nombres pairs :
>
>
vec <- c(1,2,3,4,5,6,7,8,9,10,11) vec[vec %% 2 ==0] <- 43 ; vec [1] 1 43 3 43 5 43 7 43 9 43 11
Il est également possible de filtrer conditionnellement un vecteur, en ne gardant ici que les nombres impairs :
>
>
vec <- c(2,5,9,4,8,6,11,1,10,7,3) vec <- vec[vec %% 2 ==1] ; vec [1] 5 9 11 1 7 3
%in% teste l'appartenance d'un élément dans un vecteur :
>
3 %in% c(1, 3, 4, 8, 9) [1] TRUE
En combinant condition et appartenance, il est possible de remplacer plusieurs éléments par une même valeur (en cas de vecteur de chaînes, les chaînes entières sont concernées – contrairement à un remplacement dans un texte par gsub() :
>
>
>
valrech <- c("a","b","c") # vecteur de valeurs à chercher vec <- c("b","ad","ab","a","e","cc","c") # vecteur sur lequel on travaille vec[vec %in% valrech] <- "oui" ; vec [1] "oui" "ad" "ab" "oui" "e" "cc" "oui"
Opérations sur un vecteur
Un vecteur numérique peut être une distribution.
NA («not available») est une valeur qui rend le résultat de tout calcul NA.
sum() retourne la somme des éléments d'un vecteur numérique.
Il est possible d'ajouter (ou de soustraire) un même nombre à l'ensemble des éléments d'un vecteur :
>
>
suite <- c(1, 4, 9, 16) suite +1 [1] 2 5 10 17
Les fonctions unaires s'appliquent à chaque élément d'un vecteur :
>
>
>
coll <- c(10, 40, 37, 2, 53) racine <- sqrt(coll) ; racine [1] 3.162278 6.324555 6.082763 1.414214 7.280110 round(racine, 2) [1] 3.16 6.32 6.08 1.41 7.28
Il est possible de multiplier (ou de diviser) par un même nombre tous les éléments du vecteur :
>
>
suite <- c(1, 4, 9, 16) suite *3 [1] 3 12 27 48
Il est possible d'appliquer une fonction à chaque élément d'un vecteur :
>
>
carre <- function(x) { x^2 } vect <- c(1, 2, 3, 4, 5, 6) ; carre(vect) [1] 1 4 9 16 25 36
sort(vect) trie les valeurs du vecteur vect :
>
sort(c(5, 0, 6, 4, 8, 3, 2, 9, 1, 7)) [1] 0 1 2 3 4 5 6 7 8 9
Il est possible de préciser decreasing=T et na.last=T ou F. En cas de NA dans le vecteur, omettre na.last élimine les valeurs non attribuées :
>
sort(c(1:5, NA), decreasing=T) [1] 0 1 2 3 4 5 6 7 8 9
Opérations sur les vecteurs
Rappel : NA («not available») est une valeur qui rend le résultat de tout calcul NA.
min(v1) donne la valeur minimale d'un vecteur
min(v1, v2) donne la valeur minimale parmi deux (ou plusieurs) vecteurs
max(v1) donne la valeur maximale d'un vecteur
max(v1, v2) donne la valeur maximale parmi deux (ou plusieurs) vecteurs
Il est possible d'additionner, multiplier… les vecteurs numériques (de même longueur) entre eux, les opérations affectant les éléments de même rang (v1 %*% v2 est la somme des produits terme à terme) :
>
>
v1 <- c(1, 4, 9, 16) ; v2 <- c(1, -1, 1, -1) v1 + v2 ; v1 * v2 ; v1 %*% v2 [1] 2 3 10 15 [1] 1 -4 9 -16 [,1] [1,] -10
%in% teste la présence de chaque élément du premier vecteur dans le second (par chaînes entières si variables «caractères») :
>
c(1, 5, 9, 15) %in% c(2, 5, 15, 37, 89) [1] FALSE TRUE FALSE TRUE
< teste la relation de chaque élément du premier vecteur avec l'ensemble des éléments du second (il suffit pour chaque élément du premier de trouver un élément du second satisfaisant à la condition) :
>
c(1,3,15,6,9) < c(2,5,6,7,8) [1] TRUE TRUE FALSE TRUE FALSE
all() impose la globalité de la réussite du test pour l'ensemble du premier vecteur :
>
all(c(1,3,15,6,9) < c(2,5,6,7,8)) [1] FALSE
paste(v1, v2, sep="-") assemble terme à terme les éléments de deux vecteurs, il en résulte toujours un vecteur de chaînes.
3.4 Facteurs
La variable de type factor ressemble aux vecteurs, mais permet de stocker de façon économique des données répétitives :
>
>
>
>
vec <- c("Femme", "Homme", "Homme", "Femme", "Femme"") fac <- factor(vec) ; print(fact) ; class(fact) [1] Femme Homme Homme Femme Femme Levels: Femme Homme [1] "factor" is(fac) [1] "factor" "integer" "oldClass" [4] "numeric" "vector" "data.frameRowLabels" is.factor() ; str(fac) TRUE Factor w/ 2 levels "Femme","Homme": 1 2 2 1 1
En interne, les données sont codées c("Femme", "Homme") (vecteur des «levels») et c(1, 2, 2, 1, 1), vecteur de 1 et 2 désignant respectivement Femme et Homme. Cela a surtout un intérêt pour les vecteurs comportant des données répétées (variables catégorielles), peu intéressante pour les noms et les rues d'un carnet d'adresses.
print(fact[3]) permet d'accéder au troisième rang de la variable factor
fact[3] <- "Femme" permet de modifier le troisième rang de la variable (la nouvelle doit appartenir à une des catégories)
Il est possible de prévoir une catégorie supplémentaire lors de la constitution de la variablefactor :
fact <- factor(c("Femme", "Homme", "Homme", "Femme", "Femme"), levels = c("Femme", "Homme", "Queer"))
Mais il est également possible de l'ajouter par la suite
levels(fact) <- c(levels(fact), "Queer")
Lors de la constitution d'une table de données, les vecteurs sont par défaut transformés en facteurs.
3.5 Distribution
Tout vecteur de nombres peut être considéré comme une distribution univariée. Il existe des fonctions et graphiques tout faits pour traiter de ce genre de distributions. Pour ces fonctions, préciser na.rm=TRUE («remove non-available values») permet de ne pas prendre en compte les éventuelles valeurs NA qui rendrait la réponse NA.
mean() retourne la moyenne des éléments d'un vecteur (leur somme divisée par leur nombre)
median() retourne la médiane des éléments d'un vecteur (mis en ordre, il s'agit de la valeur du milieu en cas de longueur paire de vecteur, sinon de la moyenne des deux valeurs centrales)
quantile() donne les quartiles d'une distribution (la médiane et les quartiles sont ici interpolés) :
>
dist <- c(1, 6, 5, 3, 4, 6) ; quantile(dist) 0% 25% 50% 75% 100% 1.00 3.25 4.50 5.75 6.00
summary() retourne un vecteur de six éléments : le minimum, le premier quartile, la médiane, la moyenne, le troisième quartile et le maximum. summary(vect)[2] retourne le premier quartile.
var() retourne la variance de la distribution (la variance est une mesure de dispersion d'une distribution ; il s'agit de la somme des différences au carré de chaque valeur à la moyenne, divisée par le nombre d'observations diminué d'1). Pour la variance "n", multiplier par (n-1)/n.
sd() retourne l'écart-type (standard deviation) d'une distribution représentée par un vecteur numérique (l'écart-type équivaut à la racine carrée de la variance). Pour l'écart-type "n", multiplier par sqrt((n-1)/n).
crossprod(v1, v2) retourne une matrice de 1×1 composé de la somme des produits terme à terme de deux vecteurs de longueur égale. v1 %*% v2 retourne le même résultat. Pour le résultat en nombre : (v1 %*% v2)[1][1]
tcrossprod(v1, v2) multiplie le vecteur v1 par chaque terme de v2 , fabriquant une matrice de length(v2) colonnes de longeur length(v1) (v1 et v2 peuvent être de longueurs différentes).
Un vecteur pouvant représenter un tableau de contingence d'une seule rangée, il est possible d'y appliquer le test du χ² (khi-deux) :
chisq.test(vecteur, params) - Attention : admet des petits tableaux de contingence (n =25) sans toujours prévenir de la nullité du test.
Il est possible de visualiser des distributions avec plot() et ggplot().
4. Matrices
Les matrices sont des tableaux à deux dimensions. Elle sont importantes dans les distributions bivariées, ou les enquêtes individus/variables. Il est possible de transformer une matrice en table de données.
matrix() construit une matrice (la première valeur est une variable ou un vecteur de données, la seconde le nombre de rangées (lignes) et la troisième le nombre de colonnes. Le remplissage se fait verticalement, colonne après colonne :
>
>
vect <- c(1, 2, 3, 4, 5, 6) m <- matrix(vect, 2, 3) ; m [,1] [,2] [,3] [1,] 1 3 5 [2,] 2 4 6
rbind() construit une matrice en additionnant des lignes (rangées) :
>
rbind(c(1,3,5), c(2,4,6)) [,1] [,2] [,3] [1,] 1 3 5 [2,] 2 4 6
cbind() construit une matrice en additionnant des colonnes :
>
cbind(c(1,2), c(3,4), c(5,6)) [,1] [,2] [,3] [1,] 1 3 5 [2,] 2 4 6
rbind() et cbind() permettent d'ajouter une ligne ou une colonne à une matrice existante (en respectant les dimensions)
length() retourne le nombre d'éléments d'une matrice.
nrow() et ncol() retournent respectivement le nombre de rangées et de colonnes.
L'accès à une donnée se fait au moyen de ses coordonnées [ligne,colonne] :
>
m[1,2] [1] 3
Il est possible de sélectionner toute une rangée ou toute une colonne sous forme de vecteur :
>
>
m[2,] [1] 2 4 6 m[,2] [1] 3 4
Il est possible de sélectionner une sous-matrice en utilisant des séquences, ici les rangs 1 à 2 et les colonnes de 2 à 3 :
>
m[1:2,2:3] [,1] [,2] [1,] 3 5 [2,] 4 6
Si la sélection ne porte que sur une ligne ou une colonne, le résultat retourné est converti en vecteur :
>
v <- m[1:2, 3] ; v ; is(v) [1] 5 6 [1] "numeric" "vector"
drop=FALSE permet d'éviter cette conversion pour garder une matrice d'une ligne ou d'une colonne :
>
m[1:2, 3, drop =F] [,1] [1,] 5 [2,] 6
View(matrice) permet de visualiser une matrice dans un tableau graphique, print(matrice) l'affiche dans une console.
Initialisation de matrices
Pour fabriquer une matrice uniforme, soit une seule valeur partout, il suffit de l'indiquer en première position :
>
m <- matrix(0, 2, 3) [,1] [,2] [,3] [1,] 0 0 0 [2,] 0 0 0
Pour initialiser une matrice de chaînes :
>
matrix("", 2, 3) [,1] [,2] [,3] [1,] "" "" "" [2,] "" "" ""
Il est possible de définir une matrice de nombres impairs à partir de la séquence 0:5 (vecteur des nombres de 0 à 5 inclus) :
>
matrix(0:5 *2 +1, 2, 3) [,1] [,2] [,3] [1,] 1 5 9 [2,] 3 7 11
Opérations sur une matrice
Comme les vecteurs, chaque terme d'une matrice peut être multiplié (ou divisé, ou soumis à un exposant).
>
matrix (0:5, 2, 3) *2 [,1] [,2] [,3] [1,] 0 4 8 [2,] 2 6 10
-matrice change le signe de tous les termes
1 /matrice remplace chaque terme par son inverse (Inf ou -Inf si terme négatif)
sqrt(matrice) racine carrée de chacun des termes (NaN en cas de terme négatif)
exp(matrice) remplace chaque terme en exp(x)
etc.
aperm(matrice) intervertit lignes et colonnes :
>
>
m <- matrix (0:5, 2, 3) ; m [,1] [,2] [,3] [1,] 0 2 4 [2,] 1 3 5 m <- aperm(m) ; m [,1] [,2] [1,] 0 1 [2,] 2 3 [3,] 4 5
Une matrice pouvant représenter un tableau de contingence, il est possible d'y appliquer des tests statistiques :
chisq.test(matrice, params) réalise le test du χ² (khi-deux)
fisher.test(matrice, params) réalise le test exact de Fisher
Matrices carrées
det(m) retourne le déterminant d'une matrice
solve(m) retourne une matrice inverse (sous certaines conditions)
p =eigen(m) calcule les valeurs propres (p$values) et les vecteurs propres p$vectors
Opérations sur deux matrices
Deux matrices de mêmes dimensions peuvent additionner et soustraire leurs éléments terme à terme.
>
matrix (0:5, 2, 3) + matrix(10, 2, 3) [,1] [,2] [,3] [1,] 10 12 14 [2,] 11 13 15
Les multiplication * et division / de deux matrices correspondent à la multiplication et à la division de leurs éléments terme à terme :
>
>
>
m <- matrix (0:5, 2, 3) ; print (m) [,1] [,2] [,3] [1,] 0 2 4 [2,] 1 3 5 n <- matrix (0:5*2+1, 2, 3) ; print (n) [,1] [,2] [,3] [1,] 1 5 9 [2,] 3 7 11 m *n [,1] [,2] [,3] [1,] 0 10 36 [2,] 3 21 55
m **n soumet les éléments de la première matrice aux exposants contenus dans la seconde.
La vraie multiplication de matrices nécessite que le nombre de colonnes et le nombre de lignes de l'une soient les inverses de l'autre. Utiliser %*% et %/% dans ce cas seulement :
>
>
>
m <- matrix (0:5, 2, 3) ; print (m) [,1] [,2] [,3] [1,] 0 2 4 [2,] 1 3 5 n <- matrix (0:5*2+1, 3, 2) ; print (n) [,1] [,2] [1,] 1 7 [2,] 3 9 [3,] 5 11 m %*%n [,1] [,2] [1,] 26 62 [2,] 35 89
Pour rappel,
- le premier emplacement final sera l'addition des multiplications des éléments terme à terme de la première ligne de la première matrice avec la première colonne de la seconde matrice : 26 =0*1 + 2*3 + 4*5, 62 = 0*7 + 2*9 + 4*11, etc. ; le résultat est une matrice carrée correspondant au nombre de rangée de la première matrice
- cette opération n'est pas commutative
- les personnes qui ont besoin de ce genre de chose sont généralement au courant
5. Tables de données
Une table de données est un tableau de valeurs organisées en vue d'être traitées (lues, modifiées, filtrées, regroupées, additionnées, etc.). Une table est constitué de rangées représentant des enregistrements (individus, objets, observations…) et colonnes (variables contenant principalement des nombres et des chaînes de caractères).
Une base de données peut contenir plusieurs tables en relation les unes avec les autres. Bien qu'une base de données puisse n'être constituée que d'une seule table (typiquement un carnet d'adresse), cette page n'utilise jamais le mot «base» pour «table».
R a prévu quelques variables rendant disponibles des tables de données toutes faites sur lesquels il est possible de tester les différentes fonctions qui s'y appliquent :
- iris contient 150 observations sur trois types d'iris : longueurs et largeurs des pétales et sépales
- pressure relie 19 températures à autant de pressions
- mtcars décline 32 modèles de voiture en 11 variables (consommation, cylindrée, nombres de cylindres et de vitesses…)
- AirPassengers ventile le nombre de passagers aérien par mois pour les années 1949 à 1960
- PlantGrowth affiche une masse et une chaîne (expérimentateur?) pour 30 expériences de croissance de plantes
- ToothGrowth relate les données (longueur, type d'additif alimentaire, dose) d'une expérience sur la croissance des dents d'un rongeur
- Titanic est constitué de quatre tableaux de contingence classe (1e|2e|3e|équipage) * sexe (M|F) pour les quatre combinaisons âge (enfant|adulte) * survie (oui|non)
Il est possible d'ouvrir ou d'importer un fichier contenant une table de données, mais il sera question dans ce début de chapitre de la façon de produire ce genre de table, en transformant, avec as.data.frame(), une matrice en table de données :
V1 | V2 | V3 | V4 | |
---|---|---|---|---|
1 | Richard | 179 | 1979.06.12 | M |
2 | Philippe | 183 | 1981.04.23 | C |
3 | Louis | 177 | 1984.11.12 | M |
>
>
>
>
>
vect <- c("Richard", "Philippe", "Louis", 179, 183, 177, "1979.06.12", "1981.04.23", "1984.11.12", "M", "C", "M") mat <- matrix(vect, 3, 4) # transforme le vecteur en matrice 3 rangs / 4 colonnes df <- as.data.frame(mat) # transforme la matrice en table de données View(df)
Le vecteur initial contenant au moins une chaîne, toutes les valeurs le composant sont également des chaînes, même si cela ne se voit pas dans le tableau produit par View() ou print().
data.frame() permet d'assembler des vecteurs de même longueur en table de données :
nom | taille | naissance | é_c | |
---|---|---|---|---|
Riri | Richard | 179 | 1979.06.12 | M |
Fifi | Philippe | 183 | 1981.04.23 | C |
Loulou | Louis | 177 | 1984.11.12 | M |
>
>
>
>
>
>
>
nom <- c("Richard", "Philippe", "Louis") taille <- c(179, 183, 177) naissance <- c("1979.06.12", "1981.04.23", "1984.11.12") é_c <- c("M", "C", "M") df <- data.frame(nom, taille, naissance, é_c, stringsAsFactors =FALSE) rownames(df) <- c("Riri","Fifi","Loulou") print(df)
- Chaque nom de vecteur est automatiquement devenu le nom de la colonne correspondante dans la table.
- stringsAsFactors =FALSE spécifie que les chaînes sont à prendre telles quelles et non comme valeur de rang n d'un vecteur : "M" "C" "M" et non 2 1 2 dans "C" "M"
Propriétés du tableau
class(df) renvoie "data.frame" ; is(df) est plus complet
dim(df) renvoie un vecteur contenant les dimensions de la table : 3 (observations), 4 (variables)
attributes(df) renvoie les noms de variables, la classe et le nom des colonnes : $names, $class et $row_names (sans guillemets)
str(df) renvoie la structure d'un objet, complexe pour une table de données :
'data.frame': 3 obs. of 4 variables: $ nom : chr "Richard" "Philippe" "Louis" $ taille : num 179 183 177 $ naissance: chr "1979.06.12" "1981.04.23" "1984.11.12" $ é_c : chr "M" "C" "M"
Sans stringsAsFactors =FALSE, la dernière ligne serait :
$ é_c : Factor w/ 2 levels "C","M": 2 1 2
Rangées
nrow(df) renvoie le nombre d'observations : 3
rownames(df) ou row.names(df) renvoie le nom des rangées ou permet de spécifier les noms d'observation ("1", "2", "3"… par défaut)
>
rownames(df) <- c("N01", "N02", "N03") ; View(df)
Colonnes
df$couvert <- c("cuiller", "couteau", "fourchette") ajoute une colonne à une table de données
df$couvert <- NULL supprime la colonne désignée par son nom.
ncol(df) ou length(df) renvoie le nombre de variables (colonnes) : 4
names(df) ou colnames(df) renvoie les noms de variables (de colonnes) : "nom" "taille" "naissance" "é_c", ou permet de les assigner (pour éviter les noms V1, V2, V3… par défaut) :
>
>
colnames(df) <- c("nom","taille","naissance","é_c") View(df)
- pour ne changer le nom que de la ne colonne : colnames(df)[n] <- "nvnom"
- pour renommer une colonne à partir de son nom : colnames(df)[which(colnames(df) == "ancnom")] <- "nvnom"
Extraire des données
Vous pouvez expérimenter dans R, Rcmdr ou Rstudio les commandes ci-dessous si vous y collez-copiez le bloc de code qui suit data.frame() (sans les invites ">").
Sélection de colonne(s) :
df["nom"] ou df[1] renvoie une table constituée des valeurs de la colonne couv ou de la colonne n° 2
df[2:4] renvoie une table constitué des colonnes contiguës de 2 à 4
df[c("nom","é_c")] et df[c(1,4)] renvoient une table de plusieurs colonnes choisies par leurs noms ou leurs rangs
df$taille ou df[, 2] renvoie un vecteur constitué des valeurs de la colonne taille ou de la colonne n° 2
df[, "taille", drop=F] ou df[, n, drop=F] retourne une table (drop=F) des valeurs de la variable couv ou de la colonne n
Sélection de rangée(s), virgule à droite indispensable :
df[1,] df["Riri",] renvoie une table d'une observation sélectionnée par son rang ou son nom
df[2:3,] renvoie une table de plusieurs lignes contiguës
df[c(1,3),] et df[c("Riri","3"),] renvoient une table de plusieurs lignes choisies par n° ou nom de ligne
Sélection d'observation(s), coordonnées lignes/colonnes :
df$naissance[3] retourne la valeur de la 3° observation de la colonne couv (vecteur d'un seul élément)
df$naissance["Riri"] l'expression n'accepte pas la désignation d'une rangée par son nom (NA)
df[3, 4] et df["3", "é_c"] retourne la valeur de la 3° observation de la quatrième colonne é_c (vecteur d'un seul élément)
df[c(2, 3), c("taille", "naissance")] retourne une table contenant les valeurs des colonnes taille et naissance des 2° et 3° observations
df[1:2, "taille"] ou df$taille[c(1, 3)] renvoie un vecteur des observations sélectionnées de la colonne "taille"
df[c(1:2),"taille", drop =FALSE] renvoie une table des 2° et 3° observations de la colonne "mot"
df$taille[c(1, 3), drop=F] ne permet pas d'obtenir le résultat de la sélection sous forme de table
subset() extrait sous forme de table des observations selon des conditions (elles peuvent être composées avec tout opérateur logique :
subset(df, é_c =="M")
nom taille naissance é_c Riri Richard 179 1979.06.12 M Loulou Louis 177 1984.11.12 M
Lors du chargement d'une table de données ou de sa définition ne passant pas par des vecteurs, R ne connaît pas le nom des variables des colonnes. attach() le permet :
>
>
>
>
>
df <- as.data.frame(matrix(c("Anne", "Julie", "Michel",168, 173, 170), 3, 2)) attach(df) print(V1) detach(df) print(V1)
detach(df) est censé permettre de ne plus avoir accès aux variables (fonctionne dans R console, mais pas dans Rstudio).
with(df, commande()) permet également des commandes ayant un accès aux variables :
df <- as.data.frame(matrix(c("Anne", "Julie", "Michel",168, 173, 170), 3, 2)) with(df, print(V1))
…mais pour écrire dans la table de données, il faut spécifier une variable :
>
>
>
df <- data.frame(n=c("Anne", "Julie", "Michel"), t=c(168, 173, 170)) df$diff <-with(df, t -mean(t)) df n t diff 1 Anne 168 -2.3333333 2 Julie 173 2.6666667 3 Michel 170 -0.3333333
within(df, { diff <- t -mean(t) } ) est une variante.
Ordonner une table de données
order(table$variable),] permet le tri d'un table selon une variable :
>
>
>
>
pren <- c("Anne", "Julie", "Michel") taille <- c(168, 173, 170) df <- data.frame(pren, taille, stringsAsFactors =F) nv <- df[order(df$taille),] ; print(nv)
Il est possible d'ajouter des conditions de tri (sur d'autres variables) et une commande pour un tri descendant :
>
>
>
>
pren <- c("Anne", "Julie", "Michel") taille <- c(168, 170, 170) df <- data.frame(pren, taille, stringsAsFactors =F) nv <- df[order(df$taille, df$pren, decreasing=T),] ; print(nv)
Joindre des tables de données
rbind(df1, df2) joint deux tables contenant les mêmes noms de colonnes / variables. Le r de rbind() vient de row, puisqu'il s'agit d'ajouter des rangées
>
>
>
>
>
df1 <- data.frame (x =c(1,2,3), y =c("a","b","c")) rownames(df1) <-c("A","D","N") df2 <- data.frame (x =c(4, 5), y =c("d", "e")) rownames(df2) <-c("X", "Z") rbind (df1, df2) x y A 1 a D 2 b N 3 c X 4 d Z 5 e
Il existe une technique permettant de nourrir une base de données, par exemple dans une boucle. On part alors d'une table de données vide mais dont les colonnes ont été prévues, à laquelle on ajoute une ou plusieurs rangée·s de données :
df <- data.frame(nom=character(), prenom=character(), age=numeric()) df <- rbind(df, data.frame(nom="Rigby", prenom=("Eleanor"), age=75))
Lors de la jointure de deux bases de données, il se pourrait que deux noms de rangée soient égaux. Par sécurité, le second de deux noms de rangée identiques est modifié pour lever l'ambiguïté.
>
>
>
>
>
df1 <- data.frame (x =c(1,2,3), y=c("a","b","c")) rownames(df1) <-c("A","B","C") df2 <- data.frame (x =c(4,5), y=c("d","e")) rownames(df2) <-c("A","B") rbind (df1, df2) x y A 1 a B 2 b C 3 c A1 4 d B1 5 e
Il est possible d'ajouter une rangée de nombres ou de chaînes de même valeur :
>
rbind (df1, "a") x y z w A 1 a f k B 2 b g z C 3 c h j 4 a a a a
cbind(df1, df2) joint les colonnes de bf2 à celle de bf1. Les tables doivent avoir le même nombre de rangées/enregistrements. Attention, la commande ne vérifie pas le nom des colonnes, ce qui peut poser des problèmes.
>
>
>
df1 <-data.frame(x=c(1,2,3), y=c("a","b","c")) df2 <-data.frame(z=c(4,5,6), y=c("d","e","f")) cbind(df1, df2) x y z t 1 1 a 4 d 2 2 b 5 e 3 3 c 6 f
Il est possible d'ajouter une colonne de constante ou une formule :
>
>
>
df1 <-data.frame(x =c(1,2,3), y =c("a","b","c")) df2 <-data.frame(z =c(4,5,6), y =c("d","e","f")) cbind (df1, df2, a =length(df1)) x y z t a 1 1 a 4 d 2 2 2 b 5 e 2 3 3 c 6 f 2
merge() assemble deux tables qui possède (au moins) une colonne commune (ordre pour cet l'exemple) :
>
>
>
>
>
>
>
>
>
ordre <- c(1, 2, 3) pren <- c("Anne", "Julie", "Michel") nom <- c("Cuiller", "Couteau", "Fourchette") gens <- data.frame(ordre, pren, nom) film <- c("Providence","Casanova","Sacré Graal") livre <- c("L'étranger","L'immoraliste","Le vagabond") culte <- data.frame(ordre, film, livre) tout <- merge(gens, culte, by ="ordre") print(tout) ordre pren nom film livre 1 1 Anne Cuiller Providence L'étranger 2 2 Julie Couteau Casanova L'immoraliste 3 3 Michel Fourchette Sacré Graal Le vagabond
Note : si la variable commune de l'un n'est pas complète, le résultat sera tronqué.
Croisement de variables
xtabs() permet la sommation d'une variable selon une autre :
>
>
>
>
>
>
sexe=c("G", "G", "G", "F", "F", "F", "G", "F", "F", "G") note=c(15, 12, 11, 12, 17, 11, 13, 15, 10, 9) df <- data.frame(sexe, note) somme <- xtabs(get("note") ~ get("sexe"), data =df) names(dimnames(somme)) <- "Somme des résultats par sexe" print(somme) Somme des résultats par sexe F G 65 60
table() produit un tableau de contingences à partir du croisement de deux variables :
>
>
>
>
sexe <- c("F","G","F","G","G","F","F","G","F","F") sang <- c("A","B","A","A","O","O","O","A","O","A") df <- cbind.data.frame(sexe, sang) table(df$sexe, df$sang) A B O F 3 0 3 G 2 1 1
À suivre…
6. Entrées et sorties
6.1 Clavier et console
Entrées au clavier
readline() permet la saisie d'une chaîne de caractères, s'interrompant avec [Enter] :
>
name <- readline(prompt = "Un nombre de 1 à 10… ")
…mais cela ne fonctionne qu'en mode interactif (R dans une console ou dans Rstudio).
readLines() permet une saisie au clavier en mode script. "stdin" désigne l'entrée standard (la console), n (facultatif) permet de prévoir le nombre de lignes à prévoir avant la saisie de l'ensemble (il ne semble pas possible de savoir comment forcer la saisie avant d'avoir atteint le nombre de lignes indiqué) :
cat("Un nombre de 1 à 10 : ") n <- as.numeric(readLines("stdin", n=1)) print(switch(n, "un", "deux", "trois", "quatre", "cinq", "six", "sept", "huit", "neuf", "dix"))
scan() permet la saisie de nombres en un vecteur numérique (point décimal, notation scientifique de type 3e-6 et NA sans guillemet sont acceptés, mais erreur pour tout caractère, entouré ou non de guillemets). La séparation entre les nombres est l'espace, il est possible de revenir à la ligne avec un retour-chariot ; la saisie d'une ligne vide interrompt le processus.
>
1:
4:
7:
vect <- scan() ; vect 5 4 3 2 1 5 Read 6 items [1] 5 4 3 2 1 5
Il est possible de limiter a priori le nombre maximal de ligne (l'interruption par la saisie d'une ligne vide reste valide) :
>
1:
4:
vect <- scan(nlines =2) ; vect 1 2 3 4 5 6 Read 6 items [1] 1 2 3 4 5 6
Sortie sur la console
print() permet la sortie d'une valeur (nombres, textes, vecteurs ou résultat d'une fonction), avec retour à la ligne. Les chaînes sont entourées de guillemets, et les vecteurs et matrices structurés
>
print(matrix(1:12,3,4)) [,1] [,2] [,3] [,4] [1,] 1 4 7 10 [2,] 2 5 8 11 [3,] 3 6 9 12
Pour éventuellement composer des chaînes, utiliser paste() :
>
print(paste("pi vaut", pi)) [1] "pi vaut 3.14159265358979"
cat() est plus spécialisée dans le formatage de la chaîne à sortir, en ignorant toute structure des données (pour récupérer une concaténation dans une variable, utiliser paste()).
>
cat("a", "b", "c", sep="") abc
- sep ="" précise le caractère ou la chaîne qui sépare chaque élément
- fill =T permet le saut de ligne à la fin de la chaîne (F par défaut)
- fill =n force le saut de ligne après au plus n caractères (mais les chaînes restent entières)
- labels =c("a", "b", "c") apparaissent successivement au début de chaque ligne
- file ="" précise un nom de fichier dans lequel la chaîne sera sauvegardée (ou commande?)
- append =T précise que la nouvelle sortie doit être ajoutée au fichier, en n'effaçant pas ce qui y est éventuellement écrit
cat() n'entoure pas les chaînes de guillemets, et il faut lui préciser le saut de ligne :
>
+
cat(matrix(1:12, 3, 4), unlist(strsplit("les sanglots longs des violons de l'automne", " ")), sep ="-", fill =15, labels=c("a:", "b:", "c:")) a: 1-2-3-4-5-6- b: 7-8-9-10-11- c: 12-les- a: sanglots- b: longs-des- c: violons-de- a: l'automne
Note : contrairement à paste(), cat() assemble les éléments d'un vecteur.
6.2 Fichiers de simple texte
chaine <- scan("nomdufichier.txt", what ="character", sep ="\n") lit un fichier de caractères dont les lignes sont séparées par la fin de ligne UNIX \n
cat() permet d'écrire dans un simple fichier de texte :
cat("les sanglots longs des violons de l'automne", file ="verlaine.txt")
Exemple un peu plus complexe, qui permet un certain formatage de sortie :
vec =c("les", "sanglots", "longs", "des", "violons", "de", "l'automne") cat(vec, sep=" / ", fill=30, file="ver-lai-ne.txt", append=T)
produit le fichier ver-lai-ne.txt contenant :
les / sanglots / longs / des / violons / de / l'automne
append=T permet un ajout à un fichier existant, qui sera sinon écrasé.
Pour la sortie d'une chaîne avec cat(), voir Sortie console
6.3 Tables textes (csv et tsv)
Lecture de fichiers csv et tsv
df <- read.csv("nomdufichier", params ="") ouvre un ficher de texte contenant des données aux conventions csv ("comma separated values", format pas vraiment standardisé). Les données d'une même ligne sont séparées par des virgules, chaque observation (individu) par une fin de ligne (Unix \n ou Windows \r\n). Les chaînes sont entourées de guillemets doubles et le point est le séparateur décimal. La première ligne comprend les titres de colonnes (variables) et chaque ligne commence par un nom de rangée. La variable réceptrice (df) est une table de données (data.frame).
df <- read.csv2("nomdufichier", params ="") offre des variantes par rapport au précédent, plus adaptées aux conventions latines : le séparateur est le point-virgule, pour ne pas interférer avec le séparateur décimal, qui est la virgule.
df <- read.table("nomdufichier", params ="") est plus subtil. Si la première ligne contient une valeur de moins que les autres, elle est interprétée comme titres de colonnes et la première valeurs des autres lignes est considérée comme nom d'observation. Si toutes les lignes ont un nombre égal de valeurs (le séparateur de données est la tabulation \t), la première ligne est considérée comme une observation comme les autres et les noms de colonnes seront V1, V2… Les chaînes sont entourées de guillemets doubles et le séparateur décimal est le point.
Il est possible de modifier ces spécifications des trois dernières commandes en ajoutant (à la place de param ="") :
- col.names =F et row.names =F pour empêcher les noms de colonnes et de rangées si un fichier csv n'en possède pas.
- sep ="," , sep =";" sep ="\t" pour forcer le type de séparateur de données
- quote ="'" ou quote ="\"" (sic) pour forcer le type de guillemets entourant les chaînes
- dec ="," ou dec ="." pour forcer le type de séparation décimale
Il est également possible d'ajouter d'autres précision :
- nrows =n limite à n le nombre de lignes à importer
- stringsAsFactors =F empêche l'encodage des chaînes sous forme d'index de vecteurs : ("F" ,"F" ,"H" ,"H" ,"F" ,"H") plutôt que (1, 1, 2, 2, 1, 2) se référant à c("F", "H")
Écriture de fichiers csv et tsv
write…(df, fichier, params) écrit une table de données sous la forme csv, selon diverse modalités : write.csv(), write.csv2() et write.table() suivent les spécifications décrites à la commande read().
write(c(1:12), file="col3.tsv", ncolumns = 3, sep="\t") sauvegarde des données en trois colonnes ; elles sont ici séparées par des tabulations
6.4 Tables binaires (rds et rda)
Table de données
df <- readRDS("monfichier.rds") charge une table de données préalablement sauvegardée avec saveRDS()
saveRDS(objet, file ="monfichier.rds") sauvegarde un objet (chaîne, vecteur ou table de données) dans un format binaire, ensuite mobilisable par readRDS(). Une chaîne sauvegardée produira une table d'une cellule, un vecteur une colonne.
Base de données
vect <- load("bd.rda") lit une base de données de plusieurs tables sauvegardées par save(). Il en résulte un vecteur des noms des tables sauvegardées.
save(df1, df2, df3, "bd.rda") permet la sauvegarde de plusieurs tables de données.
Espace de travail
save.image(file ="espace.RData") sauvegarde l'espace de travail (toutes les variables ouvertes à un moment donné par R)
load("espace.RData") récupère l'espace de travail.
6.5 Importation et exportation
Importer un fichier d'une autre application est souvent plus délicat qu'exporter une base de données vers une autre application, ce qui peut le plus souvent se faire à l'aide d'un fichier .csv (voir supra). Il faut sinon avoir recours à des bibliothèques.
foreign
library(foreign) charge la bibliothèque de fonctions foreign permettant l'importation de plusieurs type de bases de données. L'extension est normalement installée par défaut avec R, sous le nom de paquetage r-cran-foreign pour le système Linux/Debian. Cette bibliothèque permet normalement d'importer une base de données de type .spss (SPSS .sav), .dbf (dBaseII, dBaseIII, dBaseIV et Clipper), .dta (Stata), .arff (Weka), Minitab, S, SAS, Systat
Format .dta de STATA
db =read.dta ("chemin/ma_base.dta")
Format .arff de Weka
db =read.arff ("chemin/ma_base.arff")
Format .sav de SPSS/PSPP (import puis export)
db =read.spss ("chemin/ma_base.sav") write.foreign(db, "mabase.sav", "mabase.sps", "SPSS")
Format .dbf de dBaseII, III et IV
db =read.dbf ("chemin/ma_base.dbf")
readODS
Pour lire des fichiers ods de Libreoffice calc :
install.packages ("readODS") library (readODS) db =read_ods("nomdufichier.ods", col_names =F)
D'autres spécificités :
- col_names =T (par défaut) si la première rangée contient des noms de colonnes sur la première rangée, elles seront sinon appelées A, B, C…
- na ="" (par défaut) les cellules vides sont considérées comme valeurs manquantes
- formula_as_formula =T importe les formules des cellules plutôt que les résultats
- row_names =F (par défaut) s'il y a des noms de rangée sur la première colonne. 1, 2, 3… sinon.
- sheet =1 (par défaut) choisit la feuille du classeur.
- skip =n nombre de lignes à ne pas prendre en compte
- range ="B2:C3" sélectionne des cellules
openxlsx
Pour importer un fichier xlsx Excel, il faut utiliser la bibliothèque openxlsx :
library (openxlsx) db =read.xlsx ("chemin/votre_feuille.xlsx")
7. Divers
7.1 Système de fichiers
Répertoires
getwd() contient le répertoire courant («working directory»)
setwd("repertoire/sous-repertoire") définit le répertoire courant
dir.exists("nom2dossier") renvoie TRUE si le sous-répertoire se trouve dans le répertoire courant
list.files() liste les fichiers du répertoire courant
file.create("nom2fichier.ext") crée un fichier vide
file.rename(from ="nom1", to ="nom2") renomme un fichier
file.info("nom2fichier")
basename("chemin/vers/nom2fichier") renvoie le nom de fichier nom2fichier
file.path("repertoire", "sous-rep", "sous-sous-rep", "nom2fichier")
Le package fs fait la même chose (en remplaçant les . des fonctions par des _ , avec une meilleur compatibilité entre OS.
plot(pressure$pressure, params=…) dessine les valeurs de la variable pressure selon leur ordre dans pressure , les valeurs sont représentées par des cercles. Les paramètres principaux sont :
plot(pressure$temperature, pressure$pressure) dessine un graphique avec une relation entre deux variables, la première variable en abscisse, la seconde en ordonnée (les «points» aux coordonnées sont des cercles)
Note : plot(pressure$temperature ~ pressure$pressure) inverse les valeurs sur les axes.
barplot(iris$Petal.length) donne un graphique affichant des barres verticales : les paramètres type et pch de plot ne sont pas valides.
boxplot(iris$Petal.length) graphique «boîte à moustaches», basé sur la médiane (grosse ligne du rectangle), les quartiles (limites du rectangle), les premier et neuvième déciles (limite des lignes), et les valeurs extrêmes sous forme de points (ou autre caractère si pch=n). Les valeurs aberrantes (inférieures de plus de 1,5 fois l'écart interquartile du premier quartile ou supérieures de plus de plus de 1,5 fois l'écart interquartile du troisième quartile) sont notées par des points.
hist(iris$Petal.length, breaks =10) dessine un histogramme, qui regroupe les valeurs d'une variable numérique entre certaines bornes, produisant des planches de hauteur selon le nombre de valeurs regroupées, breaks indique le nombre de planches à produire.
curve(formule, from =deb, to =fin) dessine une courbe selon l'équation formule, de x allant de deb à fin :
Ces fonctions graphiques peuvent s'ajouter sur un graphique préalablement réalisé :
lines(pressure$temperature, pressure$pressure) (sur un plot préalable) ajoute une ligne rejoignant les cercles
abline(c, m) trace une droite de pente m passant par le point de coordonnée (0, c) (équation y = m*x +c) :
Cette dernière forme permet de tracer, dans un graphique univarié, une moyenne mean() ou une médiane median() :
Pour tracer une droite de régression dans un graphique bivarié, il faut utiliser lm() de la bibliothèque stats :
Comme R, la bibliothèque ggplot2 contient des exemples de tables de données, comme mpg (234 modèles de voitures). Il est également possible d'utiliser pour les exemples les tables de données toutes faites, par exemple iris et pressure du logiciel R, en mode console ou avec Rstudio.
Il est à noter que la fonction ggplot nécessite toujours un mode d'affichage, sous la forme + geom_…()
ggplot(iris, aes(x= Sepal.Length)) + geom_bar() réalise un histogramme (une seule variable) à partir de la colonne Sepal.Length de la table de données interne iris. Les valeurs de la colonnes sont rassemblées et le nombre de chaque valeur exprimé sous forme de colonnes (geom_bar()), verticales si x=, horizontales si y=
ggplot(iris, aes(x= Sepal.Length, fill =Species)) + geom_bar() scinde et colorise les colonnes en fonction des trois noms contenus dans la variable Species
Si une barre est partagée par plusieurs espèces, les couleurs se superposent. Pour cliver chaque barre selon les espèces, préciser geom_bar(position = "dodge")
Pour changer les couleurs, il est possible d'ajouter + scale_fill_manual(values=c("#dd0000", "#00cc00", "#0000dd"))
ggplot(iris, aes(x =1, y =Petal.Length)) +geom_boxplot() réalise une boîte à moustaches sur une valeur (x =1 assigne une valeur arbitraire à l'axe des x, qui n'a pas de grandeur.
Cela semble plus évident lorsque la variable est ventilée selon une variable facteur :
ggplot(iris, aes(x = Species, y = Sepal.Length)) +geom_boxplot() ventile la variable y en trois distribution selon un facteur discriminant (ici, la variable Species).
ggplot(iris, aes(x = Species, y = Sepal.Length, fill =Species)) + geom_boxplot() attribue une couleur différente pour les trois boîtes à moustaches générées
ggplot(iris, aes(x= Sepal.Length, y =Petal.Length)) + geom_point() charge la table de données interne iris, assigne les valeurs des abscisses (x) et des ordonnées (y) à deux variables de la table de données, respectivement Sepal.Length et Petal.Length, et dessine un point à chaque coordonnées (x, y).
ggplot(iris, aes(x= Sepal.Length, y =Petal.Length, color=Species)) + geom_point() colore les points selon les espèces. Pour fixer soi-même les couleurs, ajouter
geom_bar() histogramme (univariées uniquement)
geom_point() indique des points pour les distributions bivariées
geom_line() trace une ligne entre les coordonnées d'une distribution bivariée
geom_smooth() affiche une courbe de régression ; geom_smooth(method=lm) pour une droite de régression
geom_col() agrège une variable numérique selon une variable facteur (fill=Species pour colorer les colonnes) :
geom_count() l'affichage est pondéré en cas de plusieurs observations aux coordonnées égales (bivariés). Par défaut, la grosseur des points varient selon le nombre ; il est possible de préciser alpha=0.5 (les disques sont plus (0.9) ou moins (0.1) opaques, compatibles avec geom_point())
ggplot(iris, aes(x= Sepal.Length, y =Petal.Length, color =Species, shape =Species)) + geom_point() impose une couleur et une forme de points selon la variable Species d'iris (trois variétés).
ggplot(iris, aes(x = Sepal.Length, fill=Species)) + geom_col(position = "dodge") la colonne représentant x est divisée si plus d'une Species sont représentées à cette valeur.
size =variable ou color =variable permet de pondérer chaque observation (par la taille du point ou par l'intensité de la couleur), ce qui permet la prise en compte d'une troisième variable / troisième dimension :
labs(title="", x ="", y="") permet d'ajouter un titre ou de modifier les étiquettes des axes (par défaut, le titre des axes sont le nom des colonnes).
ggsave("nom.png", width=, height=) sauvegarde le dernier diagramme produit. .png pour un nom de fichier compressé sans perte
La programmation moderne fait appel à des fonctions qui ne sont pas écrites dans l'application principale (R en l'occurrence), mais dans des compléments souvent développés indépendamment, qui ont pour nom «bibliothèques» («library» en anglais) à télécharger sous forme de packages. Par exemple, l'ouverture d'un fichier au format R utilise une fonction interne à l'application, mais l'ouverture d'un fichier d'autres format (DBF, SAV…) se fera par une fonction appartenant à la bibliothèque foreign.
La page
cran.r-project.org/web/packages liste plus de 18 000 bibliothèques disponibles (août 2021), avec un lien vers un fichier de présentation.
Certaines sont automatiquement installées avec R, mais les plus nombreuses doivent être expressément installées. En Linux, l'installation peut parfois être faite, comme pour toute autre application, par son nom de paquetage. Mais si vous disposez d'une connexion Internet, le plus simple est d'utiliser la ligne de commande R, qui télécharge et installe elle-même la bibliothèque. Pour la bibliothèque ggplot2, qui propose des graphiques plus élaborés :
En UNIX, Rstudio charge les bibliothèques dans l'espace /home/toto/R pour l'utilisateur toto. Si l'on veut que plusieurs utilisateurs aient accès aux mêmes bibliothèques, il faut lancer R dans une console en mode super-utilisateur (su + mot de passe super-utilisateur, puis saisir R en majuscule). Les bibliothèques seront alors installées dans le répertoire /usr/local/lib/R/site-library/ :
L'installation n'est à faire qu'une fois par système installé. Notez donc les bibliothèques que vous utilisez pour les retrouver facilement à chaque mise-à-jour majeure de votre système.
Certaines bibliothèques peuvent s'avérer inutiles, entrer en conflit avec d'autres, ou être dépassées par de nouvelles. Pour désinstaller une bibliothèque et libérer un peu de place sur le système :
Dans les systèmes UNIX, le mode super-utilisateur est requis pour désinstaller une bibliothèque qui avait été installée en mode super-utilisateur. Mais n'utilisez jamais ce mode pour le travail quotidien car il produit des fichiers illisibles par les utilisateurs ordinaires.
Pour utiliser les fonctions d'une bibliothèque installée, à chaque session ou en début de script :
Pour décharger la bibliothèque avant une fin de session ou de script :
On trouve sur Internet des pages plus ou moins bien faites sur l'utilisation des fonctions des bibliothèques. Pour trouver de la documentation sur la bibliothèque ggplot2, saisir r ggplot2 dans le moteur de recherche DuckDuckGo.
setwd("..") permet de remonter au répertoire parent
dir.create("nom2dossier") crée un nouveau répertoire
file.exists("nom2dossier") TRUE si existence d'un sous-répertoire dans le répertoire courant
unlink("nom", recursive =TRUE) supprime un répertoire
list.files("repertoire") liste les fichiers d'un sous-répertoire
list.files(recursive =TRUE) liste tous les fichiers du répertoire et de tous les sous-répertoires
list.files(pattern =".txt") ne liste que les fichiers contenant l'extension txt
Fichiers
file.exists("nom") TRUE si existence d'un fichier dans le répertoire courant
unlink() et file.remove("nom2fichier") suppriment un fichier
file.copy(from ="nom1", to ="nom2", overwrite =TRUE) copie un fichier, overwrite =T écrase un éventuel fichier du même nom existant
file.append("nom1", "nom2") ajoute le fichier nom2 à nom1
file.mtime("nom2fichier")
file.size("nom2fichier")
dirname("chemin/vers/nom2fichier") renvoie chemin/vers
8. Sortie graphique
8.1 plot()
curve(cos(pi*x)/x, from = 2, to =10) # sinusoïdale amortie
Ajouts aux graphiques
versi <- subset(iris, Species =="versicolor")
plot(versi$Petal.Length)
abline(h=mean(versi$Petal.Length), col="magenta")
abline(h=median(versi$Petal.Length), col="blue")
# filtre la variété versicolor
versi <- subset(iris, Species =="versicolor")
# calcul de la régression linéaire
library(stats)
droite <- lm(Petal.Width ~ Petal.Length, data = versi)
coeff <- coefficients(droite)
# équation (sera le titre du graphique) ; "+"[sign(coeff[1])==1] affiche '+' si positif
equation <- paste0("y =", round(coeff[2],2), "x ","+"[sign(coeff[1])==1], round(coeff[1],2))
plot(versi$Petal.Length, versi$Petal.Width, main=equation)
abline(droite, col="magenta")
droite
8.2 ggplot() + geom_…()
Histogrammes
Boîtes à moustaches
Graphiques bivariés
+ scale_color_manual(values=c("#dd0000", "#00bb00", "#0000dd"))
+ geom_…() pour l'affichage
ggplot(iris, aes( Species, Petal.Length, fill=Species)) + geom_col()
ggplot(iris, aes(x= Sepal.Length, y =Petal.Length, size =Sepal.Width, color =Species)) + geom_point(alpha=.3)
+ labs() pour les titres et étiquettes
+ xlim() et/ou ylim() pour recadrer le graphique
+ scale_x_discrete() et/ou scale_y_discrete() pour recadrer le graphique
ggsave() pour sauvegarder le graphique
9. Bibliothèques
Installation
>
install.packages("ggplot2")
R
install.packages("ggplot2")
su + mot de passe#
super-utilisateur
>
remove.packages("ggplot2")
Utilisation de bibliothèques
>
library(ggplot2) # les guillemets ne semblent pas nécessaires
>
detach(package:ggplot2)