Antes de comenzar con EDA, hagamos una conceptualización del tipo de problemas que queremos resolver con lo que conocemos como Ciencia de Datos (En el tablero)
2.2 Análisis exploratorio
El análisis exploratorio se lleva a cabo a través de transformaciones y visualizaciones de los datos.1 El proceso puede ser iterativo y ayuda a comprender mejor el tipo de datos con los que se está trabajando, muchos problemas en Ciencia de Datos se resuelven en esta fase.
1 Hablar de EDA es una forma de organizar las ideas, algunas personas o autores pueden considerar que el EDA incluye la limpieza de datos e incluso alguna modelación. Por sencillez, vamos a considerar que el EDA está compuesto principalmente por transformación de variables y visualizaciones
2.3 ¿Cómo hacer EDA en R?
Hay muchos paquetes en R pensados para facilitar el trabajo del científico de datos. Nos basaremos en el ecosistema de paquetes optimizados para análisis de datos, conocido como tidyverse
El core tidyverse es el conjunto principal de paquetes de este ecosistema:
ggplot2: Para hacer gráficas
diplyr: Para manipulación de datos
tidyr: Para organizar bases de datos en formato tidy
readr: Para importar datos
tibble: para manejo de bases de datos con muchos datos
stringr: Para manipular strings
forcats: Para manipular variables categóricas
podemos cargar cada paquete de forma individual (library(ggplot2)) o cargarlos de forma conjunta con library(tidyverse). Nos interesan principalmente ggplot2 y dplyr.
Para poder hacer análisis de cualquier tipo, primero necesitamos tener disponible un conjunto de datos o data frame (o en formato del tidyverse un tibble2). Hay varias formas de obtener datos en R
2 Investigue qué es un tibble
Datos sintéticos (simulados)
Bases de datos instaladas con R o con alguno de sus paquetes
Importarlo desde una fuente externa, ya sea de forma local o desde la web
Usaremos una base de datos que viene en el paquete palmerpenguins (hay que instalar y cargar la librería) que es bastante adecuada para iniciar un análisis exploratorio
library(palmerpenguins)penguins
# A tibble: 344 × 8
species island bill_length_mm bill_depth_mm flipper_length_mm body_mass_g
<fct> <fct> <dbl> <dbl> <int> <int>
1 Adelie Torgersen 39.1 18.7 181 3750
2 Adelie Torgersen 39.5 17.4 186 3800
3 Adelie Torgersen 40.3 18 195 3250
4 Adelie Torgersen NA NA NA NA
5 Adelie Torgersen 36.7 19.3 193 3450
6 Adelie Torgersen 39.3 20.6 190 3650
7 Adelie Torgersen 38.9 17.8 181 3625
8 Adelie Torgersen 39.2 19.6 195 4675
9 Adelie Torgersen 34.1 18.1 193 3475
10 Adelie Torgersen 42 20.2 190 4250
# ℹ 334 more rows
# ℹ 2 more variables: sex <fct>, year <int>
Otra herramienta que usaremos con frecuencia en nuestros códigos es el operador pipe. Este operador viene en dos versiones:
|>: Versión base o nativa de R, no requiere la instalación de ningún paquete
%>%: Versión del tidyverse, requiere cargar alguno de los paquetes dplyr, magrittr, tidyverse
El atajo de teclado para el operador pipe es . Por defecto se genera %>%, para generar el operador nativo |>, debe ingresar a Tools -> Global Options -> Code -> Editing y activar la casilla use native pipe operator
El operador pipe nos permite escribir código de forma lineal y más fácilmente legible de izquierda a derecha, en lugar de funciones anidadas.
sin(log(sum(c(1,2,3))))
[1] 0.9756868
# usando el operador pipec(1,2,3) |>sum() |>log() |>sin()
[1] 0.9756868
El operador permite pasar el resultado de la izquierda como primer argumento de la función siguiente a la derecha.
El tipo de gráfica que debemos crear depende del tipo de variables que tengamos y de la forma en que las queramos analizar, por lo que es importante elegir las gráficas adecuadas. Antes de empezar a construir gráficas, recordemos una definición de los tipos de variables que podemos tener
Numéricas (cuantitativas)
Discretas
Continuas
categóricas (cualitativas o factores)
Ordinales
Nominales
ejecute ?penguins para estudiar y entender los datos en penguins
Una forma alterna, usando el operador pipe3 sería penguins |> ggplot()
3 Para ggplot2 solo usaremos este operador al aplicar la función ggplot() a la base de datos que estemos usando, el resto de elementos del gráfico se agregarán con el signo ++. Cuando estemos usando dplyr, usaremos con más frecuencia el operador pipe
ggplot2 implementa lo que se conoce como gramática de gráficos, que en resumen quiere decir que el gráfico se construye al ir agregando capas (layers). Al aplicar la función ggplot() a una base de datos, se crea un lienzo en blanco (gris).
penguins |>ggplot(mapping =aes(x = body_mass_g))
Aún no se muestra una gráfica, se ha creado un mapeo y puede verse la escala de valores de la variable body_mass_g en el eje X, pero aún falta por agregar el tipo de geometría o tipo de gráfico a construir
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Para hacer gráficos ordenados, es bueno personalizar las etiquetas y los títulos y subtítulos, esto se logra con la función labs() que tiene argumentos como title, subtitle, caption, etc
penguins |>ggplot(mapping =aes(x = body_mass_g)) +geom_histogram() +labs(title ="Peso de los Pingüinos del Archipiélago de Palmer",x ="Peso en gramos",y ="Conteo",caption ="Datos de 333 pingüinos distribuidos en 3 islas y 3 especies")
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Algunos argumentos o propiedades, tales como el color (colour) y relleno (fill), son comunes a muchos o todos los tipos de geometrías. Otras propiedades son más específicas, para un histograma por ejemplo, tiene sentido tener propiedades de número de clases (bins) o ancho de las clases (binwidth), pero no tendría mucho sentido hablar de número de clases en un diagrama de cajas.
En el siguiente gráfico, modificamos la cantidad de clases a usar, el color del borde y el relleno.
penguins |>ggplot(mapping =aes(x = body_mass_g)) +geom_histogram(fill="red", bins =20, color ="black") +labs(title ="Peso de los Pingüinos del Archipiélago de Palmer",x ="Peso en gramos",y ="Conteo",caption ="Datos de 333 pingüinos distribuidos en 3 islas y 3 especies")
2.5Bonus: Colores
Parte importante de toda gráfica, es el uso de los colores
En R podemos manejar colores por nombres (en inglés, por supuesto) o usando sistemas de codificación como el RGB y Hexadecimal
Una lista de colores en R la podemos obtener con colors()5. La lista completa de colores disponibles en R es
N
Colores
1
white
2
aliceblue
3
antiquewhite
4
antiquewhite1
5
antiquewhite2
6
antiquewhite3
7
antiquewhite4
8
aquamarine
9
aquamarine1
10
aquamarine2
11
aquamarine3
12
aquamarine4
13
azure
14
azure1
15
azure2
16
azure3
17
azure4
18
beige
19
bisque
20
bisque1
21
bisque2
22
bisque3
23
bisque4
24
black
25
blanchedalmond
26
blue
27
blue1
28
blue2
29
blue3
30
blue4
31
blueviolet
32
brown
33
brown1
34
brown2
35
brown3
36
brown4
37
burlywood
38
burlywood1
39
burlywood2
40
burlywood3
41
burlywood4
42
cadetblue
43
cadetblue1
44
cadetblue2
45
cadetblue3
46
cadetblue4
47
chartreuse
48
chartreuse1
49
chartreuse2
50
chartreuse3
51
chartreuse4
52
chocolate
53
chocolate1
54
chocolate2
55
chocolate3
56
chocolate4
57
coral
58
coral1
59
coral2
60
coral3
61
coral4
62
cornflowerblue
63
cornsilk
64
cornsilk1
65
cornsilk2
66
cornsilk3
67
cornsilk4
68
cyan
69
cyan1
70
cyan2
71
cyan3
72
cyan4
73
darkblue
74
darkcyan
75
darkgoldenrod
76
darkgoldenrod1
77
darkgoldenrod2
78
darkgoldenrod3
79
darkgoldenrod4
80
darkgray
81
darkgreen
82
darkgrey
83
darkkhaki
84
darkmagenta
85
darkolivegreen
86
darkolivegreen1
87
darkolivegreen2
88
darkolivegreen3
89
darkolivegreen4
90
darkorange
91
darkorange1
92
darkorange2
93
darkorange3
94
darkorange4
95
darkorchid
96
darkorchid1
97
darkorchid2
98
darkorchid3
99
darkorchid4
100
darkred
101
darksalmon
102
darkseagreen
103
darkseagreen1
104
darkseagreen2
105
darkseagreen3
106
darkseagreen4
107
darkslateblue
108
darkslategray
109
darkslategray1
110
darkslategray2
111
darkslategray3
112
darkslategray4
113
darkslategrey
114
darkturquoise
115
darkviolet
116
deeppink
117
deeppink1
118
deeppink2
119
deeppink3
120
deeppink4
121
deepskyblue
122
deepskyblue1
123
deepskyblue2
124
deepskyblue3
125
deepskyblue4
126
dimgray
127
dimgrey
128
dodgerblue
129
dodgerblue1
130
dodgerblue2
131
dodgerblue3
132
dodgerblue4
133
firebrick
134
firebrick1
135
firebrick2
136
firebrick3
137
firebrick4
138
floralwhite
139
forestgreen
140
gainsboro
141
ghostwhite
142
gold
143
gold1
144
gold2
145
gold3
146
gold4
147
goldenrod
148
goldenrod1
149
goldenrod2
150
goldenrod3
151
goldenrod4
152
gray
153
gray0
154
gray1
155
gray2
156
gray3
157
gray4
158
gray5
159
gray6
160
gray7
161
gray8
162
gray9
163
gray10
164
gray11
165
gray12
166
gray13
167
gray14
168
gray15
169
gray16
170
gray17
171
gray18
172
gray19
173
gray20
174
gray21
175
gray22
176
gray23
177
gray24
178
gray25
179
gray26
180
gray27
181
gray28
182
gray29
183
gray30
184
gray31
185
gray32
186
gray33
187
gray34
188
gray35
189
gray36
190
gray37
191
gray38
192
gray39
193
gray40
194
gray41
195
gray42
196
gray43
197
gray44
198
gray45
199
gray46
200
gray47
201
gray48
202
gray49
203
gray50
204
gray51
205
gray52
206
gray53
207
gray54
208
gray55
209
gray56
210
gray57
211
gray58
212
gray59
213
gray60
214
gray61
215
gray62
216
gray63
217
gray64
218
gray65
219
gray66
220
gray67
221
gray68
222
gray69
223
gray70
224
gray71
225
gray72
226
gray73
227
gray74
228
gray75
229
gray76
230
gray77
231
gray78
232
gray79
233
gray80
234
gray81
235
gray82
236
gray83
237
gray84
238
gray85
239
gray86
240
gray87
241
gray88
242
gray89
243
gray90
244
gray91
245
gray92
246
gray93
247
gray94
248
gray95
249
gray96
250
gray97
251
gray98
252
gray99
253
gray100
254
green
255
green1
256
green2
257
green3
258
green4
259
greenyellow
260
grey
261
grey0
262
grey1
263
grey2
264
grey3
265
grey4
266
grey5
267
grey6
268
grey7
269
grey8
270
grey9
271
grey10
272
grey11
273
grey12
274
grey13
275
grey14
276
grey15
277
grey16
278
grey17
279
grey18
280
grey19
281
grey20
282
grey21
283
grey22
284
grey23
285
grey24
286
grey25
287
grey26
288
grey27
289
grey28
290
grey29
291
grey30
292
grey31
293
grey32
294
grey33
295
grey34
296
grey35
297
grey36
298
grey37
299
grey38
300
grey39
301
grey40
302
grey41
303
grey42
304
grey43
305
grey44
306
grey45
307
grey46
308
grey47
309
grey48
310
grey49
311
grey50
312
grey51
313
grey52
314
grey53
315
grey54
316
grey55
317
grey56
318
grey57
319
grey58
320
grey59
321
grey60
322
grey61
323
grey62
324
grey63
325
grey64
326
grey65
327
grey66
328
grey67
329
grey68
330
grey69
331
grey70
332
grey71
333
grey72
334
grey73
335
grey74
336
grey75
337
grey76
338
grey77
339
grey78
340
grey79
341
grey80
342
grey81
343
grey82
344
grey83
345
grey84
346
grey85
347
grey86
348
grey87
349
grey88
350
grey89
351
grey90
352
grey91
353
grey92
354
grey93
355
grey94
356
grey95
357
grey96
358
grey97
359
grey98
360
grey99
361
grey100
362
honeydew
363
honeydew1
364
honeydew2
365
honeydew3
366
honeydew4
367
hotpink
368
hotpink1
369
hotpink2
370
hotpink3
371
hotpink4
372
indianred
373
indianred1
374
indianred2
375
indianred3
376
indianred4
377
ivory
378
ivory1
379
ivory2
380
ivory3
381
ivory4
382
khaki
383
khaki1
384
khaki2
385
khaki3
386
khaki4
387
lavender
388
lavenderblush
389
lavenderblush1
390
lavenderblush2
391
lavenderblush3
392
lavenderblush4
393
lawngreen
394
lemonchiffon
395
lemonchiffon1
396
lemonchiffon2
397
lemonchiffon3
398
lemonchiffon4
399
lightblue
400
lightblue1
401
lightblue2
402
lightblue3
403
lightblue4
404
lightcoral
405
lightcyan
406
lightcyan1
407
lightcyan2
408
lightcyan3
409
lightcyan4
410
lightgoldenrod
411
lightgoldenrod1
412
lightgoldenrod2
413
lightgoldenrod3
414
lightgoldenrod4
415
lightgoldenrodyellow
416
lightgray
417
lightgreen
418
lightgrey
419
lightpink
420
lightpink1
421
lightpink2
422
lightpink3
423
lightpink4
424
lightsalmon
425
lightsalmon1
426
lightsalmon2
427
lightsalmon3
428
lightsalmon4
429
lightseagreen
430
lightskyblue
431
lightskyblue1
432
lightskyblue2
433
lightskyblue3
434
lightskyblue4
435
lightslateblue
436
lightslategray
437
lightslategrey
438
lightsteelblue
439
lightsteelblue1
440
lightsteelblue2
441
lightsteelblue3
442
lightsteelblue4
443
lightyellow
444
lightyellow1
445
lightyellow2
446
lightyellow3
447
lightyellow4
448
limegreen
449
linen
450
magenta
451
magenta1
452
magenta2
453
magenta3
454
magenta4
455
maroon
456
maroon1
457
maroon2
458
maroon3
459
maroon4
460
mediumaquamarine
461
mediumblue
462
mediumorchid
463
mediumorchid1
464
mediumorchid2
465
mediumorchid3
466
mediumorchid4
467
mediumpurple
468
mediumpurple1
469
mediumpurple2
470
mediumpurple3
471
mediumpurple4
472
mediumseagreen
473
mediumslateblue
474
mediumspringgreen
475
mediumturquoise
476
mediumvioletred
477
midnightblue
478
mintcream
479
mistyrose
480
mistyrose1
481
mistyrose2
482
mistyrose3
483
mistyrose4
484
moccasin
485
navajowhite
486
navajowhite1
487
navajowhite2
488
navajowhite3
489
navajowhite4
490
navy
491
navyblue
492
oldlace
493
olivedrab
494
olivedrab1
495
olivedrab2
496
olivedrab3
497
olivedrab4
498
orange
499
orange1
500
orange2
501
orange3
502
orange4
503
orangered
504
orangered1
505
orangered2
506
orangered3
507
orangered4
508
orchid
509
orchid1
510
orchid2
511
orchid3
512
orchid4
513
palegoldenrod
514
palegreen
515
palegreen1
516
palegreen2
517
palegreen3
518
palegreen4
519
paleturquoise
520
paleturquoise1
521
paleturquoise2
522
paleturquoise3
523
paleturquoise4
524
palevioletred
525
palevioletred1
526
palevioletred2
527
palevioletred3
528
palevioletred4
529
papayawhip
530
peachpuff
531
peachpuff1
532
peachpuff2
533
peachpuff3
534
peachpuff4
535
peru
536
pink
537
pink1
538
pink2
539
pink3
540
pink4
541
plum
542
plum1
543
plum2
544
plum3
545
plum4
546
powderblue
547
purple
548
purple1
549
purple2
550
purple3
551
purple4
552
red
553
red1
554
red2
555
red3
556
red4
557
rosybrown
558
rosybrown1
559
rosybrown2
560
rosybrown3
561
rosybrown4
562
royalblue
563
royalblue1
564
royalblue2
565
royalblue3
566
royalblue4
567
saddlebrown
568
salmon
569
salmon1
570
salmon2
571
salmon3
572
salmon4
573
sandybrown
574
seagreen
575
seagreen1
576
seagreen2
577
seagreen3
578
seagreen4
579
seashell
580
seashell1
581
seashell2
582
seashell3
583
seashell4
584
sienna
585
sienna1
586
sienna2
587
sienna3
588
sienna4
589
skyblue
590
skyblue1
591
skyblue2
592
skyblue3
593
skyblue4
594
slateblue
595
slateblue1
596
slateblue2
597
slateblue3
598
slateblue4
599
slategray
600
slategray1
601
slategray2
602
slategray3
603
slategray4
604
slategrey
605
snow
606
snow1
607
snow2
608
snow3
609
snow4
610
springgreen
611
springgreen1
612
springgreen2
613
springgreen3
614
springgreen4
615
steelblue
616
steelblue1
617
steelblue2
618
steelblue3
619
steelblue4
620
tan
621
tan1
622
tan2
623
tan3
624
tan4
625
thistle
626
thistle1
627
thistle2
628
thistle3
629
thistle4
630
tomato
631
tomato1
632
tomato2
633
tomato3
634
tomato4
635
turquoise
636
turquoise1
637
turquoise2
638
turquoise3
639
turquoise4
640
violet
641
violetred
642
violetred1
643
violetred2
644
violetred3
645
violetred4
646
wheat
647
wheat1
648
wheat2
649
wheat3
650
wheat4
651
whitesmoke
652
yellow
653
yellow1
654
yellow2
655
yellow3
656
yellow4
657
yellowgreen
5 Ejecute el comando en la consola, a menos que quiera imprimir una lista de colores siempre que ejecute el código en su editor
Manejar colores por nombres nos permite recordarlos fácilmente, pero es bastante limitado, a pesar de los más de 600 colores de la lista, no es nada comparado con los más de 16 millones de colores que podemos generar con sistemas como RGB o HEX (aunque tampoco necesitamos tantos colores, ni todas las pantallas pueden generarlos ni nosotros notamos la diferencia)
2.5.1 RGB
Iniciales de los colores primarios (en inglés): R: Red; G: Green; B: Blue. Se basa en la combinación de diferentes niveles de intensidad para cada uno de estos colores
Se representa como una terna, donde cada valor está, por lo general, entre 0 y 255 (también en escala de 0 a 1 o en porcentajes de 0 a 100). Equivalencia de los colores primarios:
Rojo: rgb(255, 0, 0)
Verde: rgb(0, 255, 0)
Azul: rgb(0, 0, 255)
Algunos colores en sistema RGB (intente comprender el código completo, no se usa ggplot2 sino la función base plot de R, ejecute ?plot en la consola para ver la documentación si quiere aprender a usar esta función base de R)
plot(x =rep(1,3), col =c(rgb(230,50,110, maxColorValue =255), rgb(20,50,10, maxColorValue =100), rgb(0.5,0.5,0.7)), main ="Algunos colores con RGB",xlim =c(0,4),xlab ="", ylab="", pch =20, cex =10)
Por defecto, la función rgb() en R, tomará como valor máximo de la escala el 1, así que si se está trabajando en la escala 0-255 (lo más usual), es necesario establecer maxColorValue=255, en realidad de puede trabajar con cualquier valor positivo, R hará la conversión de forma adecuada.
los 256 posibles valores para cada componente (0-255), pueden producir en total \(256^3=16777216\), ¡más de 16 millones de colores!
Es posible agregar un valor \(\alpha\) de opacidad a los colores (estudie y comprenda el siguiente código)
alfa <-seq(5, 255, by =25) # ¿qué hace esto?plot(x =rep(1,length(alfa)), col =rgb(17, 125, 0, maxColorValue =255, alpha = alfa), cex =10, pch =20, xlab ="", ylab ="", xlim =c(0,12),main ="Agregar opacidad al color")
2.5.2 Hexadecimal
El sistema hexadecimal consta de 6 posiciones 👨🏫, las primeras 2 para el rojo, las siguientes para el verde y las últimas para el azul. Cada una de estas varía entre 00 y FF. Equivalencia de los colores primarios:
Rojo: #FF0000
Verde: #00FF00
Azul: #0000FF
Hay una correspondencia uno a uno entre ambos sistemas (RGB y HEX). Al igual que el sistema RGB, se puede agregar una propiedad de opacidad al agregar 2 posiciones más (también entre 00 y FF) al sistema Hexadecimal.
La función rgb() convierte el código RGB a Hexadecimal. También se puede hacer lo contrario con la función col2rgb()
rgb(255, 0, 0, maxColorValue =255) # De RGB a Hexadecimal
[1] "#FF0000"
col2rgb("#FF0000") # De Hexadecimal a RGB
[,1]
red 255
green 0
blue 0
Dado que estamos hablando de colores, sin duda alguna lo más natural y sencillo es verlos en lugar de memorizar códigos. Hay muchas herramientas online que sirven como mezcladores de colores y nos devuelven los respectivos códigos en diferentes sistemas. Puede consultar el siguiente tutorial para más detalles
En Rstudio podemos instalar el complemento colourPicker con install.packages("colourpicker"). Al hacerlo se activa en el botón Addins un nuevo complemento.
2.6 Volviendo a ggplot2
penguins |>ggplot(mapping =aes(x = body_mass_g)) +geom_histogram(fill="#FA88FC9B", color ="darkblue", binwidth =200) +labs(title ="Peso de los Pingüinos del Archipiélago de Palmer",x ="Peso en gramos",y ="Conteo",caption ="Datos de 333 pingüinos distribuidos en 3 islas y 3 especies")
Podemos cambiar la orientación del histograma al cambiar la variable en el argumento mapping y actualizar las etiquetas del gráfico
penguins |>ggplot(mapping =aes(y = body_mass_g)) +geom_histogram(fill="#FFD08594", color ="darkblue", binwidth =200) +labs(title ="Peso de los Pingüinos del Archipiélago de Palmer",y ="Peso en gramos",x ="Conteo",caption ="Datos de 333 pingüinos distribuidos en 3 islas y 3 especies")
Un gráfico de densidad se obtiene con geom_density()
penguins |>ggplot(mapping =aes(x = body_mass_g)) +geom_density(fill="aliceblue", color ="black") +labs(title ="Peso de los Pingüinos del Archipiélago de Palmer",x ="Peso en gramos",y ="",caption ="Datos de 333 pingüinos distribuidos en 3 islas y 3 especies")
Posición del signo “+”
el signo ++NO debe ir al comienzo de una línea, puede ir como último elemento de la línea pero no de primero
El siguiente código mostrará un error debido a la posición errada del signo ++
penguins |>ggplot(mapping =aes(x = body_mass_g))+geom_density(fill="aliceblue", color ="black") +labs(title ="Peso de los Pingüinos del Archipiélago de Palmer",x ="Peso en gramos",y ="",caption ="Datos de 333 pingüinos distribuidos en 3 islas y 3 especies")## Error:## ! Cannot use `+` with a single argument.## ℹ Did you accidentally put `+` on a new line?
Siguiendo la lógica de construcción de las gráficas anteriores, no debe ser difícil ahora crear un diagrama de cajas, la geometría necesaria tiene el nombre que uno esperaría: geom_boxplot()
penguins |>ggplot(aes(y = body_mass_g)) +geom_boxplot() +labs(title ="Diagrama de Cajas para el peso en gramos de los Pingüinos",y ="Peso en gramos" )
2.7 Caso 2. Una variable numérica y una categórica o factor
Al agregar una variable categórica o factor, podemos obtener información más detallada de la distribución del peso de los pingüinos por especie o isla
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
¿Cómo actúa el argumento fill dentro de aes() y por qué es diferente cuando se usa como argumento dentro de geom_histogram?6
6 Responder esta pregunta es importante para entender el funcionamiento de ggplot2
Note que se agregan leyendas de forma automática y las podemos personalizar. El argumento alpha agrega opacidad (transparencia) al color, debe ser un valor entre 0 (totalmente transparente) y 1 (totalmente opaco)
penguins |>ggplot(aes(x = body_mass_g, fill = species)) +geom_histogram(color ="darkblue", binwidth =200, alpha =0.7) +labs(title ="Peso de los Pingüinos del Archipiélago de Palmer",x ="Peso en gramos",y ="Conteo",fill ="Especie",caption ="Datos de 333 pingüinos discriminados por especies")
Al igual que con el histograma, podemos combinar la variable categórica para construir gráficos de densidad y gráficos de caja por cada categoría
penguins |>ggplot(aes(x = body_mass_g, fill = species)) +geom_density(alpha =0.5) +labs(title ="Distribución del peso por especie",subtitle ="Datos de pingüinos del archipiélago de Palmer",fill ="Especie",y ="",x ="Peso en gramos" )
Los gráficos de densidad por categoría sobre la misma escala son muy útiles. El resultado anterior puede ser un poco desalentador ya que los gráficos se superponen, agregamos transparencia al color para tener una mejor lectura, pero una mejor opción es variar un poco la escala en el eje vertical para cada densidad7. ggplot2 no tiene soporte para este tipo de gráficos, pero podemos agregar una extensión que nos permite crearlos fácilmente (existen muchas extensiones para ggplot). La librería que debemos agregar es ggridges, instalamos desde la consola install.packages("ggridges") y cargamos la librería para poder usarla: library(ggridges)
7 Estos son los llamados ridgeline plots o joyplots
# install.packages("ggridges") # haga esto en la consolalibrary(ggridges)penguins |>ggplot(aes(x = body_mass_g, y = species)) +geom_density_ridges()
Picking joint bandwidth of 153
Podemos controlar el aspecto del gráfico con algunos parámetros que ya son familiares, tales como color, fill entre otros. El parámetro scale permite controlar la superposición de los gráficos, cuando toma el valor de 1, los gráficos apenas se tocan. Entre más cercano el valor a 0, más separados, entre más alto el valor, estarán más superpuestos
p1 <- penguins |>ggplot(aes(x = body_mass_g, y = species, fill = species)) +labs(title ="Distribución del peso por especie",subtitle ="Datos de pingüinos del archipiélago de Palmer",fill ="Especie",y ="Especie",x ="Peso en gramos" )p1 +geom_density_ridges(color ="red", alpha =0.7, size =1,scale =0.5)
p1 +geom_density_ridges(alpha =0.6,scale =5)
Teniendo en cuenta lo aprendido hasta ahora, intente reproducir el siguiente gráfico de cajas del peso de los pingüinoss por islas
Click para mostrar el código
penguins |>ggplot(aes(x = island, y = body_mass_g, fill = island)) +geom_boxplot(alpha =0.8) +labs(title ="Distribución del peso por isla",subtitle ="Datos de pingüinos del archipiélago de Palmer",fill ="Especie",x ="Isla",y ="Peso en gramos" )
Ejercicio 2.1 Invierta la orientación del gráfico anterior
Un gráfico muy popular con un propósito similar al diagrama de cajas, es el gráfico de violín. Se puede construir usando ggplot2 con la misma sencillez que los anteriores gráficos
penguins |>ggplot(aes(x = island, y = body_mass_g, fill = island)) +geom_violin() +labs(title ="Distribución del peso por Isla",x ="Isla",y ="Peso en gramos",fill ="Isla" )
Sería interesante agregar sobre el mismo sistema de coordenadas, gráfico de violín y gráfico de caja
penguins |>ggplot(aes(x = island, y = body_mass_g, fill = island)) +geom_violin() +geom_boxplot()+labs(title ="Distribución del peso por Isla",x ="Isla",y ="Peso en gramos",fill ="Isla" )
Esta combinación de gráficos es bastante usual, aunque nuestro resultado no es el mejor, afinarlo requiere del uso de otras librerías. Más adelante volveremos a este tipo de gráficos.
2.8 Caso 3. Dos variables numéricas
El gráfico más común para este caso es el diagrama de dispersión. Observemos la relación que hay entre el peso del pingüino y la longitud de la aleta
penguins |>ggplot(aes(x = flipper_length_mm, y = body_mass_g)) +geom_point()
Con algo más de trabajo, podemos personalizar8 el resultado, agregando una forma a los puntos con shape, modificando el tamaño de los puntos con size, coloreando con colour y fill, modificando el ancho del marco de los puntos con stroke
8 Personalizar no quiere decir necesariamente mejorar
penguins |>ggplot(aes(x = flipper_length_mm, y = body_mass_g)) +geom_point(shape =23, fill ="white", colour ="purple", size =3, stroke =3)
En R hay un total de 25 formas (argumento shape) básicas para representar estos puntos
data.frame(x =1:25, y =1:25) |>ggplot(aes(x = x, y = y)) +geom_point(shape =1:25, size =5)
Todas estas formas admiten el argumento de color y de la forma 21 a 25 admiten además un argumento de relleno (fill). Reuniendo todo lo anterior, podemos crear un gráfico más detallado
penguins |>ggplot(aes(x = flipper_length_mm, y = body_mass_g)) +geom_point(shape =22, fill ="#37C790E6", colour ="black",size =2, stroke =1) +labs(title ="Peso vs Longitud de la aleta",subtitle ="Datos de 3 especies de pingüinos del archipiélago de Palmer",x ="Longitudad de la aleta (mm)",y ="Peso (gr)" )
Podemos agregar distribuciones marginales a este diagrama de dispersión, usando el paquete ggExtra. Instale desde la consola: install.packages("ggExtra"). Veamos un ejemplo
library(ggExtra)p1 <- penguins |>ggplot(aes(x = flipper_length_mm, y = body_mass_g)) +geom_point(shape =22, fill ="#37C790E6", colour ="black",size =2, stroke =1) +labs(title ="Peso vs Longitud de la aleta",subtitle ="Datos de 3 especies de pingüinos del archipiélago de Palmer",x ="Longitudad de la aleta (mm)",y ="Peso (gr)" )ggMarginal(p = p1)
La función ggMarginal del paquete ggExtra no funciona con el operador pipe, por lo que es necesario guardar el objeto ggplot2 (gráfico) en una variable para luego aplicar la función ggMarginal sobre esta variable. Cambiando algunos detalles del gráfico anterior, obtenemos
library(ggExtra)p1 <- penguins |>ggplot(aes(x = flipper_length_mm, y = body_mass_g)) +geom_point(shape =22, fill ="#37C790E6", colour ="black",size =2, stroke =1) +labs(title ="Peso vs Longitud de la aleta",subtitle ="Datos de 3 especies de pingüinos del archipiélago de Palmer",x ="Longitudad de la aleta (mm)",y ="Peso (gr)" )ggMarginal(p = p1, type ="histogram", size =4, fill ="slateblue",bins =20)
Otro tipo de gráfico útil para estudiar la relación entre dos variables numéricas es el de densidad en dos dimensiones.
penguins |>ggplot(aes(x = flipper_length_mm, y = body_mass_g)) +geom_density_2d()
Para modificar de forma manual la escala de valores de los ejes, agregamos xlim(inf_x, sup_x) y ylim(inf_y, sup_y)
penguins |>ggplot(aes(x = flipper_length_mm, y = body_mass_g)) +geom_density_2d() +xlim(NA, 240) +ylim(2000, 6500) +labs(title ="Densidad conjunta",subtitle ="Datos de 3 especies de pingüinos del archipiélago de Palmer",x ="Longitudad de la aleta (mm)",y ="Peso (gr)" )
O en un intento de automatizar más el cálculo de la escala de los ejes
penguins |>ggplot(aes(x = flipper_length_mm, y = body_mass_g)) +geom_density_2d() +xlim(0.98*min(penguins$flipper_length_mm), 1.02*max(penguins$flipper_length_mm)) +ylim(0.95*min(penguins$body_mass_g), 1.02*max(penguins$body_mass_g)) +labs(title ="Densidad conjunta",subtitle ="Datos de 3 especies de pingüinos del archipiélago de Palmer",x ="Longitudad de la aleta (mm)",y ="Peso (gr)" )
Volveremos después a revisar con más detalle estos gráficos.
2.9 Caso 4. Dos variables numéricas y una categórica
En el siguiente gráfico de dispersión, agregamos la información de la especie y además un modelo ajustado a los datos. Comparemos los dos resultados para comprender una característica fundamental de ggplot2
`geom_smooth()` using method = 'loess' and formula = 'y ~ x'
Los valores de data y magpping = aes() declarados en la función ggplot() se consideran globales, cada geometría o capa agregada heredará estos valores, pero pueden ser reemplazados por declaraciones locales dentro de cada geometría. Eso quiere decir que cada geometría puede tener su propio conjunto de datos y su propia forma de mapear los datos en el gráfico, permitiendo así una gran flexibilidad.
En el primer código se mapeó el atributo color con la variable especie, por eso al aplicar geom_smooth() se crea una estimación para cada tipo de especie. En el segundo código, el mapeo de color se hace dentro de geom_point() por lo que solo aplica para esa geometría en particular, al aplicar geom_smooth() no se tiene en cuenta ya que no se ha declarado globalmente dentro de la función ggplot()
Explique cada componente del siguiente gráfico
penguins |>ggplot(aes(x = flipper_length_mm, y = body_mass_g,)) +geom_point(aes(color = species, shape = species), size =2) +geom_smooth(se =FALSE, color ="#8A0200", method ="lm") +labs(title ="Peso Vs Longitud de la aleta",subtitle ="Datos de 3 especies de pingüinos del archipiélago de Palmer",x ="Longitudad de la aleta (mm)",y ="Peso (gr)",color ="Especie",shape ="Especie" )
`geom_smooth()` using formula = 'y ~ x'
Usando el paquete ggthemes podemos mejorar la presentación del gráfico9
9 Intente varios temas
library(ggthemes)penguins |>ggplot(aes(x = flipper_length_mm, y = body_mass_g,)) +geom_point(aes(color = species, shape = species)) +geom_smooth(se =FALSE, method ="lm") +labs(title ="Peso Vs Longitud de la aleta",subtitle ="Datos de 3 especies de pingüinos del archipiélago de Palmer",x ="Longitudad de la aleta (mm)",y ="Peso (gr)",color ="Especie",shape ="Especie" ) + ggthemes::scale_colour_colorblind()
`geom_smooth()` using formula = 'y ~ x'
2.10 Geometrías
Ya que hemos revisado el funcionamiento básico de ggplot2, podemos echarle un vistazo a las geometrías disponibles. La apariencia de la mayoría de ellas puede deducirse de su nombre, podemos encontrar una explicación detallada en la página de referencia de ggplot2
Utilizadas hasta ahora
geom_point()
geom_histogram()
geom_density()
geom_density_2d()
geom_boxplot()
geom_smooth()
Algunas que faltan
geom_abline(), geom_hline(), geom_vline(): Para agregar líneas rectas oblicuas (dado un intercepto y pendiente), horizontales y verticales
geom_bar(), geom_col(): Para construir diagramas de barras
geom_density_2d_filled: Para gráficas de contorno con relleno 🤯
geom_function()
geom_freqpoly()
geom_path(), geom_line()
Como se ha dicho en varias ocasiones, gran parte del trabajo es aprender el tipo de geometría a usar dependiendo del tipo de variables involucradas. Observemos las siguientes gráficas a las que no se les agrega mayor detalle para revisar rápidamente las diferentes geometrías.
2.10.1geom_abline(), geom_hline(), geom_vline()
Las líneas admiten parámetros de linewidth, color, linetype, alpha. El siguiente gráfico no tiene otro propósito diferente al de utilizar varias de estas opciones, aunque el gráfico resultante sea poco útil
Para el caso de geom_hline() y geom_vline() se deben agregar las intercepciones en el eje Y y el eje X, respectivamente. Esto puede hacerse a través de un valor numérico o un vector. Para el caso de geom_abline() se requiere una pendiente (slope) y un intercepto (intercept), ggplot2 reciclará uno de los valores si es necesario.
Los tipos de línea disponibles son: blank, solid, dashed, dotted, dotdash, longdash, twodash. Se pueden identificar de forma ordenada con los dígitos del 0 al 6, por lo que linetype = "dashed" es equivalente a linetype = 2
El gráfico anterior muestra algo interesante, estas geometrías en realidad no necesitan una base de datos para poder crearse, ya que son reglas o funciones. Para los más exigentes en la personalización, se puede crear un patrón con hasta 8 dígitos hexadecimales (1,…,9,a,b,…,f) indicando un patrón de línea y espacio (así que deben ser 2,4,6 u 8 dígitos). El valor 1 es el menor y f el mayor. El patrón “5a3f” indica una línea de longitud 5 seguida de un espacio de longitud a luego una línea de longitud 3 y un espacio de longitud f, este patrón se repetirá hasta completar la gráfica.
geom_bar() y geom_col() son adecuados para hacer gráficas que incluyen variables categóricas, con geom_bar() se cuenta el número de casos de cada categoría y con geom_col() se grafican los valores en los datos para cada categoría.
penguins |>ggplot(aes(x = island)) +geom_bar(fill ="#ddffeeaa", color ="black")
Si agregamos una segunda variable categórica, las barras saldrán apiladas. Mapeamos por ejemplo fill = species
penguins |>ggplot(aes(x = island, fill = species)) +geom_bar()
Algunas veces, es más útil mostrar la proporción de una categoría dentro de otra. En este caso, cómo está distribuida la proporción de cada especie en cada isla
penguins |>ggplot(aes(x = island, fill = species)) +geom_bar(position ="fill")
Podemos agregar las barras por categoría, lado a lado usando position = "dodge" o position = "dodge2", en la segunda opción se agregará un espacio para separar los grupos en cada categoría
p1 <- penguins |>ggplot(aes(x = island, fill = species)) +geom_bar(position ="dodge")p2 <- penguins |>ggplot(aes(x = island, fill = species)) +geom_bar(position ="dodge2")p1; p2
Para mostrar el funcionamiento de geom_col() agrupamos los datos en penguins con la variable species y agregamos algunas variables nuevas10
10 En el siguiente capítulo veremos con detalle estas funciones
`summarise()` has grouped output by 'fact1'. You can override using the
`.groups` argument.
data1
# A tibble: 12 × 3
# Groups: fact1 [4]
fact1 fact2 var_interesante
<chr> <chr> <dbl>
1 a g1 24.1
2 a g2 22.0
3 a g3 16.3
4 b g1 18.2
5 b g2 20.4
6 b g3 19.8
7 c g1 18.8
8 c g2 22.4
9 c g3 20.2
10 d g1 18.7
11 d g2 17.6
12 d g3 20.7
data1 |>ggplot(aes(x = fact1, y = var_interesante, fill = fact2)) +geom_col(position ="dodge2")
2.10.3geom_density_2d_filled()
De uso muy similar a geom_density_2d(), pero agretando un color de relleno al gráfico. Se puede combinar con geom_point() para ofrecer una gráfica más completa. Con todo lo visto hasta ahora, debe ser claro cómo funciona el siguiente código
penguins |>ggplot(aes(x = flipper_length_mm, y = body_mass_g)) +geom_density_2d_filled(alpha =0.5, show.legend =FALSE) +geom_density_2d(color ="black") +xlim(NA, 240) +ylim(2000, 6500) +geom_point(size =0.8, color ="magenta") +labs(title ="Densidad conjunta",subtitle ="Datos de 3 especies de pingüinos del archipiélago de Palmer",x ="Longitudad de la aleta (mm)",y ="Peso (gr)", )
2.10.4geom_function()
Podemos construir curvas a partir de funciones con geom_function(). En el siguiente código, construimos 2 funciones muy sencillas y las agregamos con diferente color, la capacoord_fixed nos sirve para mantener la relación 1 a 1 entre los valores de los ejes coordenados (la mayoría de veces, no es buena idea hacer esto, es mejor dejar que se reescalen los ejes)
f1 <-function(x) x^2f2 <-function(x) x^3ggplot() +geom_function(fun = f1, color ="blue") +geom_function(fun = f2, color ="red") +xlim(-1,1) +coord_fixed()
Podemos usar directamente las funciones de R. A continuación graficamos 3 distribuciones normales con la misma desviación y diferentes valores de la media
Estas geometrías unen puntos con líneas, geom_line() lo hace en orden ascendente de la variable x, mientras que geom_path() lo hace en el orden mismo que aparecen los datos. geom_line() es bastante útil para representar series de tiempo y geom_path() puede bocetar formas irregulares. Usamos la base de datos de serie de tiempo economics_long11 que viene con ggplot2 para mostrar el uso de geom_line(). Agregamos una forma geométrica cualquiera para el uso de geom_path()
11 Tanto economics como economics_long traen la misma información pero una está en formato “ancho” y la otra en formato “largo”, investigue a qué se refieren estos términos
# Revisar los primeros valores de la base de datoseconomics_long
Si tenemos una variable categórica dentro de nuestro conjunto de variables, una forma de analizar su contribución o patrón es mapeando con un atributo del gráfico como fill o color, tal como lo hemos hecho en ocasiones anteriores
penguins |>ggplot(aes(x = bill_length_mm, y = body_mass_g,color = species)) +geom_point()
Otra alternativa es construir un gráfico por separado para cada grupo o valor de la variable categórica, para este ejemplo en particular, sería construir un diagrama de dispersión para cada subconjunto de datos según la especie. Esto es fácil de conseguir usando face_wrap() o face_grid(). La primera alternativa crea un subgráfico de forma lineal para una variable categórica que se incluya usando una fórmula12 y la segunda opción crea un cuadrícula usando 2 variables categóricas. Es más fácil viendo que diciendo
`geom_smooth()` using method = 'loess' and formula = 'y ~ x'
Note que mientras face_wrap() usa una fórmula de un solo lado, face_grid() usa una fórmula de 2 lados.
Por defecto, todos los gráficos compartirán la misma escala en ambos ejes, se puede modificar este comportamiento con el argumento scales, cuyos valores posibles son: fixed (por defecto), free (ambos ejes se ajustan de manera automática según los valores en cada gráfico), free_x (se fija el eje y), free_y (se fija el eje x)
`geom_smooth()` using method = 'loess' and formula = 'y ~ x'
2.12 Más allá de ggplot2
Una de las grandes fortalezas de R para análisis de datos es su increíble cantidad de herramientas para hacer gráficas. Esta gran oferta puede resultar un poco abrumadora al principio, por lo que en este curso nos vamos a basar casi que exclusivamente en ggplot2 para hacer nuestras gráficas y ni siquiera usaremos con regularidad la función base plot. Puede parecer poco, pero ggplot2 es bastante amplio y seguramente no abarcaremos todas las opciones que ofrece.
Dicho eso, vamos a mencionar algunas librerías que agregan fortaleces a ggplot2 o funcionan de forma complementaria y algunas que son ecosistemas totalmente independientes, pero son tan geniales que debemos saber por lo menos que existen.
Ya hemos agregado algunas librerías: ggridges, ggExtra, ggthemes. Podemos encontrar una lista asombrosa de extras para ggplot2aquí
2.12.1patchwork
Esta librería permite combinar de forma sencilla varias gráficas individuales en una sola gráfica. Debemos instalar (install.packages("patchwork")) y cargar (library(patchwork)) el paquete. Revise la página de patchwork para ver los detalles. Para revisar el uso básico, vamos a crear algunos gráficos individuales sencillos y combinarlos de diferentes formas
Podemos agrupar los gráficos con el signo +, patchwork intentará distribuir los gráficos en filas y columnas de forma que el resultado sea lo más cuadrado posible, agregando los gráficos por filas (como si fuese una matriz en R). Podemos forzar la distribución usando plot_layout()
Se puede forzar un layout con “|” para separar columnas y “/” para separar filas. Probemos algunas combinaciones
(p1 / p2) | p3
Picking joint bandwidth of 1.08
(p1 | p4) / p2
p1 / p2 / p3
Picking joint bandwidth of 1.08
(p1 + p2) | p4
Se pueden agregar etiquetas y títulos a cada gráfico de forma normal a cada gráfico individual, también se puede para el conjunto completo, usando plot_annotation(). Con plot_layout() se puede especificar la proporción de ancho y alto para cada columna y fila del arreglo.
(p1 | (p2 / p3 +plot_layout(heights =c(2,1)))) +plot_layout(widths =c(3,2)) +plot_annotation(title ="Un grupo interesante de gráficas",subtitle ="Gráficas bonitas", caption ="Datos de Pingüinos del archipiélago de Palmer" )
Picking joint bandwidth of 1.08
Por último nombraremos 2 paquetes para gráficas pero que juegan en una liga diferente, están basados en librerías de JavaScript por lo que pueden generar gráficas interactivas y son especialmente adecuados para generar reportes con quarto y aplicaciones con shiny
2.12.2dygraphs
El paquete dygraphs de R es una implementación de la librería dygraphs de Javascript. Es bastante usado para graficar datos de series de tiempo. El siguiente ejemplo es tomado de la documentación
# install.packages("dygraphs") # ejecutar desde la consolalibrary(dygraphs)lungDeaths <-cbind(mdeaths, fdeaths)dygraph(lungDeaths) |>dySeries("mdeaths", label ="Male") |>dySeries("fdeaths", label ="Female") |>dyOptions(stackedGraph =TRUE) |>dyRangeSelector(height =20)
2.12.3plotly
plotly es una librería declarativa y de alto nivel basada en D3.js y stack.gl para crear gráficos interactivos. Tiene versiones para python, R, Julia, Javascript, Matlab, F# (¡casi nada!). Ofrece muchos tipos de gráficos para 2 y 3 dimensiones y es un mundo completo para aprender. Por ahora solo nos interesa la función ggplotly que convierte cualquier gráfico estático ggplot en un gráfico interactivo plotly
# install.packages("plotly") # ejecutar desde la consolalibrary(plotly)pp1 <- penguins |>ggplot(aes(x = flipper_length_mm,y = body_mass_g,color = species)) +geom_point(show.legend = F)ggplotly(pp1)