forked from hadley/r4ds
-
Notifications
You must be signed in to change notification settings - Fork 130
/
12-tidy.qmd
547 lines (372 loc) · 26.8 KB
/
12-tidy.qmd
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
# Datos ordenados
## Introducción
> "Todas las familias felices se parecen unas a otras, pero cada familia infeliz lo es a su manera." --– León Tolstoy
> "Todos los set de datos ordenados se parecen unos a otros, pero cada set de datos desordenado lo es a su manera" --- Hadley Wickham
En este capítulo aprenderás una manera consistente para organizar tus datos en R a la que llamaremos __tidy data__ (datos ordenados). Llevar tus datos a este formato requiere algo de trabajo previo; sin embargo, dicho trabajo tiene retorno positivo en el largo plazo. Una vez que tengas tus datos ordenados y las herramientas para ordenar datos que provee el tidyverse, vas a gastar mucho menos tiempo pasando de una forma de representar datos a otra, lo que te permitirá destinar más tiempo a las preguntas analíticas.
Este capítulo te dará una introducción práctica a los datos ordenados (o *tidy data*) y a las herramientas que provee el paquete __tidyr__. Si deseas aprender más acerca de la teoría subyacente, puede que te guste el artículo *Tidy Data* publicado en la revista Journal of Statistical Software, <http://www.jstatsoft.org/v59/i10/paper>.
### Prerrequisitos
En este capítulo nos enfocaremos en **tidyr**, un paquete que provee un conjunto de herramientas que te ayudarán a ordenar datos desordenados. **tidyr** es parte del núcleo del tidyverse.
```{r setup, message = FALSE}
library(tidyverse)
library(datos)
```
## Datos ordenados
Puedes representar los mismos datos subyacentes de múltiples formas. El ejemplo a continuación muestra los mismos datos organizados de cuatro maneras distintas. Cada dataset muestra los mismos valores de cuatro variables ---*pais*, *anio*, *poblacion* y *casos*---, pero cada uno organiza los valores de forma distinta.
```{r}
tabla1
tabla2
tabla3
# Dividido en dos tibbles
tabla4a # casos
tabla4b # poblacion
```
Las anteriores son representaciones de los mismos datos subyacentes, pero no todas son igualmente fáciles de usar. Un tipo de conjunto de datos, el conjunto de datos ordenado, será mucho más fácil de trabajar dentro del tidyverse.
Existen tres reglas interrelacionadas que hacen que un conjunto de datos sea ordenado:
1. Cada variable debe tener su propia columna.
1. Cada observación debe tener su propia fila.
1. Cada valor debe tener su propia celda.
La figura \@ref(fig:tidy-structure) muestra estas reglas visualmente.
```{r tidy-structure, echo = FALSE, out.width = "100%", fig.cap = "Reglas que hacen que un conjunto de datos sea ordenado: las variables están en columnas, las observaciones en filas y los valores en celdas."}
knitr::include_graphics("diagrams_w_text_as_path/es/tidy-1.svg")
```
Estas reglas están interrelacionadas ya que es imposible cumplir solo dos de las tres.
Esta interrelación lleva a un conjunto práctico de instrucciones más simple aún:
1. Coloca cada conjunto de datos en un tibble.
1. Coloca cada variable en una columna.
En este ejemplo, solo la `tabla1` está ordenada. Es la única representación en que cada columna es una variable.
¿Por qué asegurarse de que los datos estén ordenados? Existen dos ventajas principales:
1. Existe una ventaja general al elegir una forma consistente de almacenar datos. Si tienes una estructura de datos consistente, es más fácil aprender las herramientas que funcionan con ella ya que tienen una uniformidad subyacente.
1. Existe una ventaja específica al situar las variables en las columnas, ya que permite que la naturaleza vectorizada de R brille. Como habrás aprendido en las secciones sobre [crear nuevas variables](#mutate-funs) y [resúmenes](#summary-funs), muchas de las funciones que vienen con R trabajan con vectores de valores. Esto hace que transformar datos ordenados se perciba como algo casi natural.
**dplyr**, **ggplot2** y el resto de los paquetes del tidyverse están diseñados para trabajar con datos ordenados. Aquí hay algunos ejemplos de cómo podrías trabajar con `tabla1`.
```{r, out.width = "50%"}
# Calcular tasa por cada 10,000 habitantes
tabla1 %>%
mutate(tasa = casos / poblacion * 10000)
# Calcular casos por anio
tabla1 %>%
count(anio, wt = casos)
# Visualizar cambios en el tiempo
library(ggplot2)
ggplot(tabla1, aes(anio, casos)) +
geom_line(aes(group = pais), colour = "grey50") +
geom_point(aes(colour = pais))
```
### Ejercicios
1. Usando prosa, describe cómo las variables y observaciones se organizan en las tablas de ejemplo.
1. Calcula la `tasa` para las tablas `tabla2` y `tabla4a` + `tabla4b`.
Necesitarás las siguientes operaciones:
1. Extraer el número de casos de tuberculosis por país y año.
1. Extraer la población por país y año.
1. Dividir los casos por la población y multiplicarla por 10000.
1. Insertar los datos de vuelta en el lugar adecuado.
¿Cuál representación es más fácil de trabajar? ¿Cuál es la más difícil? ¿Por qué?
1. Recrea el gráfico que muestra el cambio en el número de casos usando la `tabla2` en lugar de la `tabla1`. ¿Qué necesitas hacer en primero?
## Pivotar
Los principios sobre datos ordenados parecen tan obvios que te podrías preguntar si alguna vez encontrarás un dataset que no esté ordenado. Desafortunadamente, gran parte de los datos que vas a encontrar están desordenados. Existen dos principales razones para esto:
1. La mayoría de las personas no están familiarizadas con los principios de datos ordenados y es difícil derivarlos por cuenta propia a menos que pases _mucho_ tiempo trabajando con datos.
2. Los datos a menudo están organizados para facilitar tareas distintas del análisis. Por ejemplo, los datos se organizan para que su registro sea lo más sencillo posible.
Esto significa que para la mayoría de los análisis necesitarás hacer algún tipo de orden. El primer paso es entender siempre cuáles son las variables y las observaciones. Esto a veces es fácil; otras veces deberás consultar con quienes crearon el dataset. El segundo paso es resolver uno de los siguientes problemas frecuentes:
1. Una variable se extiende por varias columnas
1. Una observación está dispersa entre múltiples filas.
Típicamente, un set de datos tiene uno de estos problemas. Si contiene ambos ¡significa que tienes muy mala suerte! Para solucionar estos problemas necesitarás las dos funciones más importantes de tidyr: `gather()` (reunir) y `spread()` (esparcir/extender).
### Datos "largos"
Un problema común es cuando en un dataset los nombres de las columnas no representan nombres de variables, sino que representan los _valores_ de una variable. Tomando el caso de la `tabla4a`: los nombres de las columnas `1999` y `2000` representan los valores de la variable `año`, los valores en las columnas `1999` y `2000` representan valores de la variable `casos` y cada fila representa dos observaciones en lugar de una.
```{r}
tabla4a
```
Para ordenar un dataset como este necesitamos __pivotar__ las columnas que no cumplen en un nuevo par de variables. Para describir dicha operación necesitamos tres parámetros:
* El conjunto de columnas cuyos nombres son valores y no variables. En este ejemplo son las columnas `1999` y `2000`.
* El nombre de la variable cuyos valores forman los nombres de las columnas. Llamaremos a esto `key` (clave) y en este caso corresponde a `anio`.
* El nombre de la variable cuyos valores están repartidos por las celdas. Llamaremos a esto `value` (valor) y en este caso corresponde al número de `casos`.
Con estos parámetros podemos utilizar la función `pivot_longer()` (_pivotar a lo largo_):
```{r}
tabla4a %>%
pivot_longer(cols = c(`1999`, `2000`), names_to = "anio", values_to = "casos")
```
Las columnas a girar quedan seleccionadas siguiendo el estilo de notación de `dplyr::select()`. En este caso hay solo dos columnas, por lo que las listamos individualmente. Ten en consideración que "1999" y "2000" son nombres no-sintáxicos (debido a que no comienzan con una letra) por lo que los rodeamos con acentos graves (o_backticks_). Para refrescar tu memoria respecto de la selección de columnas, consulta la sección sobre [select](#select). Las variables `anio` y `casos` no existen todavpia en la `tabla4a`, por lo que tenemos que poner sus nombres entre comillas.
```{r tidy-gather, echo = FALSE, out.width = "100%", fig.cap = "Pivotar la `tabla4` para un formato 'largo' y ordenado."}
knitr::include_graphics("diagrams_w_text_as_path/es/tidy-9.svg")
```
En el resultado final, las columnas pivotadas se eliminan y obtenemos la nuevas columnas `anio` y `casos`. La relación entre las variables originales se mantiene, tal como se puede observar en la Figura \@ref(fig:tidy-gather). Podemos usar `pivot_longer()` para ordenar `tabla4b` de modo similar. La única diferencia es la variable almacenada en los valores de las celdas:
```{r}
tabla4b %>%
pivot_longer(cols = c(`1999`, `2000`), names_to = "anio", values_to = "poblacion")
```
Para combinar las versiones ordenadas de `tabla4a` y `tabla4b` en un único tibble, necesitamos usar `dplyr::left_join()`, función que aprenderás en el capítulo sobre [datos relacionales].
```{r}
tidy4a <- tabla4a %>%
pivot_longer(cols = c(`1999`, `2000`), names_to = "anio", values_to = "casos")
tidy4b <- tabla4b %>%
pivot_longer(cols = c(`1999`, `2000`), names_to = "anio", values_to = "poblacion")
left_join(tidy4a, tidy4b)
```
### Datos "anchos"
`pivot_wider()` (_pivotar a lo ancho_) es lo opuesto de `pivot_longer()`. Se usa cuando una observación aparece en múltiples filas. Por ejemplo, considera la `tabla2`: una observación es un país en un año, pero cada observación aparece en dos filas.
```{r}
tabla2
```
Para ordenar esto, primero analizamos la representación de un modo similar a cómo se haría con `pivot_longer()`. Esta vez, sin embargo, necesitamos únicamente dos parámetros:
* La columna desde la que obtener los nombres de las variables. En este caso corresponde a `tipo`.
* La columna desde la que obtener los valores. En este caso corresponde a `cuenta`.
Una vez resuelto esto, podemos usar `pivot_wider()`, como se muestra programáticamente abajo y visualmente en la Figura \@ref(fig:tidy-spread).
```{r}
tabla2 %>%
pivot_wider(names_from = tipo, values_from = cuenta)
```
```{r tidy-spread, echo = FALSE, out.width = "100%", fig.cap = "Pivotar la `tabla2` para un formato 'ancho' y ordenado"}
knitr::include_graphics("diagrams_w_text_as_path/es/tidy-8.svg")
```
Como te habrás dado cuenta a partir de sus nombres, las funciones `pivot_longer()` y `pivot_wider()` son complementarias. `pivot_longer()` genera tablas angostas y largas, `pivot_wider()` genera tablas anchas y cortas.
### Ejercicios
1. ¿Por qué `pivot_longer()` y `pivot_wider()` no son perfectamente simétricas?
Observa cuidadosamente el siguiente ejemplo:
```{r, eval = FALSE}
acciones <- tibble(
anio = c(2015, 2015, 2016, 2016),
semestre = c(1, 2, 1, 2),
retorno = c(1.88, 0.59, 0.92, 0.17)
)
acciones %>%
pivot_wider(names_from = anio, values_from = retorno) %>%
pivot_longer(`2015`:`2016`, names_to = "anio", values_to = "retorno")
```
(Sugerencia: observa los tipos de variables y piensa en los nombres de las columnas)
`pivot_longer()` tiene el argumento `names_ptype`: por ejemplo: `names_ptype = list(year = double())`. ¿Qué es lo que hace dicho argumento?
1. ¿Por qué falla el siguiente código?
```{r, error = TRUE}
tabla4a %>%
pivot_longer(c(1999, 2000), names_to = "anio", values_to = "casos")
```
1. ¿Qué pasaría si trataras de pivotar esta tabla a lo ancho? ¿Por qué? ¿Cómo podrías agregar una nueva columna que identifique de manera única cada valor?
```{r}
personas <- tribble(
~nombre, ~nombres, ~valores,
#-----------------|--------|------
"Phillip Woods", "edad", 45,
"Phillip Woods", "estatura", 186,
"Phillip Woods", "edad", 50,
"Jessica Cordero", "edad", 37,
"Jessica Cordero", "estatura", 156
)
```
1. Ordena la siguiente tabla. ¿Necesitas alargarla o ensancharla? ¿Cuáles son las variables?
```{r}
embarazo <- tribble(
~embarazo, ~hombre, ~mujer,
"sí", NA, 10,
"no", 20, 12
)
```
## Separar y unir
Hasta ahora has aprendido a ordenar las tablas `tabla2` y `tabla4`, pero no la `tabla3`, que tiene un problema diferente: tenemos una columna (`tasa`) que contiene dos variables (`casos` y `poblacion`). Para solucionar este problema, necesitamos la función `separate()` (_separar_). También aprenderás acerca del complemento de `separate()`: `unite()` (_unir_), que se usa cuando una única variable se reparte en varias columnas.
### Separar
`separate()` desarma una columna en varias columnas, dividiendo de acuerdo a la posición de un carácter separador. Tomemos la `tabla3`:
```{r}
tabla3
```
La columna `tasa` contiene tanto los `casos` como la `poblacion`, por lo que necesitamos dividirla en dos variables. La función `separate()` toma el nombre de la columna a separar y el nombre de las columnas a donde irá el resultado, tal como se muestra en la Figura \@ref(fig:tidy-separate) y el código a continuación.
```{r}
tabla3 %>%
separate(tasa, into = c("casos", "poblacion"))
```
```{r tidy-separate, echo = FALSE, out.width = "75%", fig.cap = "Separar la `tabla3` la vuelve ordenada"}
knitr::include_graphics("diagrams_w_text_as_path/es/tidy-17.svg")
```
Por defecto, `separate()` dividirá una columna donde encuentre un carácter no alfanumérico (esto es, un carácter que no es un número o letra). Por ejemplo, en el siguiente código, `separate()` divide los valores de `tasa` donde aparece una barra (`/`). Si deseas usar un carácter específico para separar una columna, puedes especificarlo en el argumento `sep` de `separate()`. Por ejemplo, el código anterior se puede re-escribir del siguiente modo:
```{r eval = FALSE}
tabla3 %>%
separate(tasa, into = c("casos", "poblacion"), sep = "/")
```
(Formalmente, `sep` es una expresión regular y aprenderás más sobre esto en el capítulo sobre [cadenas de caracteres].)
Mira atentamente los tipos de columna: notarás que `casos` y `poblacion` son columnas de tipo carácter. Este es el comportamiento por defecto en `separate()`: preserva el tipo de columna. Aquí, sin embargo, no es muy útil, ya que se trata de números. Podemos pedir a separate() que intente convertir a un tipo más adecuado usando `convert = TRUE`:
```{r}
tabla3 %>%
separate(tasa, into = c("casos", "poblacion"), convert = TRUE)
```
También puedes pasar un vector de enteros a `sep`. `separate()` interpreta los enteros como las posiciones donde dividir. Los valores positivos comienzan en 1 al extremo izquierdo de las cadenas de texto; los valores negativos comienzan en -1 al extremo derecho. Cuando uses enteros para separar cadenas de texto, el largo de `sep` debe ser uno menos que el número de nombres en `into`.
Puedes usar este arreglo para separar los últimos dos dígitos de cada año. Esto deja los datos menos ordenados, pero es útil en otros casos, como se verá más adelante.
```{r}
tabla3 %>%
separate(anio, into = c("siglo", "anio"), sep = 2)
```
### Unir
`unite()` es el inverso de `separate()`: combina múltiples columnas en una única columna. Necesitarás esta función con mucha menos frecuencia que `separate()`, pero aún así es una buena herramienta para tener en el bolsillo trasero.
```{r tidy-unite, echo = FALSE, out.width = "75%", fig.cap = "Unir la `tabla5` la vuelve ordenada"}
knitr::include_graphics("diagrams_w_text_as_path/es/tidy-18.svg")
```
Podemos usar `unite()` para unir las columnas *siglo* y *anio* creadas en el ejemplo anterior. Los datos están guardados en `datos::tabla5`. `unite()` toma un data frame, el nombre de la nueva variable a crear y un conjunto de columnas a combinar, las que se especifican siguiendo el estilo de la función `dplyr::select()`:
```{r}
tabla5 %>%
unite(nueva, siglo, anio)
```
En este caso también necesitamos el argumento `sep`. Por defecto, pondrá un guión bajo (`_`) entre los valores de las distintas columnas. Si no queremos ningún separador usamos `""`:
```{r}
tabla5 %>%
unite(nueva, siglo, anio, sep = "")
```
### Ejercicios
1. ¿Qué hacen los argumentos `extra` y `fill` en `separate()`?
Experimenta con las diversas opciones a partir de los siguientes datasets de ejemplo.
```{r, eval = FALSE}
tibble(x = c("a,b,c", "d,e,f,g", "h,i,j")) %>%
separate(x, c("one", "two", "three"))
tibble(x = c("a,b,c", "d,e", "f,g,i")) %>%
separate(x, c("one", "two", "three"))
```
1. Tanto `unite()` como `separate()` tienen un argumento `remove`. ¿Qué es lo que hace?
¿Por qué lo dejarías en `FALSE`?
1. Compara y contrasta `separate()` y `extract()`. ¿Por qué existen tres variaciones de
separación (por posición, separador y grupos), pero solo una forma de unir?
## Valores faltantes
Cambiar la representación de un dataset conlleva el riesgo de generar valores faltantes. Sorprendentemente, un valor puede perderse de dos formas:
* __Explícita__, esto es, aparece como `NA`.
* __Implícita__, esto es, simplemente no aparece en los datos.
Ilustremos esta idea con un dataset muy sencillo:
```{r}
acciones <- tibble(
anio = c(2015, 2015, 2015, 2015, 2016, 2016, 2016),
trimestre = c(1, 2, 3, 4, 2, 3, 4),
retorno = c(1.88, 0.59, 0.35, NA, 0.92, 0.17, 2.66)
)
```
Existen dos valores faltantes en este dataset:
* El retorno del cuarto trimestre de 2015 que está explícitamente perdido, debido a que la celda donde el valor debiera estar contiene `NA`.
* El retorno del primer semestre de 2016 está implícitamente perdido, debido a que simplemente no aparece en el set de datos.
Una forma de pensar respecto de esta diferencia es al estilo de un kōan Zen: Un valor faltante explícito es la presencia de una ausencia; un valor faltante implícito es la ausencia de una presencia.
La forma en que se representa un dataset puede dejar explícitos los valores implícitos. Por ejemplo, podemos volver explícitos los valores faltantes implícitos al mover los años a las columnas:
```{r}
acciones %>%
spread(anio, retorno)
```
Debido a que estos valores faltantes explícitos pueden no ser tan importantes en otras representaciones de los datos, puedes especificar `na.rm = TRUE` en `gather()` para dejar explícitos los valores faltantes implícitos:
```{r}
acciones %>%
pivot_wider(names_from = anio, values_from = retorno) %>%
pivot_longer(
cols = c(`2015`, `2016`),
names_to = "anio",
values_to = "retorno",
values_drop_na = TRUE
)
```
Otra herramienta importante para hacer explícitos los valores faltantes en datos ordenados es `complete()`:
```{r}
acciones %>%
complete(anio, trimestre)
```
`complete()` toma un conjunto de columnas y encuentra todas las combinaciones únicas. Luego se asegura de que el dataset original contenga todos los valores, completando con `NA`s donde sea necesario.
Existe otra herramienta importante que deberías conocer al momento de trabajar con valores faltantes. En algunos casos en que la fuente de datos se ha usado principalmente para ingresar datos, los valores faltantes indican que el valor previo debe arrastrarse hacia adelante:
```{r}
tratamiento <- tribble(
~sujeto, ~tratamiento, ~respuesta,
"Derrick Whitmore", 1, 7,
NA, 2, 10,
NA, 3, 9,
"Katherine Burke", 1, 4
)
```
Puedes completar los valores faltantes usando `fill()`. Esta función toma un conjunto de columnas sobre las cuales los valores faltantes son reemplazados por el valor anterior más cercano que se haya reportado (también conocido como el método LOCF, del inglés *last observation carried forward*).
```{r}
tratamiento %>%
fill(sujeto)
```
### Ejercicios
1. Compara y contrasta el argumento `fill` que se usa en `pivot_wider()` con `complete()`.
1. ¿Qué hace el argumento de dirección en `fill()`?
## Estudio de caso
Para finalizar el capítulo, combinemos todo lo que aprendiste para enfrentar un problema real de ordenamiento de datos. El dataset `datos::oms` contiene datos de tuberculosis (TB) detallados por año, país, edad, sexo y método de diagnóstico. Los datos provienen del *Informe de Tuberculosis de la Organización Mundial de la Salud 2014*, disponible en <http://www.who.int/tb/country/data/download/en/>.
Existe abundante información epidemiológica en este dataset, pero es complicado trabajar con estos datos tal como son entregados:
```{r}
oms
```
Este es un ejemplo muy típico de un dataset de la vida real. Contiene columnas redundantes, códigos extraños de variables y muchos valores faltantes. En breve, `oms` está desordenado y necesitamos varios pasos para ordenarlo. Al igual que **dplyr**, **tidyr** está diseñado de modo tal que cada función hace bien una cosa. Esto significa que en una situación real deberás encadenar múltiples verbos.
LCasi siempre, la mejor forma de comenzar es reunir las columnas que no representan variables. Miremos lo que hay:
* Pareciera ser que `pais`, `iso2` e `iso3` son variables redundantes que se refieren al país.
* `anio` es claramente una variable.
* No sabemos aún el significado de las otras columnas, pero dada la estructura de los nombres de las variables (e.g. `nuevos_fpp_h014`, `nuevos_ep_h014`, `nuevos_ep_m014`) parecieran ser valores y no variables.
Necesitamos agrupar todas las columnas desde `nuevos_fpp_h014` hasta `recaidas_m65`. No sabemos aún qué representa esto, por lo que le daremos el nombre genérico de `"clave"`. Sabemos que las celdas representan la cuenta de casos, por lo que usaremos la variable `casos`.
Existen múltiples valores faltantes en la representación actual, por lo que de momento usaremos `na.rm` para centrarnos en los valores que están presentes.
```{r}
oms1 <- oms %>%
pivot_longer(
cols = nuevos_fpp_h014:nuevosrecaida_m65,
names_to = "clave",
values_to = "casos",
values_drop_na = TRUE
)
oms1
```
Podemos tener una noción de la estructura de los valores en la nueva columna `clave` si hacemos un conteo:
```{r}
oms1 %>%
count(clave)
```
Podrías resolver esto por tu cuenta pensando y experimentando un poco, pero afortunadamente tenemos el diccionario de datos a mano. Este nos dice lo siguiente:
1. Lo que aparece antes del primer `_` en las columnas indica si la columna contiene casos nuevos o antiguos de
tuberculosis. En este dataset, cada columna contiene nuevos casos.
2. Lo que aparece luego de indicar si se refiere casos nuevos o antiguos es el tipo de tuberculosis:
* `recaida` se refiere a casos reincidentes
* `ep` se refiere a tuberculosis extra pulmonar
* `fpn` se refiere a casos de tuberculosis pulmonar que no se pueden detectar mediante examen de frotis pulmonar (frotis pulmonar negativo)
* `fpp` se refiere a casos de tuberculosis pulmonar que se pueden detectar mediante examen de frotis pulmonar (frotis pulmonar positivo)
3. La letra que aparece después del último `_` se refiere al sexo de los pacientes. El conjunto de datos agrupa en hombres (`h`) y mujeres (`m`).
4. Los números finales se refieren al grupo etareo que se ha organizado en siete categorías:
* `014` = 0 -- 14 años de edad
* `1524` = 15 -- 24 años de edad
* `2534` = 25 -- 34 años de edad
* `3544` = 35 -- 44 años de edad
* `4554` = 45 -- 54 años de edad
* `5564` = 55 -- 64 años de edad
* `65` = 65 o más años de edad
Necesitamos hacer un pequeño cambio al formato de los nombres de las columnas: desafortunadamente lo nombres de las columnas son ligeramente inconsistentes debido a que en lugar de `nuevos_recaida` tenemos `nuevosrecaida` (es difícil darse cuenta de esto en esta parte, pero si no lo arreglas habrá errores en los pasos siguientes). Aprenderás sobre `str_replace()` en [cadenas de caracteres], pero la idea básica es bastante simple: reemplazar los caracteres "nuevosrecaida" por "nuevos_recaida". Esto genera nombres de variables consistentes.
```{r}
oms2 <- oms1 %>%
mutate(clave = stringr::str_replace(clave, "nuevosrecaida", "nuevos_recaida"))
oms2
```
Podemos separar los valores en cada código aplicando `separate()` dos veces. La primera aplicación dividirá los códigos en cada `_`.
```{r}
oms3 <- oms2 %>%
separate(clave, c("nuevos", "tipo", "sexo_edad"), sep = "_")
oms3
```
A continuación podemos eliminar la columna `nuevos`, ya que es constante en este dataset. Además eliminaremos `iso2` e `iso3` ya que son redundantes.
```{r}
oms3 %>%
count(nuevos)
oms4 <- oms3 %>%
select(-nuevos, -iso2, -iso3)
```
Luego separamos `sexo_edad` en `sexo` y `edad` dividiendo luego del primer carácter:
```{r}
oms5 <- oms4 %>%
separate(sexo_edad, c("sexo", "edad"), sep = 1)
oms5
```
¡Ahora el dataset `oms` está ordenado!
Hemos mostrado el código parte por parte, asignando los resultados intermedios a nuevas variables. Esta no es la forma típica de trabajo. En cambio, lo que se hace es formar incrementalmente un encadenamiento complejo usando _pipes_:
```{r, results = "hide"}
oms %>%
pivot_longer(
cols = nuevos_fpp_h014:nuevosrecaida_m65,
names_to = "clave",
values_to = "valor",
values_drop_na = TRUE) %>%
mutate(clave = stringr::str_replace(clave, "nuevosrecaida", "nuevos_recaida")) %>%
separate(clave, c("nuevos", "tipo", "sexo_edad")) %>%
select(-nuevos, -iso2, -iso3) %>%
separate(sexo_edad, c("sexo", "edad"), sep = 1)
```
### Ejercicios
1. En este caso de estudio fijamos `values_drop_na = TRUE` para hacer más simple el verificar que tenemos los valores correctos. ¿Es esto razonable? Piensa en cómo los valores faltantes están representados en este dataset. ¿Existen valores faltantes implícitos? ¿Cuál es la diferencia entre `NA` y cero?
1. ¿Qué ocurre si omites la aplicación de `mutate()`?
(`mutate(clave = stringr::str_replace(clave, "nuevosrecaida", "nuevos_recaida"))`)
1. Afirmamos que `iso2` e `iso3` son redundantes respecto a `pais`. Confirma esta aseveración.
1. Para cada país, año y sexo calcula el total del número de casos de tuberculosis. Crea una visualización informativa de los datos.
## Datos no ordenados
Antes de pasar a otros tópicos, es conveniente referirse brevemente a datos no ordenados. Anteriormente en el capítulo, usamos el término peyorativo "desordenados" para referirnos a datos no ordenados. Esto es una sobresimplificación: existen múltiples estructuras de datos debidamente fundamentadas que no corresponden a datos ordenados. Existen dos principales razones para usar otras estructuras de datos:
* Las representaciones alternativas pueden traer ventajas importantes en términos de desempeño o tamaño.
* Algunas áreas especializadas han evolucionado y tienen sus propias convenciones para almacenar datos, las que pueden diferir respecto de las convenciones de datos ordenados.
Cada uno de estas razones significa que necesitarás algo distinto a un tibble (o data frame). Si tus datos naturalmente se ajustan a una estructura rectangular compuesta de observaciones y variables, pensamos que datos ordenados debería ser tu elección por defecto. Sin embargo, existen buenas razones para usar otras estructuras; los datos ordenados no son la única forma.
Si quieres aprender más acerca de datos no ordenados, recomendamos fuertemente este artículo del blog de Jeff Leek:
<http://simplystatistics.org/2016/02/17/non-tidy-data/>