Quick R

Je croise souvent des gens qui veulent se mettre à programmer sous R mais qui, par manque de temps ou parce que les tutos qu’on trouve sur internet font parfois un peu peur, ne s’y mettent pas. Je vous propose donc une très rapide introduction pour aider celles et ceux d’entre vous à sauter le pas. Elle est volontairement très simple et incomplète : l’idée, c’est de permettre à quelqu’un qui n’a jamais programmé de sa vie de s’y mettre sans trop de difficultés, rien de plus.

Premiers pas

Pour installer R sur votre machine, rendez vous ici, cliquez sur CRAN (pour Comprehensive R Archive Network), choisissez le serveur le plus proche de chez vous et suivez la procédure. Si vous êtes sous Windows, téléchargez l'exécutable et choisissez toutes les options par défaut. Si vous travaillez sous Mac ou Linux, il n'est pas inutile d'installer RStudio après R lui-même (c'est une interface graphique qui va considérablement simplifier votre vie).

Quand c'est fait, lancez une cession. Les utilisateurs de Windows devraient voir ça :

Ce que vous voyez, c’est le GUI (pour Graphical User Interface), un logiciel très basique qui vous permet d’interagir avec R lui-même (si vous êtes sous Mac ou Linux, c’est le rôle de RStudio). La fenêtre sur fond blanc, c’est la console. C’est là-dedans que nous allons envoyer des instructions pour exécution et voir ce que nous répond R.

Sous Windows, attention : si vous cliquez que l’une ou l’autre des petites croix blanches sur fonds rouge, vous quittez R. Essayez et vous devriez voir apparaître ça :

À chaque fois que vous voyez ça et jusqu’à ce que vous sachiez exactement de quoi il est question : cliquez « Non » (dans l’immédiat, cliquez plutôt sur « Annuler ».)

Nous allons très rapidement passer sur les manipulations dans la console — principalement parce que n’est pas là-dedans que nous allons travailler. Commençons par nous débarrasser de ce message d’accueil : cliquez dans la console (n’importe où) et pressez Ctrl+L.

Toujours dans la console, devant le signe >tapez 1+1 puis Entrée. Vous devriez avoir ça :

En rouge, votre instruction (1+1) et en bleue, la réponse de R (2) — le [1] n’est qu’un indicateur de position, vous allez très vite comprendre à quoi il sert.

Si vous essayez de modifier votre première instruction (1+1), vous devriez assez rapidement constater que c’est impossible. Pour R, c’est du passé. Ce que vous pouvez faire, en revanche, c’est cliquer que la petite flèche qui pointe vers le haut sur votre clavier pour rappeler la dernière instruction envoyée à la console et là, avant de la ré-exécuter, vous pouvez la modifier. Essayez de faire ça en remplaçant le 2ème 1 par un 2.

Comme vous pouvez le constater vous-même, ça n’est pas pratique du tout (mais alors pas du tout). La bonne nouvelle c’est que nous n’allons pas travailler comme ça.

Script

Dans Fichier, sélectionnez Nouveau script (ou pressez Ctrl+N). Vous devriez avoir quelque chose comme ça :

Sans titre est un script. C’est un fichier texte dans lequel nous allons écrire des instructions avant de les envoyer à la console pour exécution. Là-dedans, à part, de la mise en forme, vous pouvez faire ce que vous voulez : copier, couper, coller et modifier à loisir. Vous pouvez aussi (et vous devriez) le sauvegarder pour ne pas perdre votre travail (sous Windows, ce sera un fichier .R que vous pouvez ouvrir avec n’importe quel éditeur de texte).

Dans votre script, saisissez 6*7 puis, en maintenant le curseur sur cette ligne, pressez Ctrl+R (sous Rstudio, c'est Cmd+Entrée). En principe, vous devriez observer que votre instruction a été envoyée à la console pour exécution :

C’est comme ça que nous allons travailler : écrire des instructions dans un script et les envoyer à la console pour exécution : plusieurs lignes de code sauvegardées dans un script, ça fait un programme.

Bases

La règle suprême de la programmation sous R s’énonce très simplement : pour reprendre les termes de John Chambers, un de ses concepteurs, « tout ce qui existe est un objet et tout ce qui arrive est un appel à une fonction. » Nous allons surtout nous concentrer sur la première partie : « tout ce qui existe est un objet. »

Avant ça, nous allons nous mettre d’accord sur une petite convention entre nous. Quand j’écris :

6*7

C’est une instruction dans un script. Mais si j’écris :

> 6*7
[1] 42
>

C’est le résultat de l’exécution de cette instruction dans la console (i.e. n’allez pas me coller des > ou des [1] au début des lignes de vos scripts !)

Dans votre script, tapez machin et exécutez (Ctrl+R sous Windows, Cmd+Entrée si vous utilisez RStudio). En principe, vous obtenez un message d'erreur :

> machin
Erreur : objet 'machin' introuvable
>

R n’ayant jamais entendu parler de machin, il vous informe qu’il ne sait pas de quoi vous parlez. Nous allons donc créer un objet machin qui sera, par exemple, la suite des entiers de 1 à 5. Dans votre script, écrivez et exécutez :

machin <- 1:5

Le signe <- permet d'assigner une valeur à un objet. Vous pouvez aussi l'utiliser dans l'autre sens (1:5 -> machin) et vous pouvez aussi faire ça avec le signe = (machin = 1:5) mais je vous le déconseille pour le moment.

Dans la console, vous observez un accusé de réception :

> machin <- 1:5
>

Si vous voulez voir vous ce que contient machin, vous pouvez écrire machin dans la console ou sélectionner juste le mot machin dans votre script (le mettre en surbrillance) et exécuter. En principe :

> machin 
[1] 1 2 3 4 5
>

Dans la console, si vous tapez ls(), R vous confirme qu'il connait bien un objet nommé machin (la fonction ls liste le nom des objets existants dans l'environnement de travail actuel) :

> ls()
[1] "machin"
>

Et la fonction class, vous dira de quelle sorte d'objet il s'agit (ici integer, pour entiers) :

> class(machin)
[1] "integer"
>

Et puisque machin existe, nous pouvons jouer avec (tapez ça dans votre script, exécutez d'un coup et essayez de deviner ce que fait chaque fonction) :

length(machin)
sum(machin)
mean(machin)
max(machin)
rev(machin)
diff(machin)
rep(machin, 3)
machin+1
machin^2

Notez, pour les deux dernières, une petite particularité magique de R : il « recycle » l’élément le plus court de votre calcul. Quand vous lui demandez de calculer machin+1, il rajoute 1 à chaque élément de machin (idem pour machin au carré).

Maintenant, essayez ça :

machin <- c(2, 1, 3, 10, 1000)
bidule <- 2
machin*bidule

Delà, vous observez deux choses : (i) vous pouvez créer plusieurs objets et jouer avec et (ii) vous venez d'écraser l'ancien machin (la séquence des entiers de 1 à 5) pour le remplacer par une nouvelle définition de machin (avec la fonction c qui concatène à peu près tout ce que vous voulez).

Fonctions

Il existe une quantité invraisemblable de fonctions dans R auxquelles se rajoutent des libraires entières de fonctions spécialisées (les packages du CRAN) et celles que vous pouvez créer pour vos propres besoins. D’une façon générale, on utilise une fonction de la façon suivante :

nom_de_la_fonction(argument1, argument2, ...)

Sauf que, dans bien des cas, R nous simplifie la vie. Un bon exemple, c'est la fonction seq qui créé des séquences (l'opérateur :, que nous avons vu plus haut, est une sorte de raccourci pour seq). Pour savoir comment l'utiliser, vous pouvez exécuter :

help()

Ou :

?seq

La page d'aide qui s'ouvre vous informe, en autres choses, que seq admet 5 arguments : from (valeur par défaut : 1), to (valeur par défaut : 1), by (valeur par défaut : ((to - from)/(length.out - 1))), length.out (valeur par défaut : NULL) et along.with (valeur par défaut : NULL).

Par exemple, pour créer la suite des entiers de 1 à 10 avec un incrément de 2, vous pouvez écrire :

seq(from = 1, to = 10, by = 2)

Mais, puisque vous donnez les arguments dans l'ordre normal, vous n'êtes pas obligé de les nommer :

seq(1, 10, 2)

Du coup, vous pouvez les donner dans le désordre en les nommant :

seq(by = 2, from = 1, to = 10)

Et puisque la valeur par défaut de from c'est déjà 1, vous pouvez carrément omettre de le préciser :

seq(to = 10, by = 2)

Ou :

seq(, 10, 2)

Et si vous voulez une séquence qui commence à 10, progresse par 10 et a une longueur de 200 (notez que je ne suis pas obligé d'écrire length.out : je peux juste écrire len ou même l) :

seq(10, by = 10, len = 200)

Si vous cherchez une fonction sans savoir comment elle s’appelle (par exemple, pour trier), utilisez :

help.search("sort")

Ou :

??sort

Enfin, vous pouvez créer vos propres fonctions. Supposez, par exemple, que vous voulez une fonction qui calcule l'aire d'un disque en fonction de son rayon (pi est déjà en mémoire, vous pouvez l'utiliser directement) :

aire_disque = function(rayon) {
 res <- rayon*pi^2
 return(res)
}

Utilisation :

> aire_disque(2)
[1] 19.73921
>
Quelques classes utiles

Voici quelques-uns des objets les plus utiles :

Vecteurs

Avec runif (qui renvoie des nombres aléatoires qui suivent une distribution uniforme) vous pouvez créer un vecteur de classe numeric :

x <- runif(10)

En effet :

> class(x)
[1] "numeric"
>

Comme tous les vecteurs, il a une longueur mais pas de dimensions (je sais, c'est bizarre mais c'est comme ça) :

> length(x)
[1] 10
> dim(x)
NULL
>

Si vous souhaitez récupérer un élément de x (mettons le 5ème), faites x[5]. Pour les 3 premiers éléments, x[1:3]. Pour tous les éléments sauf le premier, le plus simple c'est x[-1].

Vous pouvez aussi assigner une valeur à un élément de votre vecteur :

x[5] <- 1000

Les vecteurs de classe integer (nombres entiers, nous en avons vu un plus haut) fonctionnent exactement de la même façon.

Dans la grande famille des vecteurs, il a aussi les vecteurs de classe character (c'est du texte). Par exemple :

x <- c("papa", "maman")

Ces choses-là sont notamment très utiles pour donner des noms aux autres objets :

# Ceci est un commentaire
# (ce qui est écrit après un dièse n'est pas exécuté).
# Soit un vecteur 'integer'
x <- 1:26
# L'objet 'letters' existe déjà en mémoire :
names(x) <- letters

Du coup :

> x[c("a", "m", "z")]
 a  m  z 
 1 13 26 
>

Il y a aussi des vecteurs de classe Date (notez le format des dates dans R) :

as.Date("2018-01-15")-10:1

Et, mes préférés, les vecteurs de classe logical (les booléens c'est-à-dire des vecteurs de TRUE et de FALSE) :

1:10 > 5

Ils permettent, entre autres, de faire des choses comme ça :

> x <- 1:26
> x[x > 10]
 [1] 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
>

Matrices

Une matrice, très simplement, c'est un tableau de nombres (un array à deux dimensions dans lequel, en principe, vous ne devriez avoir que des nombres).

x <- matrix(1:15, nrow = 5, ncol = 3)

Ce qui nous donne :

> x
     [,1] [,2] [,3]
[1,]    1    6   11
[2,]    2    7   12
[3,]    3    8   13
[4,]    4    9   14
[5,]    5   10   15
>

Une matrice a deux dimensions — un nombre de ligne et un nombre de colonnes (par convention, toujours dans cet ordre) :

> dim(x)
[1] 5 3
>

Pour extraire la première ligne faites x[1, ]. Pour la première colonne faites x[, 1] (notez que dans les deux cas précédents, R fait « sauter » les dimensions : vous récupérez des vecteurs). Vous pouvez aussi, par exemple, récupérer les 2 premières lignes des colonnes 2 et 3 avec x[1:2, c(2, 3)].

Pour remplacer tous les éléments des x qui sont supérieurs à 10 par 10, faites simplement :

x[x > 10] <- 10

Supposez, par exemple, que vous souhaitez récupérer les lignes de x pour lesquelles les nombre de la seconde colonne sont pairs. Avec %%, l’opérateur modulo, notre condition s’écrit :

x[, 2] %% 2 == 0

Nous n'avons donc qu'à faire :

x[x[, 2] %% 2 == 0, ]

Et puisque 1 == TRUE et 0 == FALSE, on peut faire encore plus court en utilisant l'opérateur ! de la négation (!TRUE == FALSE) :

x[!x[, 2]%%2, ]

Listes

Les listes permettent de stocker à peu près n'importe quoi. Par exemple :

x <- list(1:10, letters, matrix(1, 3, 3))

Si vous voulez récupérer le 3ème élément (les lettres de l'alphabet) utilisez x[[3]]. Pour les deux 1ers, faites x[1:2] ou x[-3].

Vous pouvez aussi utiliser les noms de la liste comme ceci :

x <- list(
 nombres = 1:10,
 lettres = letters,
 matrice = matrix(1, 3, 3))

x$lettres
x[c("nombres", "matrice")]

Si vous préférez finalement des lettres majuscules :

x$lettres <- LETTERS
# Ou :
x$lettres <- toupper(x$lettres)

Data.frames

Un data.frame, c'est un peu comme une table de base de donnée : un tableau dans lequel chaque 'colonne' peut être d'une classe différente :

x <- data.frame(
 numbr = 1:26,
 alpha = LETTERS,
 dates = Sys.Date()-26:1)

Techniquement, ces choses-là sont des listes avec une structure. Vous pouvez donc les manipuler comme des matrices ou comme des listes :

x[1:2, ]
x$dates

Notez que pour la colonne alpha, vous obtenez un objet de classe factor :

> al <- x$alpha
> class(al)
[1] "factor"
> 

Pour éviter le problème, vous pouvez simplement faire ça :

> al <- as.character(x$alpha)
> class(al)
[1] "character"
> 
Boucles

Celles et ceux d’entre vous qui programment dans d’autres langages se demandent sans doute comment on écrit des boucles sous R. En général, on ne le fait pas : dans la plupart des cas, il y a des méthodes plus rapides et moins verbeuses. Mais puisque vous insistez, voici deux petits exemples qui devraient répondre à votre question.

Nous voulons les 20 premiers éléments de la suite de Fibonnacci :

n <- 20

# Vecteur vide (NA) de longueur n:
res <- rep(NA, n)

# On colle des 1 dans les 2 premiers items :
res[1:2] <- 1

# Boucle *for* -- Pour chaque valeur de i, de 3 à n
for(i in 3:n) {
 # res, position i est égal à :
 # res, position i-2 plus
 # res, position i-1
 res[i] <- res[i-2]+res[i-1]
}

Notez qu'en utilisant la formule de Binet :

phi <- (1+sqrt(5))/2
n <- 1:20
res <- (phi^n-(1-phi)^n)/sqrt(5)

Avec le vecteur res trouvé précédemment, on cherche n tel que la somme des éléments de res de 1 à n soit la plus grande possible mais inférieure à 1000 :

i <- 1
somme <- res[i]
# Boucle *while* -- Tant que somme < 1000
while(somme < 1000) {
 # On incrémente i de 1 :
 i <- i+1
 # On calcule la somme de res de la
 # position 1 à la position i :
 somme <- sum(res[1:i])
}
n <- i-1

Mais sous R, on préférera :

max(which(cumsum(res) < 1000))

Je m’arrête ici. Je posterai de temps en temps des petits challenges pour celles et ceux qui veulent s’exercer.

Aucun commentaire:

Enregistrer un commentaire

Monty Hall sans maths

Règle du jeu : on va vous proposer 3 enveloppes dont deux sont vides et une contient un billet de €100. Dans un deuxième temps, l’organisate...