-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathBrief and Deep Introduction.Rmd
464 lines (341 loc) · 10.6 KB
/
Brief and Deep Introduction.Rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
---
title: "R: A Deep and Brief Introduction"
author: "Dr. Pierre Balayé"
date: "22/11/2020"
output: rmdformats::material
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE, eval = FALSE)
```
# REPL
Dans RStudio, vous trouverez la console. Elle se matérialise par une ligne
commançant par un chevron `>` et qui attend que vous frappiez quelque chose au
clavier. C'est une boucle qui fonctionne ainsi :
+ Read
+ Eval
+ Print
On l'appelle donc la Read-Eval-Print Loop (REPL).
Elle lit ce que vous tapez, l'évalue et affiche le résultat.
Vous pouvez utiliser la console comme une calculatrice :
```{r}
> 3 + 4
[1] 7
```
Le `[1]` signifie que le résultat est un vecteur et que l'élément qui débute la
ligne (ici `7`) est le premier.
Nous reviendrons sur cette notion de vecteur. C'est un objet qui contient
plusieurs éléments du même type.
Pour comprendre la notation `[1]` examinez la variable `letters` qui est un vecteur
de 26 éléments.
```{r}
> letters
[1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s" "t" "u" "v" "w" "x" "y"
[26] "z"
```
Une variable est un symbole qui associe un nom à une valeur. La variable `letters` est associée
aux lettres de l'alphabet en minuscules.
Pour définir une variable dans **R** on utilise l'opérateur d'assignement `<-`.
Attention il est constitué de 2 caractères `<` et `-`.
```{r}
> total <- 3 + 4 + 8 + 9
```
L'assignememt est une opération silencieuse. La REPL n'affiche donc rien.
Cependant, vous pouvez afficher la valeur de total en lui demandant d'évaluer la
variable :
```{r}
> total
[1] 24
```
Vous pouvez également parenthèser l'assignement. Cela peut être utile pour vérifier la bonne
marche de vos programmes.
```{r}
> (total <- 3 + 4 + 8 + 9)
[1] 24
```
Dans **R** on peut utiliser (et définir) des fonctions. Pour cela on utilise des
parenthèses. Utilisez la fonction `sin` et la variable prédéfinie `pi` pour calculer
$\sin\dfrac{\pi}{4}$.
Vous pouvez obtenir de l'aide sur une fonction en utlisant la fonction `help`.
```{r}
> help(sin)
```
Parcourez cette aide pour trouver quelle fonction s'apparente à la fonction mathématque $x\to\arctan(x)$.
Consultez l'aide de la fonction `sqrt` puis vérifiez que $\sin\dfrac{\pi}{4}=\dfrac{\sqrt{2}}{2}$.
# Fichiers de scripts
Un fichier de script **R** un fichier de texte dont le nom est de la forme `un_script.R`.
C'est-à-dire que l'extension est de la forme `.R`.
Créez un nouveau fichier de script et sauvegardez le (`<CTRL>+<SHIFT>+N` puis `<CTRL>+S`).
Dedans, insérez les instructions suivantes.
```{r}
x <- sin(pi/4)
y <- sqrt(2)/2
x - y
```
En plaçant le curseur au niveau de chacune des lignes vous les envoyer se faire evaluer vers la console en utilisant `<CTRL>+<ENTER>`.
Les algorithmes associés aux fonctions `sin` et `sqrt` ainsi que la précision limitée de la partie décimale des nombres en machine fait que les variables `x` et `y` ont des valeurs légerement différentes et R.
Une remarque le test logique pour vérifier si $x$ et $y$ sont égaux s'écrit ainsi `==`.
```{r}
> x == y
[1] FALSE
```
Un seul signe égal `=` équivaut à l'assignement `<-` ! Tentez de comprendre ce qui se passe ici :
```{r}
> x = y
> x == y
[1] TRUE
```
Pour executer l'ensemble d'un script vous pouvez le `source`. Placez vous quelque part dans le script créé précedemment puis faîtes `<CTRL>+<SHIFT>+S`.
Vous pouvez retester l'égalité entre $x$ et $y$ pour vous convaincre que le script a bien été executé. Vous pouvez faire `<CTRL>+<SHIFT>+<ENTER>` pour voir une exécution avec affichage de toutes les évaluations sur la console.
# Packages
Un ensemble de fonctions utiles autour d'un même sujet sont regroupées en package.
Un package doit être tout d'abord installé sur votre ordinateur. **R** utilise un dépot de packages officiels abrités par le (https://cran.r-project.org/web/packages/index.html). Depuis la console, vous pouvez directement installer un package.
```{r}
> install.packages("lobstr")
```
Le package `lobstr` sert à examiner le détail des structures de données.
Installez les packages suivants :
+ Le package `rlang` donne des outils de métaprogrammation.
+ Le package `purrr` donne des outils de programmation fonctionnelle.
Si l'installation d'un package n'est à faire qu'une seule fois par machine, pour utiliser un package, il faudra le charger en mémoire au début de chaque session **R**. Au début d'un script, vous devez ajouter :
```{r}
library(purrr)
library(rlang)
library(lobstr)
```
pour utiliser ces packages dans votre code.
La fonction `help` permet d'accèder à la documentation de ces packages.
# Vecteurs
Les vecteurs sont une suite d'objets de même type.
Les 4 types de bases sont :
+ logical
+ integer
+ numeric
+ character
Pour créer un vecteur on utilise la fonction `c` :
```{r}
(booleens <- c(TRUE, FALSE, TRUE))
(entiers <- c(5L, 7L, 9L))
(decimaux <- c(1, pi, sqrt(2)))
(chaines <- c("A", "asdf", "Elle a dit \"incroyable\""))
```
Pour accèder aux éléments d'un vecteur on utilise les crochets. On peut donner une position ou un vecteur de positions :
```{r}
> booleens[1]
[1] TRUE
> entiers[c(3, 1)]
[1] 9 5
> decimaux[-3]
[1] 1.000000 3.141593
> cat(chaines[-c(1, 2)])
Elle a dit "incroyable"
```
On peut même utiliser un vecteur de booléens :
```{r}
> decimaux[booleens]
[1] 1.000000 1.414214
```
Si vous modifiez un élément d'un vecteur avec un élément d'un type différent, il y aura une conversion de type de l'élément si c'est possible et sinon du vecteur. Examinez les exemples suivants :
```{r}
> booleens[3] <- 7L
> booleens
[1] 1 0 7
> booleens[1] <- "RADS"
> booleens
[1] "RADS" "0" "7"
```
# Copy on modify (vector)
Lorsque vous modifiez un vecteur il est copié à une nouvelle adresse mémoire. Ce procédé hérité d'une logique de programmation fonctionnelle est à connaitre si vous voulez écrire des programmes **R** dont les performances restent acceptables.
Nous allons utiliser la fonction `ref` du package `lobstr`. Elle permet d'examiner l'adresse mémoire à laquelle est sotckée la valeur associée à une variable.
```{r}
> (x <- 5:10)
[1] 5 6 7 8 9 10
> lobstr::ref(x)
[1:0x18b448c6378] <int>
> x[1] <- 3L
> lobstr::ref(x)
[1:0x18b46655d30] <int>
```
Dans cet exemple, vous voyez que l'adresse de `x` a été modifée. En fait, une copie a été réalisée.
Examinons ce qu'il se passe quand vous copiez le contenu d'une variable dans une autre variable :
```{r}
> library(lobstr)
> (x <- 5:10)
[1] 5 6 7 8 9 10
> (y <- x)
[1] 5 6 7 8 9 10
> ref(x)
[1:0x18b461e2518] <int>
> ref(y)
[1:0x18b461e2518] <int>
> y[1] <- 3L
> ref(x)
[1:0x18b461e2518] <int>
> ref(y)
[1:0x18b45ac4f98] <int>
```
C'est seulement quand vous modifiez `y` que la copie est réalisée.
# Matrices
Pour créer une matrice nous allons utiliser une fonction dont les paramètres sont nommés. Examinez l'aide de la fonction `matrix`.
```{r}
> (m <- matrix(data = 1:12, ncol = 3))
[,1] [,2] [,3]
[1,] 1 5 9
[2,] 2 6 10
[3,] 3 7 11
[4,] 4 8 12
```
Pour accèder aux éléments d'une matrice, on utilise encore les crochets :
```{r}
> m[4, 2]
[1] 8
```
On peut aussi utiliser des vecteurs d'entiers et de booléens :
```{r}
> m[c(TRUE, FALSE, TRUE, FALSE), -2]
[,1] [,2]
[1,] 1 9
[2,] 3 11
```
En fait une matrice est un vecteur possédant un attribut `dim`.
```{r}
> attributes(m)
$dim
[1] 4 3
```
Vous pouvez modifier un attribut de la manière suivante :
```{r}
> attr(m, "dim") <- c(3, 4)
> m
[,1] [,2] [,3] [,4]
[1,] 1 4 7 10
[2,] 2 5 8 11
[3,] 3 6 9 12
```
# Listes
Les listes ont l'avantage que ses éléments ne sont pas forcément du même type, contrairement aux vecteurs.
Pour créer un vecteur on utilise la fonction `list` :
```{r}
> maliste <- list(c("A","B","C","A"),matrix(1:4),1,2L, "D")
> maliste
[[1]]
[1] "A" "B" "C" "A"
[[2]]
[,1]
[1,] 1
[2,] 2
[3,] 3
[4,] 4
[[3]]
[1] 1
[[4]]
[1] 2
[[5]]
[1] "D"
```
On peut connaître sa longueur à l'aide de `length` :
```{r}
> length(maliste)
[1] 5
```
On peut vérifier si un objet est une liste à l'aide de `is.list` :
```{r}
> is.list(maliste)
[1] TRUE
```
On peut concatener deux listes ainsi:
```{r}
> c(list(1,4),list(2))
[[1]]
[1] 1
[[2]]
[1] 4
[[3]]
[1] 2
```
# Data frame
Liste nommée de vecteurs de même longueur.
Pour mieux appréhender les "data frame", on peut considérer cet exemple:
```{r}
df <- mtcars
df$cyl[1] <-12
```
Considérons:
```{r}
df$cyl
```
qui permet "d'extraire" la colonne cyl de `df`. L'opération suivante:
```{r}
df$cyl[1] <-12
```
permet de modifier le premier élément de `df$cyl`.
Notez que cela modifie également `df`.
# Call by value
# Metaprogramming
```{r}
library(purrr)
library(rlang)
X_1 = 3
X_2 = 4
X_3 = 5
my_sum <- function(prefix, min, max) {
prefix <- enexpr(prefix)
var_names <- paste0(prefix, "_", min:max)
values <- map_dbl(var_names, function(name) get(name))
sum(values)
}
my_sum(X, min = 1, max = 3)
```
# Copy on modify (data.frame)
```{r}
> ref(mtcars)
> mtcars$cyl[1] <- 12
> ref(mtcars)
```
À l'éxecution de ces lignes on peut voir que seule la colonne `mpg` a son adresse modifiée.
Cela pose un problème puisque si on veut modifier une ligne du "data frame": il y a aura autant de copie que de ligne.
À la section suivante, on se propose de contourner ce problème.
# Le package data.table
Dans cette partie nous allons utiliser:
```{r}
library(lobstr)
library(data.table)
library(microbenchmark)
```
Cette instruction permet de réinitialiser `mtcars`:
```{r}
data(mtcars)
```
Comme vu précédement il y a modification de l'adresse de `mtcars$cyl`:
```{r}
data(mtcars)
ref(mtcars)
mtcars$cyl[1] <- 12
ref(mtcars)
```
Ici il n'y a pas modification de l'adresse: on utilise le paquet `data.table`:
```{r}
data(mtcars)
df <- as.data.table(mtcars)
ref(df)
df[1, cyl := 12]
ref(df)
```
```{r}
data(mtcars)
X <- mtcars
Y <- as.data.table(mtcars)
# on effectue une centaine d'opérations pour comparer
foo_trad <- function() {
for(i in 1:100) X[1,1] <- i
}
foo_data.table <- function() {
for(i in 1:100) Y[1, mpg := i]
}
microbenchmark(foo_trad(),foo_data.table())
```
En testant cela, et en faisant changeant 100 pour 1000, on voit que l'utilisation du package data.table a un coût de base, mais pour un grand nombre d'opération, on a un gain de temps.
Il faut noter que l'utilisation de data.table n'est pas standard, elle n'est pas présente par défaut dans R.
# Microbenchmark
Nous allons utiliser le package `microbenchmark`.
Il vous faut l'installer, puis le charger en début de session.
On peut voir un exemple d'utilisation dans la partie précédente.