-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy path06-Donnees-qualitatives.Rmd
executable file
·808 lines (578 loc) · 52.9 KB
/
06-Donnees-qualitatives.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
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
# Traitement des données II {#qualit}
```{r setup, include=FALSE, echo=FALSE, message=FALSE, results='hide'}
SciViews::R
```
##### Objectifs {.unnumbered}
- Comprendre les principaux tableaux de données utilisés en science des données
- Pouvoir réaliser des tableaux de contingences
- Acquérir des données et les encoder correctement et de manière à ce que les analyses soient reproductibles
- Être capable de remanier des tableaux de données et de fusionner plusieurs tableaux
##### Prérequis {.unnumbered}
Ce module est la continuation du module \@ref(import) dont le contenu doit être bien compris et maîtrisé avant de poursuivre ici.
## Tableaux de données
Les tableaux de données sont principalement représentés sous deux formes : les tableaux **cas par variables** et les tableaux de **contingence**.
### Tableaux cas par variables
Chaque individu est représenté en ligne et chaque variable en colonne par convention. En anglais, on parlera de [tidy data](https://www.jstatsoft.org/article/view/v059i10).
Nous nous efforcerons de toujours créer un tableau de ce type pour les données brutes. La question à se poser est la suivante : est-ce que j'ai un seul et même individu représenté sur *chaque* ligne du tableau ? Si la réponse est non, le tableau de données n'est **pas** correctement encodé.
##### À vous de jouer ! {.unnumbered}
*Considérez les données suivantes concernant la taille adulte mesurée en cm pour deux espèces de petits rongeurs :*
`r h5p(47, height = 270, toc = "Tableau cas par variables 1")`
```{=html}
<!----
| hamster | cobaye |
|:---------|:--------|
| 15,4 | 21,7 |
| 18,2 | 22,0 |
| 17,6 | 24,3 |
| 14,2 | 23,9 |
| 16,8 | |
Nous notons immédiatement que ce *n'est pas* un tableau correctement présenté en cas par variable. En effet, un même individu ne peut appartenir simultanément aux hamsters et aux cobayes. Il s'agit forcément d'individus différents mesurés. Nous n'avons donc pas respecté ici la règle de "une ligne = un individu". D'ailleurs, nous avons plus de hamsters mesurés ici que de cobayes, ce qui se marque par un déséquilibre dans le remplissage du tableau... qui doit aussi être un signal d'alarme (à moins qu'il n'y ait des valeurs manquantes).
----->
```
*Considérez ce second tableau de données concernant également la taille adulte mesurée en cm de deux espèces de petits rongeurs :*
`r h5p(48, height = 270, toc = "Tableau cas par variables 2")`
```{=html}
<!----
Une présentation correcte de ces données consiste à utiliser une colonne "taille" et une seconde "espèce" pour indiquer toutes les caractéristiques pertinentes dans le cadre de l'étude tout en respectant les conventions d'un tableau cas par variables. Cela donne\ :
| espèce | taille |
|:--------|:---------|
| hamster | 15,4 |
| hamster | 18,2 |
| hamster | 17,6 |
| hamster | 14,2 |
| hamster | 16,8 |
| cobaye | 21,7 |
| cobaye | 22,0 |
| cobaye | 24,3 |
| cobaye | 23,9 |
Ce dernier tableau est moins compact et plus "verbeux" que le présenter (il faut répéter "hamster" ou "cobaye" plusieurs fois dans la première colonne). Pour cette raison, un novice ou un encodeur ignorant les règles élémentaires des sciences des données est souvent amené, de bonne fois, à adopter la présentation qui semble la plus compacte, **mais ce n'est pas toujours la plus pertinente\ !** Heureusement, dons R le outils existent pour passer d'une forme à l'autre facilement.
---->
```
*Considérez maintenant ce troisième exemple fictif avec le résultat d'un test enregistré avant et après un traitement censé améliorer le résultat du test :*
`r h5p(49, height = 270, toc = "Tableau cas par variables 3")`
`r h5p(50, height = 270, toc = "Tableau cas par variables 4")`
```{=html}
<!----
| individu | résultat |
|:-----------------|:-----------|
| individu 1 avant | 10,3 |
| individu 1 après | 12,5 |
| individu 2 avant | 11,6 |
| individu 2 après | 12,4 |
| individu 3 avant | 10,8 |
| individu 3 après | 10,6 |
Ici, les labels utilisés dans la colonne "individu" suggère que l'expérience à été menée avant et après à chaque fois sur le même individu. Ainsi, le tableau a 6 lignes, mais ne représente que 3 individus. Ici encore, le tableau est mal encodé. Il aurait fallu considérer une et une seule ligne par individu et reporter les résultats "avant" et "après" le traitement dans des *colonnes différentes*. Voici ces mêmes données présentées correctement selon un tableau cas par variables\ :
| avant | après |
|:-------|:------|
| 10,3 | 12,5 |
| 11,6 | 12,4 |
| 10,8 | 10,6 |
--->
```
```{block, type='note'}
Avant toute analyse, vérifier le type de tableau de données que vous avez à disposition. Le point de départ le plus courant et le plus sûr est le **tableau cas par variables**. Rappellez-vous bien que la question à se poser pour vérifier si le tableau est bien présenté est : "a-t-on une et une seule ligne dans le tableau pour chaque individu ?" Si ce n'est pas le cas, il faut remanier le tableau avant de commencer son analyse.
```
Les tableaux de données que vous avez traités jusqu'à présent étaient tous des tableaux **cas par variables**. Chaque ligne représentait un *individu* sur qui une ou plusieurs *variables* (en colonnes) étaient mesurées.
```{r}
biometry <- read("biometry", package = "BioDataScience", lang = "fr")
head(biometry)
```
L'encodage d'un petit tableau cas par variables directement dans R est facile. Cela peut se faire de plusieurs façons différentes. En voici deux utilisant les fonctions `dtx()` (spécification colonne par colonne) et `dtx_rows()` (spécification ligne par ligne) :
```{r}
# Spécification colonne par colonne avec dtx()
(df1 <- dtx(
x = c(1, 2),
y = c(3, 4)
))
```
```{r}
# Spécification ligne par ligne avec dtx_rows()
(df2 <- dtx_rows(
~x, ~y,
1, 3,
2, 4
))
```
La seconde approche est plus naturelle, mais la première permet d'utiliser diverses fonctions de R pour faciliter l'encodage, par exemple :
- Séquence d'entiers successifs :
```{r}
1:10
```
- Répétition d'un vecteur cinq fois (le "L" après 5 indique que c'est un entier, mais il est ici facultatif) :
```{r}
rep(c("a", "b", "c"), 5L)
```
- Répétition de chaque item d'un vecteur cinq fois :
```{r}
rep(c("a", "b", "c"), each = 5L)
```
Pour de plus gros tableaux, il vaut mieux utiliser un tableur tel qu'Excel ou LibreOffice Calc pour l'encodage. Les tableurs en ligne comme Google Sheets ou Excel Online conviennent très bien également et facilitent un travail collaboratif ainsi que la mise à disposition sur Internet, comme nous avons vu au module \@ref(import).
### Tableau de contingence
Le tableau cas par variables n'est toutefois pas la seule représentation (correcte) possible des données. Un **tableau de contingence** représente de manière bien plus compacte le dénombrement de l'occurrence de chaque niveau d'une (tableau à une entrée) ou de deux variables **qualitatives** (tableau à double entrée).
##### À vous de jouer ! {.unnumbered}
`r h5p(52, height = 270, toc = "Tableau de contingence")`
La fonction `table()` crée ces deux types de tableaux de contingence à partir de données encodées en tableau cas par variables :
```{r}
biometry$age_rec <- cut(biometry$age, include.lowest = FALSE, right = TRUE,
breaks = c(14, 27, 90))
(bio_tab <- table(biometry$gender, biometry$age_rec))
```
##### À vous de jouer ! {.unnumbered}
`r h5p(51, height = 270, toc = "Tableau de contingence dans R")`
Le tableau de contingence peut toujours être calculé à partir d'un tableau cas par variable, mais il peut également être encodé directement si nécessaire. Voici un petit tableau de contingence à simple entrée encodé directement comme tel (vecteur nommé transformé en objet `table` à l'aide de la fonction `as.table()`) :
```{r}
anthirrhinum <- as.table(c(
"fleur rouge" = 54,
"fleur rose" = 122,
"fleur blanche" = 58)
)
anthirrhinum
```
Une troisième possibilité est d'utiliser un tableau indiquant les **fréquences d'occurrences** dans une colonne (`freq` ci-dessous). Ce n'est **pas** un tableau cas par variables, mais une forme bien plus concise et pratique pour préencoder les données qui devront être ensuite transformées en tableau de contingence en utilisant cette fois-ci `xtabs()`. Voici un exemple pour un tableau de contingence à double entrée. Notez que le tableau cas par variable correspondant devrait contenir 44 + 116 + 19 + 128 = 307 lignes et serait plus fastidieux à construire et à manipuler (même en utilisant la fonction `rep()`).
```{r}
timolol <- dtx(
traitement = c("timolol", "timolol", "placebo", "placebo"),
patient = c("sain", "malade", "sain", "malade"),
freq = c(44, 116, 19, 128)
)
# Création du tableau de contingence
timolol_table <- xtabs(data = timolol, freq ~ patient + traitement)
timolol_table
```
La sortie par défaut d'un tableau de contingence n'est pas très esthétique, mais plusieurs options existent pour le formater d'une façon agréable. En voici deux exemples :
```{r}
pander::pander(timolol_table,
caption = "Exemple de table de contingence à double entrée.")
```
```{r}
knitr::kable(timolol_table,
caption = "Exemple de table de contingence à double entrée.")
```
Il est même possible de représenter *graphiquement* un tableau de contingence pour l'inclure dans une figure composée, éventuellement en le mélangeant avec des graphiques[^06-donnees-qualitatives-1].
[^06-donnees-qualitatives-1]: Utilisez cette option avec parcimonie. Il vaut toujours mieux représenter un tableau comme ... un tableau plutôt que comme une figure !
```{r}
tab1 <- ggpubr::ggtexttable(head(biometry), rows = NULL)
tab2 <- ggpubr::ggtexttable(table(biometry$gender, biometry$age_rec))
combine_charts(list(tab1, tab2), nrow = 2)
```
Différentes fonctions dans R existent également pour convertir un tableau de contingence en tableau cas par variables (ou en tous cas, en un tableau similaire). Par exemple, `as_dtx()` renvoie un tableau indiquant les fréquences d'occurrences dans une colonne nommée `N` :
```{r}
(timolol2 <- as_dtx(timolol_table))
```
Si vous insistez, vous pouvez aussi obtenir un tableau cas par variables (mais celui-ci est très long et peu pratique à manipuler) à l'aide de la fonction "speedy" `suncount()` (ou la fonction "tidy" `uncount()`)[^06-donnees-qualitatives-2] :
[^06-donnees-qualitatives-2]: Notez également que passer d'un tableau cas par variables à un tableau des fréquences d'occurrences se fait à l'aide de `scount()` ou `count()`.
```{r}
suncount(timolol2, N)
```
### Métadonnées
Les données dans un tableau doivent **impérativement** être associées à un ensemble de métadonnées. Les métadonnées (*metadata* en anglais) apportent des informations complémentaires nécessaires pour une interprétation correcte des données. Elles permettent donc de replacer les données dans leur contexte et de spécifier des caractéristiques liées aux mesures réalisées comme les unités de mesure par exemple.
> Données de qualité = tableau de données + métadonnées
Les données correctement qualifiées et documentées sont les seules qui peuvent être utilisées par un collaborateur externe. C'est-à-dire qu'une personne externe à l'expérience ne peut interpréter le tableau de données que si les métadonnées sont complètes et explicites.
Exemple de métadonnées :
- Unités de mesure (exemple : 3,5 mL, 21,2 °C)
- Précision de la mesure (21,2 +/- 0,2 dans le cas d'un thermomètre gradué tous les 0,2 °C)
- Méthode de mesure utilisée (thermomètre à mercure, ou électronique, ou ...)
- Type d'instrument employé (marque et modèle du thermomètre par exemple)
- Date de la mesure (si pas encodée directement dans le tableau)
- Nom du projet lié à la prise de mesure
- Nom de l'opérateur en charge de la mesure
- ...
Vous avez pu vous apercevoir que la fonction `read()` permet d'ajouter certaines métadonnées comme les unités aux variables d'un jeu de données. Cependant, il n'est pas toujours possible de rajouter les métadonnées dans un tableau sous forme électronique, mais il faut toujours les consigner dans un **cahier de laboratoire**, et ensuite les **retranscrire dans le rapport**. La fonction `labelise()` vous permet de rajouter le **label** et les **unités** de mesure pour vos différentes variables directement dans le tableau. Par exemple, voici l'encodage direct d'un petit jeu de données qui mesure la distance du saut (`jump`) en cm de grenouilles taureaux en fonction de leur masse (`weight`) en g pour cinq individus différents (`ind`). Vous pouvez annoter ce data frame de la façon suivante :
```{r}
frog <- dtx_rows(
~ind, ~jump, ~weight,
1, 71, 204,
2, 70, 240,
3, 100, 296,
4, 120, 303,
5, 103, 422
)
# Ajout des labels et des unités
frog <- labelise(frog,
label = list(
ind = "Individu",
jump = "Distance du saut",
weight = "Masse"),
units = list(
jump = "cm",
weight = "g")
)
# Affichage synthétique des données et métadonnées associées
str(frog)
# Affichage des labels
label(frog)
```
Les métadonnées sont enregistrées dans des **attributs** en R (`attr`). De même, `comment()` permet d'associer ou de récupérer un attribut commentaire (notez comment assigner une chaîne de caractères à `comment()` ajoute ou modifie le commentaire de l'objet, tableau entier ou variable du tableau :
```{r}
# Ajout d'un commentaire concernant le jeu de données lui-même
comment(frog) <- "Saut de grenouilles taureaux"
# Ajout d'un commentaire sur une variable
comment(frog$jump) <- "Premier saut mesuré après stimulation de l'animal"
# Affichage synthétique
str(frog)
# Récupération des commentaires
comment(frog)
comment(frog$jump)
comment(frog$weight) # Rien!
```
### Dictionnaire des données
Le dictionnaire des données est un [élément important de la constitution d'une base de données](https://ineumann.developpez.com/tutoriels/merise/initiation-merise/#LII-B). Il s'agit d'un tableau annexe qui reprend le **nom** de chaque variable, son **label** (nom plus long et explicite), ses **unités** éventuelles, son **type** (numérique, facteur, facteur ordonné, date, ...), la façon dont les **valeurs manquantes** sont encodées, et un **commentaire** éventuel. Dans notre contexte, il est également utile de renseigner les **unités** de mesure, et la façon dont les **données manquantes** sont encodées. Cela donne donc un tableau du genre :
| Variable | Label | Unités | Type | Niveaux | Val. manquantes | Commentaire |
|:---------|:-----------------|:------:|:-------:|:-------------:|:---------------:|:---------------------------------------------------------|
| date | Date | \- | Date | | NA | Date de mesure |
| age | Âge | années | numeric | | -1 | |
| diameter | Diamètre du test | mm | numeric | | NA | Moyenne de deux diamètres perpendiculaires |
| origin | Origine | \- | factor | Fishery, Farm | unknown | "Fishery" = oursins sauvages, "Farm" = oursins d'élevage |
Ce tableau peut-être encodé sous forme textuelle et placé dans le même dossier que le jeu de données lui-même. Il peut aussi être encodé comme feuille supplémentaire dans un fichier Excel.
```{block, type='note'}
Le dictionnaire des données est un outil important pour comprendre ce que contient le tableau de données, et donc, son interprétation. *Ne le négligez pas !*
```
##### À vous de jouer ! {.unnumbered}
`r h5p(53, height = 270, toc = "Données et métadonnées")`
## Population et échantillonnage
Nos analyses statistiques seraient bien évidemment beaucoup plus simples si nous pouvions toujours mesurer tous les individus concernés par nos études. En fait, c'est presque toujours impossible, car les **populations** concernées sont souvent très larges, voire infinies. Nous devons donc mesurer un petit sous-ensemble de la population, ce que nous appelons un **échantillon** (*sample* en anglais) de taille finie déterminée (on parle de la **taille de l'échantillon** ou *sample size* en anglais). Le processus qui mène à la sélection des individus dans l'échantillon s'appelle l'**échantillonnage** (*sampling* en anglais). De cet échantillon, nous souhaitons malgré tout retirer un maximum d'information concernant la population d'origine. Cela s'appelle faire de l'**inférence** sur la population à partir de l'échantillon (*to infer* en anglais).
![Population et échantillon.](images/sdd1_06/pop_sample.png)
```{block, type='warning'}
Faites attention à la signification des termes selon les disciplines. Par exemple, le terme **population** ne signifie pas la même chose pour un biologiste (ensemble des individus d'une même espèce pouvant se reproduire entre eux) et pour un statisticien (ensemble des valeurs que peut prendre une variable). Ainsi, la définition statistique du terme se réfère à un bien plus grand sous-ensemble en général. Par exemple, si nous étudions la souris *Mus musculus*, nous considérerons bien évidemment une population (ou une souche donnée pour les souris de laboratoire) en qualité de biologistes. Les statisticiens considéreront l'ensemble des souris qui existent, ont existé et existeront à l'avenir comme **la** population de souris.
De même, un **individu** statistique est une entité sur laquelle nous effectuons nos mesures (ce qui donne lieu à une **observation** pour chaque **variable**). Ainsi, un individu statistique peut correspondre ou non à un individu biologique selon ce que l'on considère. Par exemple, une section dans un organe peut constituer un individu statistique lors de l'étude de l'hétérogénéité à l'intérieur de cet organe. Nous aurons donc autant d'individus statistiques que de sites de prélèvement sur l'organe, ... même si ce dernier provient au final du même individu biologique (même animal ou végétal) !
```
La **variabilité** tant au niveau de la population que de l'échantillon provient essentiellement de deux facteurs :
1. La **variabilité individuelle** inhérente (nous n'avons pas tous la même taille ni la même masse, par exemple),
2. Les **erreurs de mesure**.
Ces deux facteurs se cumulent pour contribuer à disperser les valeurs d'un individu à l'autre. Nous n'avons que peu de prise sur la variabilité individuelle, mais nous pouvons parfois réduire les erreurs de mesure si cela s'avère souhaitable en utilisant un appareil de mesure plus précis, par exemple. Quoi qu'il en soit, plus la variabilité est importante, plus la taille de l'échantillon devra également être grande pour conserver une bonne "représentativité" de la population.
Du point de vue de la notation mathématique, nous utiliserons une lettre latine majuscule en italique pour représenter une variable, par exemple, *X*. La taille de l'échantillon est souvent notée *n*. Les observations individuelles de la variable *x* pour les *n* individus de l'échantillon seront alors notées avec une lettre minuscule en italique assortie d'un indice compris entre 1 et *n*, donc, *x~i~* de manière générale avec l'indice *i* variant de 1 à *n*. Ainsi, *x*~5~ représente la cinquième observation pour la variable *X* dans notre échantillon, et *x~n~* est la dernière observation.
### Échantillonnage aléatoire
La démarche du statisticien et du scientifique des données est de retirer un maximum d'information d'un échantillon afin de faire des inférences fiables sur la population tout entière (c'est-à-dire, tenter de tirer des conclusions les plus générales possibles à partir de l'étude d'un petit échantillon seulement). Ceci n'est possible que si l'échantillon "est conforme" à la population. En langage statistique on dit que l'**échantillon est représentatif**.
Un échantillon représentatif n'est pas facile à obtenir et il faut respecter scrupuleusement certaines règles pour l'obtenir. *A contrario* un échantillon **non** représentatif s'obtient sans précautions particulières, mais ce dernier est quasi toujours totalement inutile (on ne peut tirer de conclusions *que* sur cet échantillon particulier). Imaginez un soudage qui ne représente pas la population sondée... quel est son intérêt ? Il est nul !
La meilleure façon d'obtenir un échantillon représentatif est de réaliser un **échantillonnage aléatoire**. Dans ce cas, chaque individu de la population doit avoir la même chance d'être sélectionné dans l'échantillon. Nous parlons aussi d'échantillonnage au hasard. Vous devez bien réfléchir au **processus** qui va mener à la sélection des individus dans l'échantillon. Celui-ci doit comporter une étape qui fait intervenir le hasard.
```{block, type='error'}
"Choisir au hasard" ses individus en les prélevant au petit bonheur la chance en fonction de son humeur n'est **pas** une bonne approche. En effet, notre main qui saisira les individus à inclure dans l'échantillon aura tendance à prélever ceux qui sont plus facile à attraper ou plus proches, par exemple. Il peut s'agir d'individus moins vigoureux, moins réactifs, ou au contraire, moins peureux... Du coup, nous n'étudierions qu'une fraction de la population qui correspond à une caractéristique particulière (ceux qui sont faibles et peu réactifs, par exemple)
Une bonne sélection aléatoire **doit** faire intervenir le hasard (tirage au sort dans une urne, pile ou face, jet de dés, ou génération de nombres dits "pseudo-aléatoires" à l'aide d'un ordinateur). Par exemple, si vous avez un élevage de souris dans votre laboratoire, et que vous considérez cet élevage comme votre population, vous pouvez réaliser deux groupes (témoin et traitement) de cinq souris chacun de plusieurs façons :
1. Prendre dix souris dans les cages "au hasard", et les répartir toujours "au hasard" entre les deux groupes. Ce type d'échantillonnage est **incorrect**. En effet, votre choix sera (inconsciemment) conditionné.
2. Donner un identifiant numérique unique à chacune de vos souris. Ensuite tirer deux fois cinq identifiants à partir d'une urne, ou effectuer ce même traitement virtuellement à l'aide d'un ordinateur. Dans ce cas, l'échantillonnage sera réellement aléatoire et correctement réalisé !
```
En pratique, nous pourrons utiliser la fonction `sample()` dans R. Elle permet de simuler facilement et rapidement le processus de tirage au hasard depuis une urne. Dans le cas de nos deux groupes de cinq souris à partir d'un élevage qui contient 213 animaux numérotés de 1 à 213 (identifiants uniques), nous ferons :
```{r, echo=FALSE, results='hide'}
set.seed(67567)
```
```{r}
# Échantillon de 5 souris témoins
sample(1:213, size = 5)
# Échantillon de cinq souris pour le traitement
sample(1:213, size = 5)
```
Ici, la sélection aléatoire (en réalité, on parle de "pseudo-aléatoire" pour ces nombres générés par un algorithme, mais qui ont des propriétés très similaires au hasard pur) nous indique que nous devrons aller chercher les souris n°15, 12, 102, 136 et 42 dans notre élevage pour notre groupe témoin, et les souris n°187, 108, 211, 68 et 49 pour le groupe traitement.
Dans le cas où un échantillonnage doit se faire **avec replacement** (l'équivalent de replacer une boule dans l'urne à chaque tirage au sort), nous pouvons indiquer l'argument `replace = TRUE` dans `sample()`. Donc, quelque chose comme `sample(0:9, size = 50, replace = TRUE)` pour échantillon les chiffres 0 à 9 au hasard cinquante fois avec remise (à chaque tirage chaque chiffre a même chance d'être tiré).
L'utilisation de `sample()` est pratique, mais cela rend le code **non reproductible**. En effet, à chaque fois, la fonction génère une série différente au hasard (c'est son rôle !) Toutefois, comme la série est pseudo-aléatoire, il est possible de régénérer la même série une seconde fois si on part du même point dans l'algorithme qui la calcule. Cela peut être réalisé à l'aide de `set.seed()`. Vous *devez* indiquer comme argument à cette dernière fonction un nombre aléatoire. Ce nombre représentera une position dans la séquence générée par l'algorithme de sorte que la série suivante obtenue à l'aide de `sample()` sera toujours la même. Voici comment cela fonctionne :
```{r}
set.seed(2563) # Utiliser un nombre différent à chaque appel de set.seed() !
sample(1:10, size = 6)
```
**Naturellement, chaque fois que vous insérez `set.seed()` dans votre code, vous devez indiquer un nombre différent, lui-même choisi au hasard.**
### Échantillonnage stratifié
L'échantillonnage aléatoire n'est pas la seule stratégie correcte. L'**échantillonnage stratifié** consiste à diviser la population en sous-populations identifiables facilement (par exemple, séparer la population en fonction du sexe, ou de l'âge, voire des deux simultanément). Ensuite, un échantillonnage aléatoire est réalisé à l'intérieur de chaque sous-population pour un nombre déterminé d'individus, souvent le même. Cette approche plus complexe est utile si les sous-populations sont **très mal balancées** (une sous-population possède bien plus d'individus qu'une autre).
Par exemple, vous voulez comparer des prélèvements sanguins faits sur une population d'Européens hospitalisés dans le but de déterminer les critères qui permettent de diagnostiquer une infection nosocomiale[^06-donnees-qualitatives-3] rare. Les individus sont suivis en hôpital par définition et nous admettrons que l'on sait *a priori* s'ils sont atteints de la maladie ou non grâce à d'autres tests plus lourds et coûteux. La maladie est rare, heureusement. Sa prévalence n'est que de 1 cas sur 10.000.
[^06-donnees-qualitatives-3]: Une infection nosocomiale est une infection contractée dans un hôpital.
Dans ce cas, si vous effectuez un échantillonnage aléatoire de 100 patients ou même de 1.000 patients hospitalisés, vous avez toutes les chances de ne pas inclure même un seul patient atteint de l'infection ! Ici l'échantillonnage stratifié est utile. Il consiste à séparer les patients en deux sous-populations : ceux qui sont atteints et les autres. Ensuite, vous décidez, par exemple, d'analyser 50 prélèvements sanguins dans chacune des deux sous-populations. Vous échantillonnez alors 50 patients aléatoirement comme nous l'avons fait plus haut pour nos souris, mais à l'intérieur de chaque sous-population. Au final, votre échantillon contiendra alors 50 patients infectés et 50 autres qui ne le sont pas. Cet échantillon est également représentatif (sauf, bien sûr, concernant la prévalence de l'infection).
## Acquisition de données
Dans le module \@ref(import), vous avez pris connaissance des types de variable et venez d'apprendre comment encoder différents types de tableaux de données et de leur associer les indispensables métadonnées. Cependant, la première étape avant d'acquérir des données est de planifier correctement son expérience. La Science des Données est intimement liée à la démarche scientifique et intervient dans toutes les étapes depuis la caractérisation de la question et le planning de l'expérience jusqu'à la diffusion des résultats. Plus en détail, cela correspond à :
- Définir une question (objectif)
- Réaliser une recherche bibliographique sur la thématique
- Définir le protocole de l'expérience à partir de l'objectif
- Définir la population étudiée et l'échantillonnage
- Définir les variables à mesurer
- Définir les unités des mesures
- Définir la précision des mesures
- Définir les instruments de mesure nécessaires
- Définir les conventions d'encodage
- Codifier l'identification des individus
- Définir les niveaux des variables facteurs et leurs labels
- Acquérir et encoder les données
- Traiter les données
- Importer des données
- Remanier des données
- Visualiser et décrire des données
- Analyser les données (traitements statistiques, modélisation...).
- Produire des supports de présentation répondant à la question de départ et diffuser l'information dans la communauté scientifique
Nous traitons ici des premières étapes qui visent à acquérir les données.
### Précision et exactitude
Les erreurs de mesures sont inévitables lors de l'acquisition de nos données. Cependant, il est possible de les minimiser en choisissant un instrument plus précis (*precise* en anglais) et plus exact (*accurate* en anglais). Ces deux notions sont différentes, mais complémentaires.
##### À vous de jouer ! {.unnumbered}
`r h5p(54, height = 270, toc = "Précision et exactitude")`
```{=html}
<!----
La figure ci-dessous illustre de manière visuelle la différence qu'il y a entre précision et exactitude.
![](images/sdd1_06/targets.png)
---->
```
### Codification des données
Afin d'éviter que divers collaborateurs encodent différemment la même information, vous allez devoir préciser très clairement comment encoder les différentes variables de votre jeu de données. Par exemple pour une variable `genre`, est-ce que vous indiquez `homme` ou `femme`, ou `h` / `f`, ou encore `H` / `F` ?
De même, vous allez devoir attribuer un code **unique** à chaque individu mesuré. Enfin, vous devez vous assurer que toutes les mesures sont réalisées de la même manière et avec des instruments qui, s'ils sont différents, seront cependant **intercalibrés**. Comment faire ? Réfléchissez à cette question sur base d'une mesure de la masse des individus à l'aide de pèse-personnes différents !
### Respect de la vie privée
Lors d'expérience sur des personnes, le respect de la vie privée **doit** être pris en compte[^06-donnees-qualitatives-4]. Le nom et le prénom, ou toute autre information permettant de retrouver les individus étudiés (adresse mail, numéro de sécurité sociale, etc.) **ne peuvent pas apparaître** dans la base de données consolidée. En outre, il vous faudra un **accord explicite** des personnes que vous voulez mesurer, et il faudra leur expliquer ce que vous faites, et **comment** les données seront ensuite utilisées. Une question se pose : comment pouvoir revenir vers les enregistrements liés à un individu en particulier (en cas d'erreur d'encodage, par exemple) si les informations relatives directement à ces individus ne sont pas consignées dans le tableau final ? Réfléchissez à la façon dont vous vous y prendriez avant de lire la suite...
[^06-donnees-qualitatives-4]: En Europe, les données numériques concernant les personnes sont soumises à des règles strictes édictées dans le [Règlement Général pour la Protection des Données](https://ec.europa.eu/info/law/law-topic/data-protection/reform/rules-business-and-organisations/principles-gdpr_fr) ou **RGPD** en abrégé, en vigueur depuis le 25 mai 2018. Vous devez vous assurer de respecter ce règlement lors de la collecte et de l'utilisation de données relatives à des personnes. Pour les autres types de données, le droit d'auteur ou des copyrights peuvent aussi limiter votre champ d'action. Renseignez-vous !
Voici un petit tableau qui correspond à ce que vous ne pourrez **pas faire** (nom et prénom explicitement mentionnés dans le tableau) :
```{r}
(biometry_marvel <- dtx_rows(
~id, ~gender, ~weight, ~height,
"Banner Bruce", "M", 95, 1.91,
"Stark Tonny", "M", 80, 1.79,
"Fury Nicholas", "M", 82, 1.93,
"Romanoff Natasha", "F", 53, 1.70
))
```
Vous devez fournir un code permettant de garder l'anonymat des sondés à l'ensemble des personnes étudiées vis-à-vis des analystes qui vont utiliser ces données. Cependant, le code doit permettre au chercheur ayant pris ces mesures de les retrouver dans son cahier de laboratoire, si besoin. Une façon de procéder consiste à attribuer un numéro au hasard par tirage dans une urne à chacune des personnes chargées des mesures. Ensuite, chaque expérimentateur attribue lui-même un second numéro aux différentes personnes qu'il mesure. Prenons par exemple le scientifique n°24 (seul lui sait qu'il porte ce numéro). Il attribue un code de 1 à *n* sous forme d'une lettre de l'alphabet à chaque personne étudiée. En combinant le code secret de l'expérimentateur et le code individu, cela donne un identifiant unique de la forme `24_A`, `24_B`, etc. Il pourra alors encoder sa partie comme suit :
```{r}
(biometry_marvel1 <- dtx_rows(
~id, ~gender, ~weight, ~height,
"24_A", "M", 95, 1.91,
"24_B", "M", 80, 1.79,
"24_C", "M", 82, 1.93,
"24_D", "F", 53, 1.70
))
```
Il garde néanmoins les correspondances dans son carnet de laboratoire, au cas où il faudrait faire des vérifications ou revenir à la donnée originale.
```{r}
(biometrie_correspondance <- dtx(
name = biometry_marvel$id,
id = biometry_marvel1$id
))
```
À partir des données du tableau général consolidé, personne à part lui ne peut revenir sur ces données d'origine et mettre un nom sur les individus mesurés. Et lui-même n'a pas la possibilité de déterminer *qui* se cache derrière les autres identifiants tels `03_A`, `12_C`, `21_B`, etc.
**Vous allez maintenant encoder et analyser vos données relatives à l'étude de l'obésité.**
```{r assign_A05Ga_biometry_II, echo=FALSE, results='asis'}
if (exists("assignment2"))
assignment2("A05Ga_biometry", part = "II",
url = "https://github.com/BioDataScience-Course/A05Ga_biometry",
course.ids = c(
'S-BIOG-006' = !"A05Ga_{YY}M_biometry"),
course.urls = c(
'S-BIOG-006' = "https://classroom.github.com/a/W6qHZvA3"),
course.starts = c(
'S-BIOG-006' = !"{W[12]+5} 10:00:00"),
course.ends = c(
'S-BIOG-006' = !"{W[14]+5} 23:59:59"),
term = "Q1", level = 4, n = 4,
toc = "Collecte de données relative à l'obésité")
```
## Recombinaison de tableaux
### Formats long et large
<!-- Newer versions (starting with svbox2020) propose pivot_long() and pivot_large() instead of spread() and gather() with a more intuitive syntax and arguments names, see: https://blog.methodsconsultants.com/posts/data-pivoting-with-tidyr/ => to be change later on ! -->
```{=html}
<!----
![`gather()` versus `spread()` par [gadenbuie](https://github.com/gadenbuie/tidyexplain/blob/master/images/tidyr-spread-gather.gif).](images/sdd1_06/tidyr-spread-gather.gif)
---->
```
Le **format long** d'un tableau de données correspond à un encodage en un minimum de colonnes, les données étant réparties sur un plus grand nombre de lignes en comparaison du **format large** qui regroupe les données dans plusieurs colonnes successives. Voici un exemple fictif d'un jeu de données au format long :
```{r, echo=FALSE}
dtx_rows(
~sex, ~traitment, ~value,
"m", "control", 1.2,
"f", "control", 3.4,
"m", "test1", 4.8,
"f", "test1", 3.1,
"m", "test2", 0.9,
"f", "test2", 1.2
)
```
Voici maintenant le même jeu de données présenté dans le format large :
```{r, echo=FALSE}
as_dtx(tribble(
~sex, ~control, ~test1, ~test2,
"m", 1.2, 4.8, 0.9,
"f", 3.4, 3.1, 1.2
))
```
Dans le format large, les différents niveaux de la variable facteur `treatment` deviennent autant de colonnes (donc de variables) séparées, et la variable d'origine n'existe plus de manière explicite. Ces deux tableaux contiennent la même information. Bien évidemment, un seul de ces formats est un *tableau cas par variables correct*. Le format long sera le bon si toutes les mesures sont réalisées sur des individus différents. Par contre, le format large sera correct, si les différentes mesures ont été faites à chaque fois sur les *mêmes* individus (dans le cas présent, *un seul* mâle et *une seule* femelle auraient alors été mesurés dans les trois situations).
```{block, type='note'}
C'est la règle qui veut qu'**une ligne corresponde à un et un seul individu** dans un tableau cas par variables qui permet de décider si le format long ou le format large est celui qui est correctement encodé.
```
Encoder correctement un tableau de données n'est pas une chose simple. Il peut y avoir plusieurs manières de le représenter. De plus, beaucoup de scientifiques ignorent ou oublient l'importance de bien encoder un tableau sous forme cas par variables. Lorsque vous souhaitez effectuer une représentation graphique, un format peut convenir mieux qu'un autre également, en fonction de ce que vous souhaitez visualiser sur le graphique. Il est donc important de connaître les fonctions permettant de recombiner simplement un tableau de données d'une forme vers l'autre : `spivot_longer()`/`pivot_longer()` et `spivot_wider()`/`pivot_wider()`.
```{block, type='info'}
<!----
L'aide-mémoire [Data Import](https://github.com/rstudio/cheatsheets/blob/master/data-import.pdf) est un outil pratique pour vous aider à retrouver les fonctions. Les explications relatives à cette partie s'y trouvent dans la section **Reshape Data**.
---->
L'utilisation des fonction `spivot_longer()` et `spivot_wider()` de `SciViews::R` ou `pivot_longer()` et `pivot_wider()` du package {tidyr} est également décrite en détails dans [R for Data Science (2e)](https://r4ds.hadley.nz/data-tidy.html#sec-pivoting).
```
Prenons l'exemple d'un jeu de données provenant de l'article scientifique suivant : [Paleomicrobiology to investigate copper resistance in bacteria: isolation and description of Cupriavidus necator B9 in the soil of a medieval foundry](https://orbi.umons.ac.be/handle/20.500.12907/5748). L'article est basé sur l'analyse métagénomique de type "shotgun" pour quatre communautés microbiennes (notées `c1`, `c4`, `c7`et `c10`, respectivement)[^06-donnees-qualitatives-5]. Il en résulte une longue liste de séquences que l'on peut attribuer à des règnes.
[^06-donnees-qualitatives-5]: Les analyses métagénomiques coûtent très cher. Il est souvent impossible de faire des réplicats. Un seul échantillon d'ADN a donc été séquencé ici pour chaque communauté.
```{r}
shotgun_wide <- dtx(
kingdom = c("Archaea", "Bacteria", "Eukaryota", "Viruses",
"other sequences", "unassigned", "unclassified sequences"),
c1 = c( 98379, 6665903, 81593, 1245, 757, 1320419, 15508),
c4 = c( 217985, 9739134, 101834, 4867, 1406, 2311326, 21572),
c7 = c( 143314, 7103244, 71111, 5181, 907, 1600886, 14423),
c10 = c(272541, 15966053, 150918, 15303, 2688, 3268646, 35024))
rmarkdown::paged_table(shotgun_wide)
```
Ce tableau est clair et lisible... seulement, est-il correctement encodé en cas par variables d'après vous ? Quelle que soit la réponse à cette question, il est toujours possible de passer de ce format large à un format long dans R de la façon suivante (`pivot_longer()` étant une fonction tidy, des précautions de collection des résultats avec, par exemple, `%<-%` sont nécessaires). Sinon, la fonction équivalent speedy `spivot_longer()` ne nécessite pas de précautions particulières :
```{r}
shotgun_long <- spivot_longer(shotgun_wide, cols = c(c1, c4, c7, c10),
names_to = "batch", values_to = "sequences")
rmarkdown::paged_table(shotgun_long)
```
L'argument `cols =` est assez flexible. Toutes les formes ci-dessous permettent d'obtenir le même résultat (ici, nous passons sur la fonction tidy `pivot_longer()` avec l'assignation alternative `%<-%` pour "collecter" le résultat).
```{r, eval=FALSE, echo=TRUE}
shotgun_long %<-% pivot_longer(shotgun_wide, cols = c1:c10,
names_to = "batch", values_to = "sequences")
shotgun_long %<-% pivot_longer(shotgun_wide, cols = 2:5,
names_to = "batch", values_to = "sequences")
shotgun_long %<-% pivot_longer(shotgun_wide, cols = starts_with("c"),
names_to = "batch", values_to = "sequences")
```
Voici la logique derrière `pivot_longer()`, présentée sous forme d'une animation :
`r img("sdd1_06/pivot_longer_smaller.gif", caption = "'''pivot_longer()''' par [apreshill](https://github.com/apreshill/teachthat/blob/master/pivot/pivot_longer_smaller.gif).")`
Vous conviendrez que le tableau nommé `shotgun_long` est moins compact et moins aisé à lire comparé à `shotgun_wide`. C'est une raison qui fait que beaucoup de scientifiques sont tentés d'utiliser le format large alors qu'ici il ne correspond **pas** à un tableau cas par variables correct, puisqu'il est impossible que les *mêmes* individus soient présents dans les différents lots (il s'agit de communautés microbiennes *indépendantes* les unes des autres). De plus, seul le format `shotgun_long` permet de produire des graphiques pertinents[^06-donnees-qualitatives-6].
[^06-donnees-qualitatives-6]: Notez malgré tout que, à condition de bien en comprendre les implications, le format complémentaire peut se justifier dans une publication pour y présenter un tableau le plus lisible possible, ce qui est le cas ici. Mais pour les analyses, c'est le format qui correspond à un tableau cas par variables qui **doit** être utilisé.
```{r}
chart(data = shotgun_long, sequences ~ batch %fill=% kingdom) +
geom_col(position = "fill")
```
Essayez de réaliser ce type de graphique en partant de `shotgun_wide`... Bonne chance !
```{block, type='note'}
Très souvent, lorsqu'il est impossible de réaliser un graphique avec `chart()` ou `ggplot()` parce que les données se présentent mal, c'est parce que le jeu de données est encodé de manière incorrecte ! Si les données sont, par contre, correctement encodées, demandez-vous alors si le graphique que vous voulez faire est pertinent.
```
##### À vous de jouer ! {.unnumbered}
`r h5p(55, height = 270, toc = "Transformation de long vers large")`
Pour passer du format long au format large (traitement inverse à `(s)pivot_longer()`), il faut utiliser la fonction tidy `pivot_wider()` ou la fonction speedy `spivot_wider()`. Ainsi pour retrouver le tableau d'origine (ou quelque chose de très semblable) à partir de `shotgun_long` nous utiliserons :
```{r}
shotgun_wide2 <- spivot_wider(shotgun_long,
names_from = batch, values_from = sequences)
rmarkdown::paged_table(shotgun_wide2)
```
### Recombinaison de variables
Parfois, ce sont les variables qui sont encodées de manière inappropriée par rapport aux analyses que vous souhaitez faire. Les fonctions speedy `sseparate()` et `sunite()`ou les fonctions tidy `separate()` et `unite()` permettent de séparer une colonne en plusieurs, ou inversement.
````{=html}
<!-- PhG: ce n'est plus le cas dans la dezrnière version!
```{block, type='info'}
L'aide-mémoire [Data Import](https://github.com/rstudio/cheatsheets/blob/master/data-import.pdf) vous rappelle ces fonctions dans sa section **Split Cells**. Elles sont également décrites en détail dans [R for Data Science](https://r4ds.had.co.nz/tidy-data.html#separating-and-uniting).
```
-->
````
Partons, par exemple, du jeu de données sur la biométrie des crabes du package {MASS} :
```{r}
crabs <- read("crabs", package = "MASS", lang = "fr")
rmarkdown::paged_table(crabs)
```
Les fonctions `sunite()` ou `unite()` permettent de combiner facilement les colonnes `sex` et `species` comme montré dans l'exemple ci-dessous. N'hésitez pas à faire appel à la page d'aide de la fonction via `?unite` pour vous guider.
```{r}
crabs %<-% unite(crabs, col = "sp_sex", sex, species, sep = "_")
rmarkdown::paged_table(crabs)
```
Les fonctions complémentaires à `(s)unite()` sont `sseparate()` et `separate()`. Elles permettent de séparer une variable en deux ou plusieurs colonnes séparées. Donc, pour retrouver un tableau similaire à celui d'origine, nous pourrons faire :
```{r}
crabs %<-% separate(crabs, col = "sp_sex", into = c("sex", "species"), sep = "_")
rmarkdown::paged_table(crabs)
```
##### À vous de jouer ! {.unnumbered}
`r learnr("A06La_recombination", title = "Recombinaison de tableaux", toc = "Recombinaison de tableaux")`
## Traitements multi-tableaux
Dans vos analyses, vous serez confronté à devoir gérer plusieurs tableaux que vous allez vouloir rassembler en un seul. Selon le travail à réaliser, il s'agit de coller les tableaux l'un au-dessus de l'autre, l'un à côté de l'autre, ou d'effectuer un travail de fusion plus complexe. Nous allons maintenant voir ces différents cas successivement.
```{block, type='info'}
L'aide-mémoire [Data Transformation with dplyr](https://github.com/rstudio/cheatsheets/blob/master/data-transformation.pdf) vous rappelle les différentes fonctions à utiliser dans sa section **Combine Tables**. Leur utilisation est également décrite en détails dans [R for Data Science (2e)](https://r4ds.hadley.nz/joins.html).
```
### Empilement vers le bas
Pour empiler des tableaux l'un au-dessus de l'autre, la fonction la plus simple est `bind_rows()` (tidy) ou `sbind_rows()` (speedy). Partons de données mesurées dans des mésoscosmes récifaux. Les différentes variables mesurées sont les suivantes :
- les données **physico-chimiques** : la température, le pH, la salinité, l'oxygène dissous à l'aide, respectivement, d'un pH-mètre, d'un conductimètre et d'un oxymètre
- la concentration en **nutriments** : orthophosphates (PO~4~^3-^) et nitrates (NO~3~^-^) dissous dans l'eau par analyse colorimétrique
Pour la première série de mesures, des étudiants ont encodé deux tableaux qu'ils devront par la suite rassembler en un seul. Voici le premier tableau :
```{r}
physico1 <- dtx(
sample = c("A0", "B0", "A0", "B0", "A0", "B0", "A0", "B0"),
student = c("st1", "st1", "st2", "st2", "st3", "st3", "st4", "st4"),
ph = c(7.94, 7.94, 7.94, 7.99, 7.94, 7.99, 7.94, 7.99),
salinity = c(34.0, 35.3, 33.9, 35.1, 34.0, 35.2, 33.9, 35.1),
oxygen = c(7.98, 8.00, 7.98, 7.98, 7.99, 7.86, 7.89, 7.98),
temperature = c(24.6, 24.4, 25.1, 24.7, 24.9, 24.7, 25.0, 24.6))
rmarkdown::paged_table(physico1)
```
Voici le second tableau :
```{r}
physico2 <- dtx(
sample = c("A0", "B0", "A0", "B0"),
student = c( "st5", "st5", "st6", "st6"),
ph = c(7.94, 7.99, 7.93, 7.99),
salinity = c(33.8, 35.0, 33.9, 35.1),
oxygen = c(7.96, 8.01, 7.90, 8.00),
temperature = c(25.0, 24.6, 24.0, 24.0))
rmarkdown::paged_table(physico2)
```
L'empilement des deux tableaux de données en un seul se fait via la fonction tidy `bind_rows()` ou la fonction speedy `sbind_rows()` lorsque les tableaux contiennent les mêmes variables présentées exactement dans le même ordre comme ici :
```{r}
physico <- sbind_rows(physico1, physico2)
rmarkdown::paged_table(physico)
```
### Empilement à droite
Pour combiner des tableaux de données par les colonnes, de gauche à droite, la fonction la plus simple à utiliser est la fonction tidy `bind_cols()` ou la fonction speedy `sbind_cols()`. Les étudiants ont également réalisé des prélèvements d'eau qui ont été dosés par colorimétrie avec un analyseur automatique. Les échantillons des deux groupes ont été mesurés dans la même série par l'appareil, ce qui donne le tableau suivant pour les nutriments :
```{r}
nutrients <- dtx(
sample = rep(c("A0", "B0"), times = 6),
student = rep(c("st4", "st6", "st5", "st2", "st1", "st3"), each = 2),
po4 = c(2.445, 0.374, 2.446, 0.394, 2.433, 0.361,
2.441, 0.372, 2.438, 0.388, 2.445, 0.390),
no3 = c(1.145, 0.104, 0.447, 0.066, 0.439, 0.093,
0.477, 0.167, 0.443, 0.593, 0.450, 0.125))
rmarkdown::paged_table(nutrients)
```
Vous devez être très vigilant lors de l'utilisation de, `bind_cols()` ou `sbind_cols()` car ces fonctions combinent vos tableaux sans s'assurer que vos lignes soient alignées convenablement !
```{r}
oceano %<-% bind_cols(nutrients, physico)
rmarkdown::paged_table(oceano)
```
Qu'observez-vous ?
Effectivement nos deux tableaux de données n'ont pas les lignes dans le même ordre. Il faut être vigilant lors de ce genre de combinaison de tableaux. Il est préférable d'employer des fonctions de fusion de tableaux plus complexes comme `full_join()`/`sfull_join()` (ci-dessous). Pour utiliser correctement `bind_cols()` ou `sbind_cols()`, il faut vous assurer que les lignes des deux tableaux correspondent exactement, par exemple, en utilisant la fonction `arrange()` ou `sarrange()` :
```{r}
nutrients2 %<-% arrange(nutrients, student, sample)
rmarkdown::paged_table(nutrients2)
```
Le tableau `nutrients2` a maintenant les données présentées dans le même ordre (en lignes) que le tableau `physico`. Nous pouvons donc rassembler ces deux tableaux à l'aide de `bind_cols()` :
```{r}
oceano %<-% bind_cols(nutrients2, physico)
rmarkdown::paged_table(oceano)
```
Après vérification de l'adéquation des lignes, nous n'aurons plus besoin des colonnes `sample...1` et `student...2`. La vérification automatique à l'aide de code R et l'élimination de ces variables du tableau `oceano` vous sont laissées comme exercices...
### Fusion de tableaux
La fusion fera intervenir une ou plusieurs colonnes communes des deux tableaux pour déterminer quelles lignes du premier correspondent aux lignes du second. Ainsi, la fusion des tableaux est assurée d'être réalisée correctement, quel que soit l'ordre des lignes dans les deux tableaux d'origine. Utilisons la fonction speedy `sfull_join()` en joignant les lignes en fonction des valeurs de `student` et `sample` :
```{r}
oceano <- sfull_join(nutrients, physico, by = c("student", "sample"))
rmarkdown::paged_table(oceano)
```
Observez bien ce dernier tableau. L'ordre retenu est celui de `nutrients` (le premier), mais les données issues de `physico` ont été *retriées* avant d'être fusionnées pour que les données correspondent. Comparez au tableau `physico` d'origine réimprimé ci-dessous :
```{r}
rmarkdown::paged_table(physico)
```
Il existe, en fait, plusieurs versions pour la fusion de tableaux, représentées par une série de fonctions tidy `XXX_join()` ou speedy `sXXX_join()`. Lorsque les lignes entre les deux tableaux fusionnés correspondent parfaitement comme dans l'exemple traité ici, les différentes variantes ont le même effet. Mais lorsque des lignes diffèrent, les variantes ont leur importance :
- `(s)full_join()` garde toutes les lignes,
`r img("sdd1_06/full-join.gif", caption = "'''full_join()''' par [gadenbuie](https://github.com/gadenbuie/tidyexplain/blob/master/images/full-join.gif).")`
- `(s)left_join()` ne garde que les lignes uniques du tableau de gauche en plus des lignes communes,
`r img("sdd1_06/left-join.gif", caption = "'''left_join()''' par [gadenbuie](https://github.com/gadenbuie/tidyexplain/blob/master/images/left-join.gif).")`
- `(s)right_join()` ne garde que les lignes uniques du tableau de droite en plus des lignes communes,
`r img("sdd1_06/right-join.gif", caption = "'''right_join()''' par [gadenbuie](https://github.com/gadenbuie/tidyexplain/blob/master/images/right-join.gif).")`
- `(s)inner_join()` garde uniquement les lignes communes aux deux tableaux,
`r img("sdd1_06/inner-join.gif", caption = "'''inner_join()''' par [gadenbuie](https://github.com/gadenbuie/tidyexplain/blob/master/images/inner-join.gif).")`
##### À vous de jouer ! {.unnumbered}
`r learnr("A06Lb_multi_table", title = "Traitements multi-tableaux", toc = "Traitements multi-tableaux")`
```{r assign_A06Ia_belgium_demo, echo=FALSE, results='asis'}
if (exists("assignment"))
assignment("A06Ia_belgium_demo", part = NULL,
url = "https://github.com/BioDataScience-Course/A06Ia_belgium_demo",
course.ids = c(
'S-BIOG-006' = !"A06Ia_{YY}M_belgium_demo"),
course.urls = c(
'S-BIOG-006' = "https://classroom.github.com/a/QjzyWaBr"),
course.starts = c(
'S-BIOG-006' = !"{W[14]+1} 13:00:00"),
course.ends = c(
'S-BIOG-006' = !"{W[14]+1} 16:00:00"),
term = "Q1", level = 3,
toc = "Démographie en Belgique")
```
##### Pour en savoir plus {.unnumbered}
- Un [aide-mémoire général](https://www.business-science.io/r-cheatsheet.html) en science des données avec lien vers les sites Web importants et les autres aide-mémoires. À partir de là, vous pouvez retrouver les packages, puis les fonctions qui réalisent telle ou telle transformation des données. Allez ensuite voir la page d'aide de la fonction avec `?ma_fonction`. Vous pouvez aussi rechercher sur <https://stackoverflow.com>, en précédent le nom de la fonction par "[R]" (R entre crochets) pour restreindre la recherche uniquement dans les pages relatives au langage R.
- Le chapitre relatif aux [jointures de **R for Data Science (2e)**](https://r4ds.hadley.nz/joins.html) contient divers exemples de transformation des données à partir de un ou plusieurs tableaux et présente aussi d'autres formes de jointures.
## Récapitulatif des exercices
Vous venez de terminer le module 6 qui clôture la première partie du cours. Ce module vous a permis d'apprendre à recombiner, remodeler et fusionner des tableaux. Pour évaluer votre compréhension de cette matière, vous aviez les exercices suivants à réaliser :
`r show_ex_toc()`
##### Progression {.unnumbered}
`r launch_report("06", height = 800)`