Análisis exploratorio de datos con tidyverse

Parte 1: Fundamentos de análisis exploratorio en R

Autores

Rodrigo Zepeda-Tello

Última actualización

October 11, 2022

Resumen
Mostramos cómo funciona dplyr para filtrar (filter), seleccionar (select), mutar (mutate), agrupar (group_by), y resumir (summarise) bases de datos en R
Note

Los datos están disponibles en el Github y en Dropbox

Warning

Si aún no cuentas con una instalación de tidyverse dentro de R corre la siguiente instrucción:

install.packages("tidyverse")

1 El flujo de trabajo de trabajo con datos

En general el flujo de trabajo de un análisis de datos se divide en tres componentes principales:

  1. Preparación de los datos lo que incluye la recolección (no discutida aquí), la importación de los datos y la limpieza inicial (por ejemplo el poner nombres a las columnas u homologar mayúsculas y minúsculas) para generar una base de trabajo.
Warning

Una vez recolectados la recomendación es que las bases de datos no se toquen una vez se tiene la información. Entre menos modifiquemos la base de datos hay menor probabilidad de cometer errores y accidentes que resulten en pérdida de información.

  1. Análisis de datos incluye tres pasos que fluyen en cualquier orden:
  1. Formulación de preguntas ¿qué me gustaría saber de mis datos?_
  2. Visualización de los datos ¿puede una gráfica ayudarme a responder mi pregunta u orientarme hacia qué analizar?
  3. Análisis de los datos: ¿qué resumen de la información (por ejemplo una tabla o un promedio) resulta eficaz para presentar lo que me interesa?
  1. Una vez se tienen los datos analizados continuamos a la parte de comunicación donde buscamos generar tablas, gráficas y reportes (entre otros) que comuniquen nuestros datos al público.

El siguiente diagrama (traducido de aquí) intenta resumir el flujo de trabajo:

flowchart TB;

    subgraph C[Comunicación]
       Tablas --> Reportes
       G[Gráficas] --> Reportes
    end
    
    subgraph AD[Análisis de datos]
        FP[Preguntas]  --> V[Visualización]
        V  --> FP
        V  --> AN[Análisis]
        AN --> FP
        AN --> V
        FP --> AN
    end

    subgraph PD[Preparación de los datos]
        R[Recolección] --> I[Importación]
        I  --> L[Limpieza]
    end

    PD --> AD --> C

2 Armado de un proyecto

En RStudio para un proyecto de análisis de datos la recomendación es crear un Project. Ésta es una carpeta especial en la cual se almacena todo el código, las bases de datos e incluso los registros de las versiones de los paquetes que estás usando Con pasarle a otra persona tu proyecto (Project) ésta podrá reproducir absolutamente todo sin preocuparse por tener que acomodar las rutas a los archivos o instalar los paquetes que tú usaste.

Para armar un proyecto puedes ir a File > New Project. Esto abrirá una ventana como sigue:

Opciones de proyecto incluyen nuevo directorio o existente así como control de versiones

Existen diferentes opciones: empezar a crear un proyecto desde cero (New Directory) o bien trabajar con algún folder que ya tenemos Existing directory. El control de versiones (Version Control) es una herramienta más avanzada de programación y no la discutiremos por ahora.

Elige la opción de New Directory y en la ventana que sigue elige New R Proyect. Notarás que esto sirve para muchas cosas entre ellas armar presentaciones y páginas web. Por ahora trabajaremos sólo con código normal.

Las opciones de tipo de proyecto incluyen blogs, páginas web y libros. Por ahora comenzamos con New Proyect para hacer un proyecto nuevo sin opciones específicas de los otros tipos.

Finalmente en la tercer ventana elegimos el nombre del proyecto, el folder dentro de nuestros documentos donde habrá de guardarse y activamos las opciones:

  • renv sirve para controlar los paquetes de R usados. Si eliges la opción renv, cualquier otra persona que use el proyecto se le instalarán los paquetes que tú usaste y las versiones específicas (digamos tu ggplot2 es del 2021 entonces esa persona tendrá ese ggplot2 cuando abra el proyecto).

  • git sirve para guardar un historial de tu código. Explicaremos más adelante su funcionamiento principal pero la idea es que se guarde cada cambio que haces en el código (pues ctrl Z es limitado).

  • Open in new session cierra la ventana actual de RStudio y te abre el proyecto en un nuevo lienzo en blanco para que comiences tu trabajo.

Un nuevo proyecto con nombre AnalisisDatos, en mi carpeta de Dropbox con las opciones de git y renv habilitadas. Se solicitó a R además abrir en una sesión nueva.

Una vez iniciado el proyecto nos aparecerá un mensaje similar a este en una nueva consola de `R``:

The version of R recorded in the lockfile will be updated:
- R      [*] -> [4.2.1]

* Lockfile written to '~/AnalisisDatos/renv.lock'.

¡Podemos empezar a usarlo!

Warning

Todas las bases de datos que utilicemos dentro de estas notas supondremos están almacenadas dentro del proyecto AnalisisDatos el cual está en tus documentos donde sea hayas elegido.

Por favor copia todos los datos que uses dentro del proyecto para que así, a cualquier persona que le envíes el proyecto pueda usarlo.

3 Lectura de bases de datos

R sirve para abrir cualquier tipo de dato. En particular es posible leer bases de datos desde Excel, csv, txt, Stata. También (aunque no lo veremos) puede leer imágenes, videos, datos provenientes de documentos pdf, páginas web, mapas, etc. Al día de hoy no he encontrado un sólo tipo de dato que no pueda leer R.

Las bases de datos si ya están recolectadas no se tocan. Lo que haremos en R será leerlas, copiarlas en una base nueva y trabajar sobre la base nueva sin modificar la original. De esta forma, cualquier error que cometamos ¡y seguro cometeremos muchos! no afectará la original. Esto permite además tener un flujo de trabajo seguro (en el sentido de que estamos seguros que no borraremos nada).

3.1 Lectura de datos desde un archivo delimitado (csv ó txt).

Los documentos de datos, si son (relativamente) medianas, pueden ser compartidos en archivos de texto que se pueden abrir con el bloc de notas. Por ejemplo, el documento casos_covid_agosto_2022.csv se ve como sigue:

"FECHA_SINTOMAS","n"
"2020-01-01","287"
"2020-01-02","233"
"2020-01-03","247"
"2020-01-04","245"

por otro lado el documento embarazo_adolescente.txt es un archivo delimitado por tabs (a veces llamados tsv) donde cada columna ocurre después de un tab (espacio largo):

Location    PovPct  Brth15to17  Brth18to19  ViolCrime   TeenBrth
Alabama 20.1    31.5    88.7    11.2    54.5
Alaska  7.1 18.9    73.7    9.1 39.5
Arizona 16.1    35  102.5   10.4    61.2
Arkansas    14.9    31.6    101.7   10.4    59.9

finalmente, covid_sinave_bc_bcs.txt es un archivo donde las columnas son separadas por |:

SECTOR|ENTIDAD_UM|SEXO|ENTIDAD_NAC|ENTIDAD_RES|TIPO_PACIENTE|FECHA_INGRESO|FECHA_SINTOMAS|FECHA_DEF|EDAD|HABLA_LENGUA_INDIG|DIABETES|TOMA_MUESTRA_LAB|RESULTADO_LAB|TOMA_MUESTRA_ANTIGENO|RESULTADO_ANTIGENO|CLASIFICACION_FINAL|UCI
4|03|2|12|03|1|2021-07-05T00:00:00Z|2021-07-04T00:00:00Z|NA|22|2|2|2|97|1|1|3|97
4|03|2|03|03|1|2021-07-12T00:00:00Z|2021-07-11T00:00:00Z|NA|52|2|1|2|97|1|2|7|97
4|03|2|03|03|1|2021-07-22T00:00:00Z|2021-07-19T00:00:00Z|NA|19|2|2|2|97|1|2|7|97
12|03|1|03|03|1|2021-07-15T00:00:00Z|2021-07-13T00:00:00Z|NA|10|2|2|2|97|1|1|3|97

Todos estos archivos son archivos de texto simple delimitados y se pueden leer con la librería readr.

Lectura simple

Para leer los archivos basta con File > Import dataset o bien con código:

casos_covid <- read_csv("casos_covid_agosto_2022.csv")

Para los archivos delimitados por espacios podemos usar read_tsv:

adolescentes <- read_tsv("embarazo_adolescente.txt")

Finalmente archivos con delimitadores que no son comas ni tabs (como los | ) puedes usar read_delim y especificar el separador delim:

covid <- read_delim("covid_sinave_bc_bcs.txt", delim = "|")

Complicaciones

La base de datos zapopan.csv contiene las estimaciones de la población del municipio homónimo por parte del INEGI. Sin embargo, al momento de leerla pasan dos cosas:

  1. Los acentos en algunos equipos no se leen bien
  2. La primera fila no representa nada pues sólo dice Datos.

Aquí una muestra de cómo viene el archivo. Nota que en mi equipo los acentos y las ñ aparecen como el símbolo ?:

Datos Poblacionales,,,,,,,,,,, Unidad,Nombre Unidad,Zona Coplademun,Habitantes,Hombres,Mujeres,Poblacin de 0 a 14 Aos,Poblacin de 15 a 64 Aos,Poblacin Mayor de 18 Aos,Viviendas Habitadas,Promedio de Ocupantes por Vivienda,Clave INEGI 1,12 de diciembre,7,“1,782”,“1,005”,953,759,“1,143”,“1,012”,394,5.221,0 2,27 de Septiembre,1B,“1,730”,824,906,469,“1,122”,“1,171”,478,4.141666667,001-F 3,“Abetos, Los”,1B,367,179,188,121,240,231,101,3.63,002-L

Para leer esta base es necesario saltarnos la primera fila pues Datos Poblacionales no es un nombre de columna. Para ello usamos skip = 1 indicándole que se salte (skip) una fila (= 1). Por otro lado para los acentos usamos el encoding de WINDOWS-1252. Los más comunes para acentos en México son UTF-8 y WINDOWS-1252. Cuando no leemos bien los acentos vale la pena probar ambos para hallar el correcto:

zapopan <- read_csv("zapopan.csv", 
                    locale = locale(encoding = "WINDOWS-1252"), 
                    skip = 1)

3.2 Lectura de datos desde un Excel

Lectura simple

Para leer datos desde un Excel podemos usar la Import From > Excel o bien read_excel dentro de la librería readxl:

library(readxl)

dado un archivo como persona_cigarros.xlsx podemos leerlo directamente:

cigarros <- read_excel("persona_cigarros.xlsx")

Complicaciones

Algunos archivos como Poblacion_01.xlsx contienen filas tanto al inicio como al final que funcionan como descriptores del archivo. Al momento de leerlo debemos ignorar estas partes:

Opciones de proyecto incluyen nuevo directorio o existente así como control de versiones

Para ello en read_excel podemos especificar el rango de las celdas que nos interesa exportar indicando las dos esquinas del rectángulo de celdas:

poblacion <- read_excel("Poblacion_01.xlsx", range = "A5:C38")

3.3 Ejercicios

  1. Lee las bases de datos ile-2019-2021.csv, IME_2020.xls y niños.txt.

4 Análisis de bases de datos

Vamos a leer la base de datos conjunto_de_datos_defunciones_generales_2017.csv la cual contiene el registro de mortalidad en México para el año 2017 del INEGI:

mortalidad_2017 <- read_csv("conjunto_de_datos_defunciones_generales_2017.csv")

Aquí sólo muestro las filas de la base:

ent_regis mun_regis ent_resid mun_resid tloc_resid loc_resid ent_ocurr mun_ocurr tloc_ocurr loc_ocurr causa_def lista_mex sexo edad dia_ocurr mes_ocurr anio_ocur dia_regis mes_regis anio_regis dia_nacim mes_nacim anio_nacim ocupacion escolarida edo_civil presunto ocurr_trab lugar_ocur necropsia asist_medi sitio_ocur cond_cert nacionalid derechohab embarazo rel_emba horas minutos capitulo grupo lista1 gr_lismex vio_fami area_ur edad_agru complicaro dia_cert mes_cert anio_cert maternas lengua cond_act par_agre ent_ocules mun_ocules loc_ocules razon_m dis_re_oax
01 001 01 001 15 0001 01 001 15 0001 I679 30Z 2 4068 26 7 1994 19 1 2017 99 99 1926 11 3 3 8 8 88 9 1 1 2 1 1 8 8 8 45 9 7 069 30 8 1 18 8 99 1 2017 NA 9 2 88 88 888 8888 0 999
01 009 01 009 1 0016 01 009 1 0016 I64X 30D 2 4090 10 11 2011 30 1 2017 31 10 1921 11 3 5 8 8 88 2 1 11 3 1 7 8 8 19 0 9 7 069 30 8 2 23 8 99 1 2017 NA 9 2 88 88 888 8888 0 999
01 001 01 001 15 0001 01 001 15 0001 E112 20D 1 4088 12 2 2011 99 1 2017 19 11 1922 4 3 3 8 8 88 2 2 11 3 1 2 8 8 7 0 4 2 052 20 8 1 22 8 99 1 2017 NA 9 1 88 88 888 8888 0 999
01 006 01 006 8 0001 01 006 8 0001 X590 51Z 2 4096 27 12 2016 10 1 2017 20 1 1920 11 3 3 1 9 9 9 1 1 1 1 7 8 8 11 10 20 25 103 E51 8 1 24 8 27 12 2016 NA 2 2 88 88 888 8888 0 999
01 001 01 001 15 0001 01 001 15 0001 I251 28Z 2 4051 1 3 2016 13 1 2017 11 11 1964 9 1 2 8 8 88 2 1 11 3 1 99 9 9 14 30 9 4 067 28 8 1 15 9 1 3 2016 NA 9 1 88 88 888 8888 0 999
01 001 01 001 15 0001 01 001 15 0001 N009 38A 1 4078 1 7 2016 10 1 2017 8 5 1938 11 3 5 8 8 88 2 1 3 3 1 2 8 8 17 15 14 1 085 38 8 1 20 8 1 7 2016 NA 2 2 88 88 888 8888 0 999

La función glimpse nos permite darnos una idea de la composición de nuestros datos:

mortalidad_2017 %>% glimpse() 
Rows: 703,047
Columns: 59
$ ent_regis  <chr> "01", "01", "01", "01", "01", "01", "01", "01", "01", "01",…
$ mun_regis  <chr> "001", "009", "001", "006", "001", "001", "001", "001", "00…
$ ent_resid  <chr> "01", "01", "01", "01", "01", "01", "01", "01", "01", "01",…
$ mun_resid  <chr> "001", "009", "001", "006", "001", "001", "001", "001", "00…
$ tloc_resid <dbl> 15, 1, 15, 8, 15, 15, 15, 15, 15, 5, 15, 1, 15, 15, 1, 15, …
$ loc_resid  <chr> "0001", "0016", "0001", "0001", "0001", "0001", "0001", "00…
$ ent_ocurr  <chr> "01", "01", "01", "01", "01", "01", "01", "01", "01", "01",…
$ mun_ocurr  <chr> "001", "009", "001", "006", "001", "001", "001", "001", "00…
$ tloc_ocurr <dbl> 15, 1, 15, 8, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 1…
$ loc_ocurr  <chr> "0001", "0016", "0001", "0001", "0001", "0001", "0001", "00…
$ causa_def  <chr> "I679", "I64X", "E112", "X590", "I251", "N009", "E129", "M6…
$ lista_mex  <chr> "30Z", "30D", "20D", "51Z", "28Z", "38A", "20D", "37H", "09…
$ sexo       <dbl> 2, 2, 1, 2, 2, 1, 1, 2, 2, 1, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1,…
$ edad       <dbl> 4068, 4090, 4088, 4096, 4051, 4078, 4070, 4079, 4061, 4069,…
$ dia_ocurr  <dbl> 26, 10, 12, 27, 1, 1, 19, 20, 7, 18, 18, 20, 1, 20, 28, 20,…
$ mes_ocurr  <dbl> 7, 11, 2, 12, 3, 7, 12, 10, 1, 1, 12, 1, 1, 1, 11, 1, 12, 1…
$ anio_ocur  <dbl> 1994, 2011, 2011, 2016, 2016, 2016, 2016, 2016, 2017, 2017,…
$ dia_regis  <dbl> 19, 30, 99, 10, 13, 10, 13, 4, 11, 25, 3, 24, 9, 25, 2, 24,…
$ mes_regis  <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,…
$ anio_regis <dbl> 2017, 2017, 2017, 2017, 2017, 2017, 2017, 2017, 2017, 2017,…
$ dia_nacim  <dbl> 99, 31, 19, 20, 11, 8, 15, 22, 15, 1, 26, 18, 13, 28, 16, 4…
$ mes_nacim  <dbl> 99, 10, 11, 1, 11, 5, 3, 6, 5, 2, 2, 5, 9, 9, 6, 7, 6, 7, 1…
$ anio_nacim <dbl> 1926, 1921, 1922, 1920, 1964, 1938, 1946, 1937, 1955, 1947,…
$ ocupacion  <dbl> 11, 11, 4, 11, 9, 11, 2, 11, 2, 11, 2, 6, 11, 7, 6, 9, 2, 4…
$ escolarida <dbl> 3, 3, 3, 3, 1, 3, 10, 3, 10, 3, 9, 3, 4, 4, 1, 3, 9, 4, 1, …
$ edo_civil  <dbl> 3, 5, 3, 3, 2, 5, 5, 5, 5, 5, 5, 5, 3, 5, 5, 2, 5, 5, 9, 5,…
$ presunto   <dbl> 8, 8, 8, 1, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,…
$ ocurr_trab <dbl> 8, 8, 8, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,…
$ lugar_ocur <dbl> 88, 88, 88, 9, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, …
$ necropsia  <dbl> 9, 2, 2, 9, 2, 2, 2, 2, 2, 9, 2, 9, 2, 9, 2, 9, 2, 9, 2, 9,…
$ asist_medi <dbl> 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,…
$ sitio_ocur <dbl> 1, 11, 11, 1, 11, 3, 11, 11, 11, 3, 11, 3, 11, 3, 12, 3, 11…
$ cond_cert  <dbl> 2, 3, 3, 1, 3, 3, 1, 3, 1, 3, 1, 3, 1, 3, 3, 3, 3, 3, 3, 1,…
$ nacionalid <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,…
$ derechohab <dbl> 1, 7, 2, 7, 99, 2, 2, 99, 2, 2, 1, 2, 1, 2, 2, 2, 99, 2, 3,…
$ embarazo   <dbl> 8, 8, 8, 8, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 8, 8, 8, 8,…
$ rel_emba   <dbl> 8, 8, 8, 8, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 8, 8, 8, 8,…
$ horas      <dbl> 8, 19, 7, 11, 14, 17, 10, 0, 20, 4, 19, 4, 10, 9, 16, 10, 1…
$ minutos    <dbl> 45, 0, 0, 10, 30, 15, 20, 20, 15, 40, 10, 7, 45, 15, 0, 15,…
$ capitulo   <dbl> 9, 9, 4, 20, 9, 14, 4, 13, 2, 11, 2, 10, 9, 2, 4, 11, 9, 2,…
$ grupo      <dbl> 7, 7, 2, 25, 4, 1, 2, 9, 2, 6, 2, 5, 7, 9, 2, 9, 4, 9, 5, 6…
$ lista1     <chr> "069", "069", "052", "103", "067", "085", "052", "083", "03…
$ gr_lismex  <chr> "30", "30", "20", "E51", "28", "38", "20", "37", "09", "35"…
$ vio_fami   <dbl> 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,…
$ area_ur    <dbl> 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 1,…
$ edad_agru  <chr> "18", "23", "22", "24", "15", "20", "19", "20", "17", "18",…
$ complicaro <dbl> 8, 8, 8, 8, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 8, 8, 8, 8,…
$ dia_cert   <dbl> 99, 99, 99, 27, 1, 1, 19, 20, 7, 18, 19, 20, 1, 20, 28, 20,…
$ mes_cert   <dbl> 1, 1, 1, 12, 3, 7, 12, 10, 1, 1, 12, 1, 1, 1, 11, 1, 12, 1,…
$ anio_cert  <dbl> 2017, 2017, 2017, 2016, 2016, 2016, 2016, 2016, 2017, 2017,…
$ maternas   <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
$ lengua     <dbl> 9, 9, 9, 2, 9, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,…
$ cond_act   <dbl> 2, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1,…
$ par_agre   <dbl> 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88,…
$ ent_ocules <dbl> 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88,…
$ mun_ocules <chr> "888", "888", "888", "888", "888", "888", "888", "888", "88…
$ loc_ocules <chr> "8888", "8888", "8888", "8888", "8888", "8888", "8888", "88…
$ razon_m    <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,…
$ dis_re_oax <dbl> 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999,…

Hacer esto es lo mismo que hacerlo con el pipe nativo de R, |>:

mortalidad_2017 |> glimpse() 

o bien ponerlo dentro del glimpse:

glimpse(mortalidad_2017) 

El comando ncol nos muestra el número de columnas en la base de datos y tally nos cuenta el número de filas en la base de datos.

mortalidad_2017 %>% ncol() #Columnas
[1] 59
mortalidad_2017 %>% tally() #Filas
# A tibble: 1 × 1
       n
   <int>
1 703047

El comando nrow hace lo mismo: conteo de filas. Pero no es tan recomendado como veremos más adelante.

mortalidad_2017 %>% nrow() #Filas
[1] 703047

Podemos ver los nombres de las columnas de la base de datos con colnames:

#Mostramos las columnas
mortalidad_2017 %>% colnames()
 [1] "ent_regis"  "mun_regis"  "ent_resid"  "mun_resid"  "tloc_resid"
 [6] "loc_resid"  "ent_ocurr"  "mun_ocurr"  "tloc_ocurr" "loc_ocurr" 
[11] "causa_def"  "lista_mex"  "sexo"       "edad"       "dia_ocurr" 
[16] "mes_ocurr"  "anio_ocur"  "dia_regis"  "mes_regis"  "anio_regis"
[21] "dia_nacim"  "mes_nacim"  "anio_nacim" "ocupacion"  "escolarida"
[26] "edo_civil"  "presunto"   "ocurr_trab" "lugar_ocur" "necropsia" 
[31] "asist_medi" "sitio_ocur" "cond_cert"  "nacionalid" "derechohab"
[36] "embarazo"   "rel_emba"   "horas"      "minutos"    "capitulo"  
[41] "grupo"      "lista1"     "gr_lismex"  "vio_fami"   "area_ur"   
[46] "edad_agru"  "complicaro" "dia_cert"   "mes_cert"   "anio_cert" 
[51] "maternas"   "lengua"     "cond_act"   "par_agre"   "ent_ocules"
[56] "mun_ocules" "loc_ocules" "razon_m"    "dis_re_oax"

Una descripción de las variables las puedes encontrar en el archivo diccionario_datos_defunciones_generales_2017.csv. Donde aparece como sigue:

NOMBRE_CAMPO LONGITUD TIPO NEMÓNICO CATÁLOGO RANGO_CLAVES
Entidad Registro 2 N ent_regis decateml 01-32
Municipio Registro 3 N mun_regis decateml 001-570
Entidad Residencia 2 N ent_resid decateml 01-35, 99
Municipio Residencia 3 N mun_resid decateml 001-570, 999
Tamaño Localidad Residencia 2 N tloc_resid detamloc 01-17,99
Clave Localidad de Residencia 4 N loc_resid decateml 0001 - 6999, 9999
Entidad Ocurrencia 2 N ent_ocurr decateml 01-35,99
Municipio Ocurrencia 3 N mun_ocurr decateml 001-570,999
Tamaño de Localidad Ocurrencia 2 N tloc_ocurr detamloc 01-17,99
Clave Localidad de Ocurrencia 4 N loc_ocur decateml 0001 - 6999, 9999
Causa Defunción (Lista Detallada) 4 A causa_def decatcausa NA
Causa Defunción (Lista Mexicana) 3 A lista_mex delistamex NA
Sexo 1 N sexo desexo 1-2,9
Edad 4 N edad deedad 1001-1023, 1097,1098, 2001-2029,2098, 3001-3011,3098, 4001-4120, 4998
Día Defunción 2 N dia_ocurr dedias 01-31,99
Mes Defunción 2 N mes_ocurr demeses 01-12, 99
Año Defunción 4 N anio_ocur deaño 1900-Año estadística, 9999
Día Registro 2 N dia_regis dedias 01-31,99
Mes Registro 2 N mes_regis demeses 01-12
Año Registro 4 N anio_regis deaño Año estadística
Día Nacimiento 2 N dia_nacim dedias 01-31,99
Mes Nacimiento 2 N mes_nacim demeses 01-12,99
Año Nacimiento 4 N anio_nacim deaño 1900-Año estadística, 9999
Ocupación 2 N ocupacion deocupa 1 - 11, 97, 98, 99
Escolaridad 2 N escolarida deesco 1-10, 88, 99
Estado Conyugal 1 N edo_civil deedocony 1-6, 8, 9
Presunto 1 N presunto depresunto 1-5, 8
Ocurrió Trabajo 1 N ocurr_trab deocutrab 1-2, 8, 9
Sitio donde Ocurrio la Lesión 2 N lugar_ocur desitiolesion 0 - 9, 88
Necropsia 1 N necropsia denecrop 1-2, 9
Asistencia Médica 1 N asist_medi deasismed 1-2,9
Sitio donde Ocurrio la Defunción 2 N sitio_ocur desitiodefun 1-12,99
Certificada Por 1 N cond_cert deccertif 1-5, 8, 9
Nacionalidad 1 N nacionalid denacion 1-2, 9
Derechohabiencia 2 N derechohab dederech 1-9, 99
Condición de embarazo 1 N embarazo decondemba 1-6, 8, 9
Causas relacionadas con embarazo 1 N rel_emba derelemba 1,2, 8, 9
Hora de la defunción 2 N horas dehoradef 00-23, 99
Minuto de la defunción 2 N minutos demindef 00-59, 99
Capitulo 2 N capitulo decapgpo NA
Grupo 2 N grupo decapgpo NA
Lista1 3 A lista1 delista1 NA
Grupos lista mexicana 3 A gr_lismex degpolisme NA
Violencia Familiar 1 N vio_fami deviofam 1, 2, 8, 9
Area Urbano Rural 1 N area_ur deurbrur 1, 2, 9
Edad agrupada 2 C edad_agru deedadagrup 01-30
Complicaron el embarazo 1 N complicaro decomplicaemba 1, 2, 8, 9
Día de Certificación 2 N dia_cert dedias 01-31,99
Mes de Certificación 2 N mes_cert demeses 01-12, 99
Año de Certificación 4 N anio_cert deaño AE* -1, AE*, 9999
Maternas 4 C maternas decatcausa NA
Lengua indígena 1 N lengua delengindi 1, 2, 8, 9
Condición de Actividad económica 1 N cond_act decondact 1, 2, 8, 9
Parentesco del presunto agresor 2 N par_agre deparenagresor 1 - 72, 88, 99
Entidad Ocurrencia de la lesión 2 N ent_ocules decateml 01-35,88, 99
Municipio Ocurrencia de la lesión 3 N mun_ocules decateml 001-570, 888, 999
Clave Localidad de Ocurrencia de la lesión 4 N loc_ocules decateml 0001 - 6999, 8888 9999
Razón Materna 1 N razon_m derazonm 1
Distritos de Oaxaca 3 N dis_re_oax decateml 901-930, 999

Una vez tenemos una base de datos podemos analizar sus entradas usando el nombre de la base y corchetes. Por ejemplo:

#Obtengo todo el registro de la columna sexo
mortalidad_2017[ ,"sexo"]
# A tibble: 6 × 1
   sexo
  <dbl>
1     2
2     2
3     1
4     2
5     2
6     1

También podemos usar el número de columna:

#Me regresa las observaciones de la columna 2
#dada por mun_regis
#| eval: false
mortalidad_2017[ ,2]
# A tibble: 703,047 × 1
   mun_regis
   <chr>    
 1 001      
 2 009      
 3 001      
 4 006      
 5 001      
 6 001      
 7 001      
 8 001      
 9 001      
10 001      
# … with 703,037 more rows
#Me regresa las observaciones de la columna 2
#dada por mun_regis
head(mortalidad_2017[ , 2])

También podemos acceder a la base por renglones. Por ejemplo, así vemos el tercer renglón:

mortalidad_2017[3, ]
# A tibble: 1 × 6
  ent_regis mun_regis ent_resid mun_resid tloc_resid loc_resid
  <chr>     <chr>     <chr>     <chr>          <dbl> <chr>    
1 01        001       01        001               15 0001     

Finalmente, podemos combinar la primer entrada de la columna lista1 se vería así:

mortalidad_2017[1, "lista1"]
# A tibble: 1 × 1
  lista1
  <chr> 
1 069   

En resumen, la notación siempre es de la siguiente forma:

\[ \text{datos}[\underbrace{f}_{fila},\overbrace{c}^{columna}] \] Esta notación notación matricial es estándar en el mundo de computación y de las matemáticas. Siempre siempre primero es fila luego columna.

Otra forma de seleccionar una columna es con $ seguido del nombre de la columna. Por ejemplo:

mortalidad_2017$edo_civil
[1] 3 5 3 3 2 5

Por ciertos errores en los que se pueden incurrir al crear funciones, se recomienda que se utilice siempre la notación de doble corchete y se evite el signo de $. Pero ambos métodos funcionan. Sólo recuerda que la notación es así:

\[ \text{datos}\$\text{Columna}[\underbrace{f}_{\text{Fila}}] \] Una última opción es con select:

mortalidad_2017 %>% select(edo_civil)
# A tibble: 6 × 1
  edo_civil
      <dbl>
1         3
2         5
3         3
4         3
5         2
6         5

la cual nos regresa la columna de estado civil. El comando select es bastante útil si, por ejemplo, no recordamos exactamente el nombre de la columna. Por ejemplo, si sólo recordamos que tiene la palabra "civil" pero no exactamente cómo se escribe podemos usar contains:

#Podemos usar contains si recordamos que dice civil 
#pero no el nombre completo
mortalidad_2017 %>% select(contains("civil"))
# A tibble: 703,047 × 1
   edo_civil
       <dbl>
 1         3
 2         5
 3         3
 4         3
 5         2
 6         5
 7         5
 8         5
 9         5
10         5
# … with 703,037 more rows

Podemos preguntarnos, de igual manera por la 7a entrada de edo_civil haciendo:

mortalidad_2017$edo_civil[7]
[1] 5

Lo cual es similar (mas no equivalente) a la forma anterior:

mortalidad_2017[7, "edo_civil"]
# A tibble: 1 × 1
  edo_civil
      <dbl>
1         5

En el caso del tidyverse el equivalente a select, para elegir fila, el equivalente se conoce como slice:

#Selecciona la fila 11
mortalidad_2017 %>% slice(11)
# A tibble: 1 × 59
  ent_regis mun_regis ent_resid mun_re…¹ tloc_…² loc_r…³ ent_o…⁴ mun_o…⁵ tloc_…⁶
  <chr>     <chr>     <chr>     <chr>      <dbl> <chr>   <chr>   <chr>     <dbl>
1 01        001       01        001           15 0001    01      001          15
# … with 50 more variables: loc_ocurr <chr>, causa_def <chr>, lista_mex <chr>,
#   sexo <dbl>, edad <dbl>, dia_ocurr <dbl>, mes_ocurr <dbl>, anio_ocur <dbl>,
#   dia_regis <dbl>, mes_regis <dbl>, anio_regis <dbl>, dia_nacim <dbl>,
#   mes_nacim <dbl>, anio_nacim <dbl>, ocupacion <dbl>, escolarida <dbl>,
#   edo_civil <dbl>, presunto <dbl>, ocurr_trab <dbl>, lugar_ocur <dbl>,
#   necropsia <dbl>, asist_medi <dbl>, sitio_ocur <dbl>, cond_cert <dbl>,
#   nacionalid <dbl>, derechohab <dbl>, embarazo <dbl>, rel_emba <dbl>, …

Podemos combinar múltiples argumentos con %>%1:

  • 1 En el mismo renglón debe estar el %>% que el último comando para no generar error

  • mortalidad_2017 %>% 
      select(sexo, edo_civil) %>%  #Selecciona edo civil y sexo
      slice(11:20) #Selecciona filas 11 a 20
    # A tibble: 10 × 2
        sexo edo_civil
       <dbl>     <dbl>
     1     1         5
     2     1         5
     3     2         3
     4     1         5
     5     1         5
     6     2         2
     7     1         5
     8     1         5
     9     2         9
    10     1         5

    Esta forma de combinación con pipes (%>% ó |>) será bastante útil más adelante.

    Para seleccionar múltiples filas o columnas, como vimos en el ejemplo anterior, hay que crear un vector usando c2. Un vector es una lista ordenada de variables del mismo tipo. Por ejemplo:

  • 2 Se llama c por concatenate (concatenar).

  • mi_vector <- c(1, 141, 12)

    Es un vector de 3 entradas. De hecho, la forma de acceder a sus entradas es la misma que la de los tibbles con un agregado: ¡sólo hay filas, no hay columnas!

    Note

    Intuitivamente podemos pensar un vector como una columna de una base de datos. En ella todas las variables son del mismo tipo.

    Para acceder a las entradas de un vector es de la siguiente forma:

    #Para un vector sólo pongo el número de entrada ¡no hay columna!
    mi_vector[2] #entrada 2
    [1] 141

    En general la notación es la siguiente:

    \[ \text{vector}[\underbrace{i}_{\text{Entrada}}] \]

    Un vector que ya nos encontramos antes es el de columnas. Podemos, por ejemplo, ver el nombre de la cuarta columna de la base combinando lo que sabemos de vectores con el comando colnames:

    #Regresa el nombre de la 5a columna
    colnames(mortalidad_2017)[5]
    [1] "tloc_resid"

    La pregunta también puede hacerse al revés: podemos pedirle a R que nos conteste cuál es el número de columna para una columna dada. Por ejemplo, ¿cuál es el número de columna para edad?

    #Preguntamos a R cuál de las columnas se llama edad
    which(colnames(mortalidad_2017) == "edad")
    [1] 14

    Nota que si preguntamos por una columna que no existe, R nos regresa lo siguiente:

    #Preguntamos a R cuál de las columnas se llama edad
    which(colnames(mortalidad_2017) == "Paraguas")
    integer(0)

    Esto significa que no hay ninguna columna con ese nombre. Finalmente, nota que el which puede regresar múltiples resultados si las cosas se repiten. Por ejemplo, el siguiente comando nos regresa las múltiples entradas del vector nombres_de_amigos donde hay un amigo que tiene el nombre de Alejandro:

    #Creo un vector con nombres de mis amigos
    nombres_de_amigos <- c("Alejandro", "Beatriz", "Alejandro", "Carla")
    
    #Pregunto por cuáles entradas contienen a Alejandro
    which(nombres_de_amigos == "Alejandro")
    [1] 1 3

    Finalmente, podemos usar vectores para seleccionar múltiples columnas y filas, por ejemplo si deseo seleccionar, de la base, las columnas de sexo y edad:

    mortalidad_2017[ , c("sexo", "edad")]
    # A tibble: 6 × 2
       sexo  edad
      <dbl> <dbl>
    1     2  4068
    2     2  4090
    3     1  4088
    4     2  4096
    5     2  4051
    6     1  4078

    Finalmente si quiero seleccionar sólo algunos renglones puedo ponerlos en un vector:

    #Selecciona sólo el renglón 1 y el 7
    mortalidad_2017[c(1, 7), c("sexo", "edad")]
    # A tibble: 2 × 2
       sexo  edad
      <dbl> <dbl>
    1     2  4068
    2     1  4070

    Mientras que el : selecciona del renglón 1 al renglón 7

    #Selecciona del 1 al 7
    mortalidad_2017[1:7, c("sexo", "edad")]
    # A tibble: 7 × 2
       sexo  edad
      <dbl> <dbl>
    1     2  4068
    2     2  4090
    3     1  4088
    4     2  4096
    5     2  4051
    6     1  4078
    7     1  4070

    El equivalente usando select y slice es:

    mortalidad_2017 %>% 
      select(sexo, edad) %>%
      slice(1:7)
    # A tibble: 7 × 2
       sexo  edad
      <dbl> <dbl>
    1     2  4068
    2     2  4090
    3     1  4088
    4     2  4096
    5     2  4051
    6     1  4078
    7     1  4070
    #Selecciona renglones del 2 al 7
    #y las columnas 5 a 9
    mortalidad_2017[2:7, 5:9]
    # A tibble: 6 × 5
      tloc_resid loc_resid ent_ocurr mun_ocurr tloc_ocurr
           <dbl> <chr>     <chr>     <chr>          <dbl>
    1          1 0016      01        009                1
    2         15 0001      01        001               15
    3          8 0001      01        006                8
    4         15 0001      01        001               15
    5         15 0001      01        001               15
    6         15 0001      01        001               15

    Los : también funcionan para seleccionar rangos de columnas a través del select:

    #Selecciona todas las columnas desde loc_resid hasta tloc_ocurr
    mortalidad_2017 %>%
      select(loc_resid:tloc_ocurr) 
    # A tibble: 703,047 × 4
       loc_resid ent_ocurr mun_ocurr tloc_ocurr
       <chr>     <chr>     <chr>          <dbl>
     1 0001      01        001               15
     2 0016      01        009                1
     3 0001      01        001               15
     4 0001      01        006                8
     5 0001      01        001               15
     6 0001      01        001               15
     7 0001      01        001               15
     8 0001      01        001               15
     9 0001      01        001               15
    10 1025      01        001               15
    # … with 703,037 more rows

    5 Ejercicios

    1. Lee la hoja MCV2 del archivo unicef_vacunas.xlsx el cual contiene información sobre vacunas MCV2 dada por la UNICEF. Responde las siguientes preguntas:
    1. Determina los nombres de todas las columnas de las variables usando R (no vale ver el archivo).
    2. Determina el número de renglones y el número de filas totales de la base.
    3. Encuentra cuál fila contiene a México en la columna de country.
    4. Regresa todas las mediciones para la fila de Colombia.
    5. Regresa la 5a columna.
    6. Obtén el nombre de la columna 9.
    7. Obtén la entrada en la columna 5 y fila 14.
    1. Considera la base de datos creada por el siguiente código:
    base_inventada <- tibble(Tiempo = rexp(100), 
                                 Enfermo = rbinom(100, 83, 1/3))

    Determina qué ocasionó los resultados siguientes:

    1. ¿Por qué da error?
    #Primer error
    base_inventada[ , 200]
    Error in `base_inventada[, 200]`:
    ! Can't subset columns past the end.
    ℹ Location 200 doesn't exist.
    ℹ There are only 2 columns.
    1. ¿Por qué da NA?
    #NA
    base_inventada[1000, ]
    # A tibble: 1 × 2
      Tiempo Enfermo
       <dbl>   <int>
    1     NA      NA
    1. ¿Por qué dice esto?
    #Primer error
    base_inventada[0,0]
    # A tibble: 0 × 0
    1. ¿Por qué da error`?
    base_inventada[2, c("tiempo")]
    Error in `base_inventada[2, c("tiempo")]`:
    ! Can't subset columns that don't exist.
    ✖ Column `tiempo` doesn't exist.
    1. Arregla este código para que no dé error
    base.inventada %>% select("Tiempo")
                   %>% slice(2)

    6 Limpieza de la base de datos

    6.1 Seleccionar columnas con select

    De la base de mortalidad comencemos por quedarnos sólo con las columnas ent_regis,mun_regis, sexo, edad, dia_ocurr, mes_ocurr, anio_ocurr y causa_def. Para ello seleccionamos múltiples columnas mediante un vector con el nombre de las columnas a seleccionar.

    Warning

    R trabaja con una copia de la base de datos. Todo lo que hacemos aquí nunca va a cambiar la base de datos a menos que explícitamente se lo pidamos. ¡Es genial porque nos evitamos el riesgo de perder información!

    #Reescribimos la variable sólo con las columnas que nos
    #interesan
    mortalidad_2017 <- mortalidad_2017 %>%
      select(ent_regis, mun_regis, sexo, edad, dia_ocurr, mes_ocurr, anio_ocur, causa_def)

    Ojo que aquí estoy sobreescribiendo la copia de R de la base de mortalidad_2017. Es decir, estoy editando la base mortalidad_2017 y guardándola en sí misma (para que se queden los cambios). También lo pude haber guardado en otra variable:

    #Reescribimos la variable sólo con las columnas que nos
    #interesan
    #| eval: false
    mortalidad_2017_pedazo <- mortalidad_2017 %>%
      select(ent_regis, mun_regis, sexo, edad, dia_ocurr, mes_ocurr, anio_ocur, causa_def)

    El punto importante es guardarla porque de otra forma los cambios no son permanentes. Por ejemplo el siguiente comando de seleccionar sólo sexo y edad no edita la base pues no se asigna a la base:

    #Reescribimos la variable sólo con las columnas que nos
    #interesan
    mortalidad_2017 %>%
      select(sexo, edad)
    # A tibble: 703,047 × 2
        sexo  edad
       <dbl> <dbl>
     1     2  4068
     2     2  4090
     3     1  4088
     4     2  4096
     5     2  4051
     6     1  4078
     7     1  4070
     8     2  4079
     9     2  4061
    10     1  4069
    # … with 703,037 more rows

    6.2 Renombrar columnas con rename

    Utilicemos rename para mejorar los nombres de las variables. El comando es:

    rename(`Nuevo nombre` = `Viejo nombre`)

    Por ejemplo:

    mortalidad_2017 <- mortalidad_2017 %>%
      rename(`Entidad` = `ent_regis`)

    También podemos renombrar varias columnas de golpe aplicando varios rename concatenados por el %>% o bien poniendo muchas igualdades dentro del rename:

    mortalidad_2017 <- mortalidad_2017 %>%
      rename(`Sexo`  = `sexo`) %>%
      rename(`Edad`  = `edad`) %>% 
      rename(`Día`      = `dia_ocurr`, 
             `Mes`      = `mes_ocurr`,
             `Año`      = `anio_ocur`,
             `Causa`    = `causa_def`, 
             `Municipio`= `mun_regis`)

    6.3 Filtrar filas con filter

    Podemos reducir nuestra base quedándonos, por ejemplo, con aquellas observaciones que ocurrieron en el Año 2017. Nota que el número de filas cambia de:

    #Antes de filtrar
    mortalidad_2017 %>% tally()
    # A tibble: 1 × 1
           n
       <int>
    1 703047
    #Filtro
    mortalidad_2017 <- mortalidad_2017 %>%
      filter(Año == 2017)
    #Después de filtrar
    mortalidad_2017 %>% 
      tally()
    # A tibble: 1 × 1
           n
       <int>
    1 688468

    El filter opera poniéndole una condición adentro. Aquí te copio las instrucciones más comunes:

    Instrucciones comunes para el `filter`
    Nombre Instrucción Significado
    Igualdad x == y x es igual a y
    Mayor/menor x > y x es menor que y
    Mayor/menor igual x >= y x es mayor o igual que y
    Diferente x != y x es distinto de y (\(x \neq y\))
    Pertenencia x %in% y x está en y si y es un vector c
    O A | B al menos una de las dos condiciones A ó B es verdadera
    Y A & B ambas A y B son verdaderas
    No !A lo contrario a la condición A
    Búsqueda de palabras str_detect(Columna, "palabra") Devuelve aquellos casos donde la columna Columna contiene la palabra "palabra"
    Identifica datos faltantes is.na is.na(Columna)

    Podemos jugar más con el filter por ejemplo devolviendo aquellas defunciones en un mes después de febrero (mes 2):

    mortalidad_2017 %>%
      filter(Mes > 2)
    # A tibble: 568,041 × 8
       Entidad Municipio  Sexo  Edad   Día   Mes   Año Causa
       <chr>   <chr>     <dbl> <dbl> <dbl> <dbl> <dbl> <chr>
     1 01      001           1  4079    22     3  2017 C61X 
     2 01      001           2  4080     4     4  2017 M623 
     3 01      001           1  4075     6     4  2017 E149 
     4 01      001           2  1097    27     3  2017 P832 
     5 01      001           2  4075     1     5  2017 E46X 
     6 01      001           1  4085    30     4  2017 I500 
     7 01      011           1  4092    17    11  2017 F102 
     8 01      003           1  4061     2     5  2017 C189 
     9 01      003           1  4024    21     4  2017 C959 
    10 01      003           2  4073    24     4  2017 E142 
    # … with 568,031 more rows

    Aquellas defunciones cuyo mes es antes de febrero (incluyendo febrero):

    mortalidad_2017 %>%
      filter(Mes <= 2)
    # A tibble: 120,427 × 8
       Entidad Municipio  Sexo  Edad   Día   Mes   Año Causa
       <chr>   <chr>     <dbl> <dbl> <dbl> <dbl> <dbl> <chr>
     1 01      001           2  4061     7     1  2017 C259 
     2 01      001           1  4069    18     1  2017 K631 
     3 01      001           1  4091    20     1  2017 J441 
     4 01      001           2  4076     1     1  2017 I698 
     5 01      001           1  4070    20     1  2017 C61X 
     6 01      001           2  4048    20     1  2017 K803 
     7 01      001           1  4062    12     1  2017 C61X 
     8 01      001           1  4089    13     1  2017 N390 
     9 01      001           2  4042     8     1  2017 E117 
    10 01      001           2  4085    14     1  2017 I120 
    # … with 120,417 more rows

    Aquellas defunciones cuyos días estén entre el día 7 y el 9

    mortalidad_2017 %>%
      filter(Día %in% c(7,8,9)) #o bien 7:9 en lugar del c
    # A tibble: 67,650 × 8
       Entidad Municipio  Sexo  Edad   Día   Mes   Año Causa
       <chr>   <chr>     <dbl> <dbl> <dbl> <dbl> <dbl> <chr>
     1 01      001           2  4061     7     1  2017 C259 
     2 01      001           2  4042     8     1  2017 E117 
     3 01      001           1  4073     8     2  2017 J440 
     4 01      001           1  4088     7     2  2017 I802 
     5 01      001           1  4067     9     1  2017 E119 
     6 01      001           1  4019     7     1  2017 Q070 
     7 01      001           2  4062     9     1  2017 I678 
     8 01      007           1  4057     8     5  2017 K703 
     9 01      001           2  4052     7     1  2017 K274 
    10 01      007           1  4059     9     3  2017 J180 
    # … with 67,640 more rows

    Aquellas defunciones cuyo día no esté entre el día 7 y el 9

    mortalidad_2017 %>%
      filter(!(Día %in% c(7,8,9))) #o bien 7:9 en lugar del c
    # A tibble: 620,818 × 8
       Entidad Municipio  Sexo  Edad   Día   Mes   Año Causa
       <chr>   <chr>     <dbl> <dbl> <dbl> <dbl> <dbl> <chr>
     1 01      001           1  4069    18     1  2017 K631 
     2 01      001           1  4091    20     1  2017 J441 
     3 01      001           2  4076     1     1  2017 I698 
     4 01      001           1  4070    20     1  2017 C61X 
     5 01      001           2  4048    20     1  2017 K803 
     6 01      001           1  4062    12     1  2017 C61X 
     7 01      001           1  4089    13     1  2017 N390 
     8 01      001           2  4085    14     1  2017 I120 
     9 01      001           2  4042    19     1  2017 K729 
    10 01      001           2  4067     3     1  2017 I120 
    # … with 620,808 more rows

    Aquellas defunciones en enero el día 14:

    mortalidad_2017 %>%
      filter(Día == 14 & Mes == 1) #o bien 7:9 en lugar del c
    # A tibble: 2,035 × 8
       Entidad Municipio  Sexo  Edad   Día   Mes   Año Causa
       <chr>   <chr>     <dbl> <dbl> <dbl> <dbl> <dbl> <chr>
     1 01      001           2  4085    14     1  2017 I120 
     2 01      001           1  4083    14     1  2017 I698 
     3 01      001           1  4089    14     1  2017 R54X 
     4 01      001           1  4078    14     1  2017 E119 
     5 01      002           1  4062    14     1  2017 E142 
     6 01      001           1  4076    14     1  2017 I64X 
     7 01      001           2  4085    14     1  2017 I210 
     8 01      009           2  4078    14     1  2017 I219 
     9 01      001           2  4087    14     1  2017 I119 
    10 01      007           1  4056    14     1  2017 E119 
    # … with 2,025 more rows

    O bien:

    mortalidad_2017 %>%
      filter(Día == 14) %>%
      filter(Mes == 1) 
    # A tibble: 2,035 × 8
       Entidad Municipio  Sexo  Edad   Día   Mes   Año Causa
       <chr>   <chr>     <dbl> <dbl> <dbl> <dbl> <dbl> <chr>
     1 01      001           2  4085    14     1  2017 I120 
     2 01      001           1  4083    14     1  2017 I698 
     3 01      001           1  4089    14     1  2017 R54X 
     4 01      001           1  4078    14     1  2017 E119 
     5 01      002           1  4062    14     1  2017 E142 
     6 01      001           1  4076    14     1  2017 I64X 
     7 01      001           2  4085    14     1  2017 I210 
     8 01      009           2  4078    14     1  2017 I219 
     9 01      001           2  4087    14     1  2017 I119 
    10 01      007           1  4056    14     1  2017 E119 
    # … with 2,025 more rows

    Aquellas defunciones donde el mes sea enero o diciembre:

    mortalidad_2017 %>%
      filter(Mes == 1 | Mes == 12)
    # A tibble: 121,073 × 8
       Entidad Municipio  Sexo  Edad   Día   Mes   Año Causa
       <chr>   <chr>     <dbl> <dbl> <dbl> <dbl> <dbl> <chr>
     1 01      001           2  4061     7     1  2017 C259 
     2 01      001           1  4069    18     1  2017 K631 
     3 01      001           1  4091    20     1  2017 J441 
     4 01      001           2  4076     1     1  2017 I698 
     5 01      001           1  4070    20     1  2017 C61X 
     6 01      001           2  4048    20     1  2017 K803 
     7 01      001           1  4062    12     1  2017 C61X 
     8 01      001           1  4089    13     1  2017 N390 
     9 01      001           2  4042     8     1  2017 E117 
    10 01      001           2  4085    14     1  2017 I120 
    # … with 121,063 more rows

    Aquellas defunciones donde el mes sea distinto de octubre:

    mortalidad_2017 %>%
      filter(Mes != 10)
    # A tibble: 630,907 × 8
       Entidad Municipio  Sexo  Edad   Día   Mes   Año Causa
       <chr>   <chr>     <dbl> <dbl> <dbl> <dbl> <dbl> <chr>
     1 01      001           2  4061     7     1  2017 C259 
     2 01      001           1  4069    18     1  2017 K631 
     3 01      001           1  4091    20     1  2017 J441 
     4 01      001           2  4076     1     1  2017 I698 
     5 01      001           1  4070    20     1  2017 C61X 
     6 01      001           2  4048    20     1  2017 K803 
     7 01      001           1  4062    12     1  2017 C61X 
     8 01      001           1  4089    13     1  2017 N390 
     9 01      001           2  4042     8     1  2017 E117 
    10 01      001           2  4085    14     1  2017 I120 
    # … with 630,897 more rows

    Aquellas defunciones cuya causa contenga el caracter C5:

    mortalidad_2017 %>%
      filter(str_detect(Causa,"C5"))
    # A tibble: 14,701 × 8
       Entidad Municipio  Sexo  Edad   Día   Mes   Año Causa
       <chr>   <chr>     <dbl> <dbl> <dbl> <dbl> <dbl> <chr>
     1 01      001           2  4049     6     1  2017 C509 
     2 01      001           2  4071    23     1  2017 C509 
     3 01      001           2  4053    20     1  2017 C56X 
     4 01      001           2  4066    18     2  2017 C56X 
     5 01      001           2  4029     2     1  2017 C509 
     6 01      001           2  4063     5    12  2017 C56X 
     7 01      001           2  4059     6     1  2017 C56X 
     8 01      001           2  4047    31     1  2017 C539 
     9 01      001           2  4064    27     1  2017 C56X 
    10 01      001           2  4058    31     1  2017 C56X 
    # … with 14,691 more rows

    Ejercicio

    En la base unicef_vacunas.xlsx abre la hoja HEPBB con información de la cobertura de dicha vacuna. Determina:

    1. ¿Cuántos países están registrados para la región ROSA?
    2. ¿Cuántos países en 2020 lograron una cobertura mayor al 90%?
    3. Dentro de la región de Latinoamérica y el Caribe (LACR) ¿cuántos países lograron una cobertura menor a 80%?
    4. ¿Cuál fue la cobertura de México, Colombia y Uruguay en 2020?
    5. ¿Cuántos países no contienen datos para 1990?

    6.4 Estadísticos de resumen con summarise

    La función de summarise sirve para colapsar columnas en números. Por ejemplo: obtener el promedio (mean) de una columna, obtener el máximo (max), un cuantil (quantile), una suma (sum) o un conteo (n). Por ejemplo para obtener el promedio de la columna Edad basta con usar mean adentro de summarise:

    mortalidad_2017 %>%
      summarise(`Edad promedio` = mean(Edad))
    # A tibble: 1 × 1
      `Edad promedio`
                <dbl>
    1           4000.

    Nota que aquí la edad sale altísima y esto es porque el INEGI empieza a contar los años a partir del 4000 siendo 4001 un año, 4002 dos años etc. Por otro lado es necesario eliminar a aquellos con edad de 4998 pues corresponde a Edad no especificada. Para ello filtramos (filter) y luego calculamos la media (mean) de edad menos 4000:

    mortalidad_2017 %>%
      filter(Edad >= 4000 & Edad != 4998) %>%
      summarise(`Edad promedio` = mean(Edad - 4000))
    # A tibble: 1 × 1
      `Edad promedio`
                <dbl>
    1            65.5

    Esto nos dice que en el 2017 el promedio de edad de las defunciones de más de un año fue de 65 años.

    Observa que ese promedio es lo mismo que haber sumado todas las edades con sum y luego dividido entre el total de observaciones n:

    mortalidad_2017 %>%
      filter(Edad >= 4000 & Edad != 4998) %>%
      summarise(`Suma de edades` = sum(Edad - 4000))
    # A tibble: 1 × 1
      `Suma de edades`
                 <dbl>
    1         43216448
    mortalidad_2017 %>%
      filter(Edad >= 4000 & Edad != 4998) %>%
      summarise(`Total de observaciones` = n())
    # A tibble: 1 × 1
      `Total de observaciones`
                         <int>
    1                   660152

    pues:

    43216448/660152
    [1] 65.46439

    Podemos también obtener el máximo de edad con max (el mínimo sería con min)

    mortalidad_2017 %>%
      filter(Edad >= 4000 & Edad != 4998) %>%
      summarise(`Edad promedio` = max(Edad - 4000))
    # A tibble: 1 × 1
      `Edad promedio`
                <dbl>
    1             120

    O bien la mediana o algún cuantil:

    mortalidad_2017 %>%
      filter(Edad >= 4000 & Edad != 4998) %>%
      summarise(`Edad mediana` = median(Edad - 4000))
    # A tibble: 1 × 1
      `Edad mediana`
               <dbl>
    1             69
    #Cuantil 0.25 = primer cuartil
    mortalidad_2017 %>%
      filter(Edad >= 4000 & Edad != 4998) %>%
      summarise(`Edad (25%)` = quantile(Edad - 4000, 0.25))
    # A tibble: 1 × 1
      `Edad (25%)`
             <dbl>
    1           53

    de hecho podemos aplicar el summarise de todos a la vez:

    #Cuantil 0.25 = primer cuartil
    mortalidad_2017 %>%
      filter(Edad >= 4000 & Edad != 4998) %>%
      summarise(`Edad promedio` = mean(Edad - 4000),
                `Edad mediana`  = median(Edad - 4000),
                `Edad máxima`   = max(Edad - 4000))
    # A tibble: 1 × 3
      `Edad promedio` `Edad mediana` `Edad máxima`
                <dbl>          <dbl>         <dbl>
    1            65.5             69           120

    6.5 Operaciones en grupos usando group_by

    Supongamos que es de nuestro interés calcular la media de edad de la defunción pero no para todo el país sino por entidad. Una opción es ir filtrando 32 veces para cada entidad como sigue (por ejemplo en este caso obteniendo todo Baja California que es la entidad 02)

    mortalidad_2017 %>%
      filter(Edad >= 4000 & Edad != 4998) %>%
      filter(Entidad == "02") %>%
      summarise(`Edad promedio` = mean(Edad - 4000))
    # A tibble: 1 × 1
      `Edad promedio`
                <dbl>
    1            59.7

    Repetir este proceso 32 veces es bastante ineficiente. Para ello el group_by nos sirve pues el group_by indica sobre qué columna debe repetirse la operación. En nuestro caso sería la de Entidad y podría ponerse:

    mortalidad_2017 %>%
      filter(Edad >= 4000 & Edad != 4998) %>%
      group_by(Entidad) %>%
      summarise(`Edad promedio` = mean(Edad - 4000))
    # A tibble: 32 × 2
       Entidad `Edad promedio`
       <chr>             <dbl>
     1 01                 65.1
     2 02                 59.7
     3 03                 58.3
     4 04                 66.1
     5 05                 66.0
     6 06                 62.0
     7 07                 62.9
     8 08                 62.0
     9 09                 66.9
    10 10                 66.4
    # … with 22 more rows

    Podemos, por ejemplo, también calcular el número total de registros por cada Entidad como sigue:

    mortalidad_2017 %>%
      group_by(Entidad) %>%
      tally()
    # A tibble: 32 × 2
       Entidad     n
       <chr>   <int>
     1 01       5986
     2 02      20572
     3 03       3949
     4 04       4477
     5 05      16137
     6 06       4871
     7 07      26530
     8 08      23468
     9 09      75310
    10 10       8490
    # … with 22 more rows

    Se puede agrupar por más de una columna separando por comas. Por ejemplo el siguiente conteo de hombres y mujeres por entidad

    conteo_sexo_entidad <- mortalidad_2017 %>%
      group_by(Entidad, Sexo) %>%
      tally()
    # A tibble: 96 × 3
    # Groups:   Entidad [32]
       Entidad  Sexo     n
       <chr>   <dbl> <int>
     1 01          1  3315
     2 01          2  2669
     3 01          9     2
     4 02          1 13135
     5 02          2  7420
     6 02          9    17
     7 03          1  2617
     8 03          2  1327
     9 03          9     5
    10 04          1  2526
    # … with 86 more rows

    Una vez hayamos terminado de operar por la variable agrupada y decidamos seguir usando la base es necesario desagrupar primero. Por ejemplo si queremos seguir ocupando la base conteo_sexo_entidad para ahora calcular el total de defunciones a nivel nacional usando una suma sum el programa no sabe que queremos dejar de agrupar:

    conteo_sexo_entidad %>%
      summarise(Todas = sum(n))
    # A tibble: 32 × 2
       Entidad Todas
       <chr>   <int>
     1 01       5986
     2 02      20572
     3 03       3949
     4 04       4477
     5 05      16137
     6 06       4871
     7 07      26530
     8 08      23468
     9 09      75310
    10 10       8490
    # … with 22 more rows

    De hecho en la misma impresión de la base conteo_sexo_entidad puedes ver que dice # Groups: Entidad [32]. Esto porque se quedó agrupada. Para eliminar los grupos y poder trabajar con toda la base basta con usar ungroup:

    conteo_sexo_entidad %>%
      ungroup() %>%
      summarise(Todas = sum(n))
    # A tibble: 1 × 1
       Todas
       <int>
    1 688468

    6.6 Cambio de columnas usando mutate

    La función de mutate sirve para cambiar columnas en función de otras columnas o bien generar columnas nuevas. Por ejemplo podemos generar una nueva columna que se llame Dos y que consista sólo del número 2:

    mortalidad_2017 %>%
      mutate(`Dos` = 2)
    # A tibble: 688,468 × 9
       Entidad Municipio  Sexo  Edad   Día   Mes   Año Causa   Dos
       <chr>   <chr>     <dbl> <dbl> <dbl> <dbl> <dbl> <chr> <dbl>
     1 01      001           2  4061     7     1  2017 C259      2
     2 01      001           1  4069    18     1  2017 K631      2
     3 01      001           1  4091    20     1  2017 J441      2
     4 01      001           2  4076     1     1  2017 I698      2
     5 01      001           1  4070    20     1  2017 C61X      2
     6 01      001           2  4048    20     1  2017 K803      2
     7 01      001           1  4062    12     1  2017 C61X      2
     8 01      001           1  4089    13     1  2017 N390      2
     9 01      001           2  4042     8     1  2017 E117      2
    10 01      001           2  4085    14     1  2017 I120      2
    # … with 688,458 more rows

    También podemos generar una columna que asigne el número de fila:

    mortalidad_2017 %>%
      mutate(`Fila` = 1:n())
    # A tibble: 688,468 × 9
       Entidad Municipio  Sexo  Edad   Día   Mes   Año Causa  Fila
       <chr>   <chr>     <dbl> <dbl> <dbl> <dbl> <dbl> <chr> <int>
     1 01      001           2  4061     7     1  2017 C259      1
     2 01      001           1  4069    18     1  2017 K631      2
     3 01      001           1  4091    20     1  2017 J441      3
     4 01      001           2  4076     1     1  2017 I698      4
     5 01      001           1  4070    20     1  2017 C61X      5
     6 01      001           2  4048    20     1  2017 K803      6
     7 01      001           1  4062    12     1  2017 C61X      7
     8 01      001           1  4089    13     1  2017 N390      8
     9 01      001           2  4042     8     1  2017 E117      9
    10 01      001           2  4085    14     1  2017 I120     10
    # … with 688,458 more rows

    Por último podemos generar una columna que a la edad le reste 4000:

    mortalidad_2017 %>%
      mutate(`Edad corregida` = `Edad` - 4000)
    # A tibble: 688,468 × 9
       Entidad Municipio  Sexo  Edad   Día   Mes   Año Causa `Edad corregida`
       <chr>   <chr>     <dbl> <dbl> <dbl> <dbl> <dbl> <chr>            <dbl>
     1 01      001           2  4061     7     1  2017 C259                61
     2 01      001           1  4069    18     1  2017 K631                69
     3 01      001           1  4091    20     1  2017 J441                91
     4 01      001           2  4076     1     1  2017 I698                76
     5 01      001           1  4070    20     1  2017 C61X                70
     6 01      001           2  4048    20     1  2017 K803                48
     7 01      001           1  4062    12     1  2017 C61X                62
     8 01      001           1  4089    13     1  2017 N390                89
     9 01      001           2  4042     8     1  2017 E117                42
    10 01      001           2  4085    14     1  2017 I120                85
    # … with 688,458 more rows

    Cambio de columnas de manera condicional usando if_else y case_when dentro de mutate

    El if_else y el case_when sirven para realizar cambios en columnas (mutate) en función de condiciones de la columna. La redacción del if_else es como sigue:

    if_else(CONDICIÓN, VALOR SI VERDADERO, VALOR SI FALSO)

    por ejemplo podemos construir una columna que se llame Sexo categoría y que diga Hombre, Mujer en los casos de 1 y 2 respectivamente:

    mortalidad_2017 %>%
      filter(Sexo %in% c(1,2)) %>% #eliminamos los desconocidos
      mutate(`Sexo categoría` = if_else(Sexo == 1, "Hombre", "Mujer"))
    # A tibble: 688,104 × 9
       Entidad Municipio  Sexo  Edad   Día   Mes   Año Causa `Sexo categoría`
       <chr>   <chr>     <dbl> <dbl> <dbl> <dbl> <dbl> <chr> <chr>           
     1 01      001           2  4061     7     1  2017 C259  Mujer           
     2 01      001           1  4069    18     1  2017 K631  Hombre          
     3 01      001           1  4091    20     1  2017 J441  Hombre          
     4 01      001           2  4076     1     1  2017 I698  Mujer           
     5 01      001           1  4070    20     1  2017 C61X  Hombre          
     6 01      001           2  4048    20     1  2017 K803  Mujer           
     7 01      001           1  4062    12     1  2017 C61X  Hombre          
     8 01      001           1  4089    13     1  2017 N390  Hombre          
     9 01      001           2  4042     8     1  2017 E117  Mujer           
    10 01      001           2  4085    14     1  2017 I120  Mujer           
    # … with 688,094 more rows

    O bien podemos crear una columna de edad nueva que sea 0 si la edad es menor que 4000 y Edad - 4000 en otro caso. Esto porque en la codificación del INEGI los números menores a 4000 se usan para codificar horas, días y meses.

    mortalidad_2017 %>%
      mutate(`Edad corregida` = if_else(Edad >= 4000, Edad - 4000, 0))
    # A tibble: 688,468 × 9
       Entidad Municipio  Sexo  Edad   Día   Mes   Año Causa `Edad corregida`
       <chr>   <chr>     <dbl> <dbl> <dbl> <dbl> <dbl> <chr>            <dbl>
     1 01      001           2  4061     7     1  2017 C259                61
     2 01      001           1  4069    18     1  2017 K631                69
     3 01      001           1  4091    20     1  2017 J441                91
     4 01      001           2  4076     1     1  2017 I698                76
     5 01      001           1  4070    20     1  2017 C61X                70
     6 01      001           2  4048    20     1  2017 K803                48
     7 01      001           1  4062    12     1  2017 C61X                62
     8 01      001           1  4089    13     1  2017 N390                89
     9 01      001           2  4042     8     1  2017 E117                42
    10 01      001           2  4085    14     1  2017 I120                85
    # … with 688,458 more rows

    También podemos, por ejemplo, obtener una columna que diga Tuberculosis si la causa de defunción fue tuberculosis (códigos A15-A19) o bien Otra en caso contrario:

    mortalidad_2017 %>%
      mutate(TB = if_else(str_detect(Causa,"A15") | str_detect(Causa,"A16") |
                           str_detect(Causa,"A17") | str_detect(Causa,"A18") |
                           str_detect(Causa,"A19"), "Tuberculosis", "Otra"))
    # A tibble: 688,468 × 9
       Entidad Municipio  Sexo  Edad   Día   Mes   Año Causa TB   
       <chr>   <chr>     <dbl> <dbl> <dbl> <dbl> <dbl> <chr> <chr>
     1 01      001           2  4061     7     1  2017 C259  Otra 
     2 01      001           1  4069    18     1  2017 K631  Otra 
     3 01      001           1  4091    20     1  2017 J441  Otra 
     4 01      001           2  4076     1     1  2017 I698  Otra 
     5 01      001           1  4070    20     1  2017 C61X  Otra 
     6 01      001           2  4048    20     1  2017 K803  Otra 
     7 01      001           1  4062    12     1  2017 C61X  Otra 
     8 01      001           1  4089    13     1  2017 N390  Otra 
     9 01      001           2  4042     8     1  2017 E117  Otra 
    10 01      001           2  4085    14     1  2017 I120  Otra 
    # … with 688,458 more rows

    Además del if_else (que sirve para dos condiciones) existe el case_when que sirve para múltiples. La redacción siempre es:

    case_when(
      CONDICION1 ~ VALOR1,
      CONDICION2 ~ VALOR2,
      CONDICION3 ~ VALOR3,
      TRUE ~ VALOR_DEFAULT #Este se puede omitir y el default es NA
    )

    Por ejemplo, la vez anterior eliminamos aquellos que tenían sexo faltante. Podemos mejor dejarlos como missing: NA

    mortalidad_2017 %>%
      mutate(`Sexo corregido` = case_when(
        `Sexo` == 1 ~ "Hombre",
        `Sexo` == 2 ~ "Mujer",
        TRUE ~ NA_character_ 
      ))
    # A tibble: 688,468 × 9
       Entidad Municipio  Sexo  Edad   Día   Mes   Año Causa `Sexo corregido`
       <chr>   <chr>     <dbl> <dbl> <dbl> <dbl> <dbl> <chr> <chr>           
     1 01      001           2  4061     7     1  2017 C259  Mujer           
     2 01      001           1  4069    18     1  2017 K631  Hombre          
     3 01      001           1  4091    20     1  2017 J441  Hombre          
     4 01      001           2  4076     1     1  2017 I698  Mujer           
     5 01      001           1  4070    20     1  2017 C61X  Hombre          
     6 01      001           2  4048    20     1  2017 K803  Mujer           
     7 01      001           1  4062    12     1  2017 C61X  Hombre          
     8 01      001           1  4089    13     1  2017 N390  Hombre          
     9 01      001           2  4042     8     1  2017 E117  Mujer           
    10 01      001           2  4085    14     1  2017 I120  Mujer           
    # … with 688,458 more rows

    Nota que pusimos NA_character_ para indicar el faltante. Esto es porque existen diferentes tipos de valores faltantes según la variable que tenemos: NA_real_ para números, NA_integer_ para números enteros y NA_character_ para palabras/caracteres.

    Como nota no hace falta poner la última condición para que R sepa que aquellos que no son "Hombre" o "Mujer" son faltantes:

    #Es lo mismo
    mortalidad_2017 %>%
      mutate(`Sexo corregido` = case_when(
        `Sexo` == 1 ~ "Hombre",
        `Sexo` == 2 ~ "Mujer",
      ))
    # A tibble: 688,468 × 9
       Entidad Municipio  Sexo  Edad   Día   Mes   Año Causa `Sexo corregido`
       <chr>   <chr>     <dbl> <dbl> <dbl> <dbl> <dbl> <chr> <chr>           
     1 01      001           2  4061     7     1  2017 C259  Mujer           
     2 01      001           1  4069    18     1  2017 K631  Hombre          
     3 01      001           1  4091    20     1  2017 J441  Hombre          
     4 01      001           2  4076     1     1  2017 I698  Mujer           
     5 01      001           1  4070    20     1  2017 C61X  Hombre          
     6 01      001           2  4048    20     1  2017 K803  Mujer           
     7 01      001           1  4062    12     1  2017 C61X  Hombre          
     8 01      001           1  4089    13     1  2017 N390  Hombre          
     9 01      001           2  4042     8     1  2017 E117  Mujer           
    10 01      001           2  4085    14     1  2017 I120  Mujer           
    # … with 688,458 more rows

    En un mutate podemos sobreescribir nombres de variables (es decir asignarle a Sexo un nuevo valor de Sexo). Esto sólo se sobreescribe en R y no la original.

    #Es lo mismo
    mortalidad_2017 %>%
      mutate(`Sexo` = case_when(
        `Sexo` == 1 ~ "Hombre",
        `Sexo` == 2 ~ "Mujer",
      ))
    # A tibble: 688,468 × 8
       Entidad Municipio Sexo    Edad   Día   Mes   Año Causa
       <chr>   <chr>     <chr>  <dbl> <dbl> <dbl> <dbl> <chr>
     1 01      001       Mujer   4061     7     1  2017 C259 
     2 01      001       Hombre  4069    18     1  2017 K631 
     3 01      001       Hombre  4091    20     1  2017 J441 
     4 01      001       Mujer   4076     1     1  2017 I698 
     5 01      001       Hombre  4070    20     1  2017 C61X 
     6 01      001       Mujer   4048    20     1  2017 K803 
     7 01      001       Hombre  4062    12     1  2017 C61X 
     8 01      001       Hombre  4089    13     1  2017 N390 
     9 01      001       Mujer   4042     8     1  2017 E117 
    10 01      001       Mujer   4085    14     1  2017 I120 
    # … with 688,458 more rows

    Finalmente podemos combinar operaciones que ya hemos visto antes como tally y group_by por poner un ejemplo:

    #Es lo mismo
    mortalidad_2017 <- mortalidad_2017 %>%
      mutate(`Sexo` = case_when(
        `Sexo` == 1 ~ "Hombre",
        `Sexo` == 2 ~ "Mujer",
      )) 
    
    #Tabla de sexo
    mortalidad_2017 %>% 
      group_by(`Sexo`) %>% 
      tally()
    # A tibble: 3 × 2
      Sexo        n
      <chr>   <int>
    1 Hombre 386125
    2 Mujer  301979
    3 <NA>      364

    Un ejemplo más complicado de case_when consiste en asignar el tipo de tuberculosis a cada causa:

    mortalidad_2017 %>%
      mutate(`Tipo tuberculosis` = case_when(
        str_detect(`Causa`, "A15") ~ "Tuberculosis respiratoria",
        str_detect(`Causa`, "A17") ~ "Tuberculosis del sistema nervioso",
        str_detect(`Causa`, "A18") ~ "Tuberculosis de otros órganos",
        str_detect(`Causa`, "A19") ~ "Tuberculosis miliar",
        TRUE ~ "Sin tuberculosis" #Valor default
      )) %>%
      filter(`Tipo tuberculosis` != "Sin tuberculosis") %>%
      group_by(`Tipo tuberculosis`) %>%
      tally()
    # A tibble: 4 × 2
      `Tipo tuberculosis`                   n
      <chr>                             <int>
    1 Tuberculosis de otros órganos       113
    2 Tuberculosis del sistema nervioso    89
    3 Tuberculosis miliar                 116
    4 Tuberculosis respiratoria           516

    6.7 Unión de otras bases usando _join

    Unión de bases de datos usando diferentes tipos de _join. Fuente: William Surles (https://rpubs.com/williamsurles/293454)

    Para unir los nombres de las entidades o de los municipios podríamos hacer un case_when gigante pero eso es poco eficiente dado que el INEGI nos provee de una base de datos (decateml.csv). Leámosla

    codigos_entidad <- read_csv("decateml.csv", 
                                locale = locale(encoding = "WINDOWS-1252"))

    Nota que las entidades son todas aquellas que en cve_mun y cve_loc tienen ceros. Primero hagamos una base de entidades quedándonos sólo con cve_ent y nom_loc:

    base_entidades <- codigos_entidad %>%
      filter(`cve_loc` == "0000") %>%
      filter(`cve_mun` == "000") %>%
      select(`cve_ent`, `nom_loc`) %>%
      rename(`Entidad federativa` = `nom_loc`)
    # A tibble: 37 × 2
       cve_ent `Entidad federativa`
       <chr>   <chr>               
     1 01      Aguascalientes      
     2 02      Baja California     
     3 03      Baja California Sur 
     4 04      Campeche            
     5 05      Coahuila de Zaragoza
     6 06      Colima              
     7 07      Chiapas             
     8 08      Chihuahua           
     9 09      Ciudad de México    
    10 10      Durango             
    # … with 27 more rows

    Nota que en la base_entidades la columna con la clave de la entidad se llama cve_ent mientras que en la base de mortalidad_2017 se llama Entidad. Para juntar las bases usaremos un left_join. Esta instrucción lo que hace es tomar una base grande y pegarle el diccionario de datos de una base pequeña como sigue:

    grande %>% left_join(pequeña)

    En nuestro caso la base grande es mortalidad_2017 y la base pequeña es base_entidades y las variables en común son: Entidad = cve_ent.

    mortalidad_2017 <- mortalidad_2017 %>%
      left_join(base_entidades, by = c("Entidad" = "cve_ent"))

    En el caso del municipio requerimos dos columnas cve_ent (Entidad) y cve_mun (Municipio). Para ello filtramos la base inicial del INEGI:

    base_municipios <- codigos_entidad %>%
      filter(`cve_loc` == "0000") %>%
      filter(`cve_mun` != "000") %>%
      select(`cve_ent`, `cve_mun`, `nom_loc`) %>%
      rename(`Nombre del municipio` = `nom_loc`)

    y pegamos a nuestros datos:

    mortalidad_2017 <- mortalidad_2017 %>%
      left_join(base_municipios, 
                by = c("Entidad" = "cve_ent",
                       "Municipio" = "cve_mun"))

    Podemos entonces mostrar las defunciones para los municipios de Sinaloa:

    mortalidad_2017 %>%
      filter(`Entidad federativa` == "Sinaloa") %>%
      group_by(`Nombre del municipio`) %>%
      tally()
    # A tibble: 18 × 2
       `Nombre del municipio`     n
       <chr>                  <int>
     1 Ahome                   2509
     2 Angostura                434
     3 Badiraguato              105
     4 Choix                    128
     5 Concordia                149
     6 Cosalá                    63
     7 Culiacán                5007
     8 El Fuerte                332
     9 Elota                    130
    10 Escuinapa                292
    11 Guasave                 1407
    12 Mazatlán                2943
    13 Mocorito                 214
    14 Navolato                 549
    15 Rosario                  249
    16 Salvador Alvarado        354
    17 San Ignacio               95
    18 Sinaloa                  322

    6.8 Pivoteo de bases con pivot

    La siguiente tabla muestra por sexo y entidad las defunciones. Muchas veces para mejorar el formato buscamos transponer la tabla de tal forma que hombres sea una columna y mujeres otra. Éste no es el formato recomendado para análisis pero a veces sí para presentar. Para poder transformar la tabla podemos pivot_wider:

    #Tabla en formato largo (long)
    formato_largo <- mortalidad_2017 %>%
      group_by(`Entidad federativa`, Sexo) %>%
      tally()
    formato_largo
    # A tibble: 96 × 3
    # Groups:   Entidad federativa [32]
       `Entidad federativa` Sexo       n
       <chr>                <chr>  <int>
     1 Aguascalientes       Hombre  3315
     2 Aguascalientes       Mujer   2669
     3 Aguascalientes       <NA>       2
     4 Baja California      Hombre 13135
     5 Baja California      Mujer   7420
     6 Baja California      <NA>      17
     7 Baja California Sur  Hombre  2617
     8 Baja California Sur  Mujer   1327
     9 Baja California Sur  <NA>       5
    10 Campeche             Hombre  2526
    # … with 86 more rows

    Podemos decirle a R que vuelva cada sexo una columna. Para ello hay que especificar las variables que quedan constantes como columnas en id_cols (en este caso Entidad federativa) y las que van a cambiar a columna (names_from) Sexo junto con el valor asignar (values_from) n:

    formato_ancho <- formato_largo %>%
      pivot_wider(id_cols = `Entidad federativa`,
                  names_from  = `Sexo`,
                  values_from = `n`)
    # A tibble: 32 × 4
    # Groups:   Entidad federativa [32]
       `Entidad federativa` Hombre Mujer  `NA`
       <chr>                 <int> <int> <int>
     1 Aguascalientes         3315  2669     2
     2 Baja California       13135  7420    17
     3 Baja California Sur    2617  1327     5
     4 Campeche               2526  1945     6
     5 Chiapas               14474 12051     5
     6 Chihuahua             13845  9613    10
     7 Ciudad de México      39204 36096    10
     8 Coahuila de Zaragoza   8877  7256     4
     9 Colima                 3049  1820     2
    10 Durango                4862  3627     1
    # … with 22 more rows

    por otro lado si tenemos una base en formato ancho wide y que queremos pasar a largo para su análisis (long) podemos trabajar con pivot_longer seleccionando en cols las columnas a transformar, bajo qué nombre quedan en names_to y bajo qué valor en values_to:

    #Y de regreso
    formato_ancho %>%
      pivot_longer(cols = c(`Mujer`, `Hombre`, `NA`),
                   names_to = "Sexo",
                   values_to = "n")
    # A tibble: 96 × 3
    # Groups:   Entidad federativa [32]
       `Entidad federativa` Sexo       n
       <chr>                <chr>  <int>
     1 Aguascalientes       Mujer   2669
     2 Aguascalientes       Hombre  3315
     3 Aguascalientes       NA         2
     4 Baja California      Mujer   7420
     5 Baja California      Hombre 13135
     6 Baja California      NA        17
     7 Baja California Sur  Mujer   1327
     8 Baja California Sur  Hombre  2617
     9 Baja California Sur  NA         5
    10 Campeche             Mujer   1945
    # … with 86 more rows

    6.9 Unión de columnas con paste

    En nuestra base de datos tenemos el día, mes y año separados en las columnas homónimas. Podemos juntarlas en una sola con paste especificando cómo separarlas con sep:

    mortalidad_2017 <- mortalidad_2017 %>%
      mutate(Fecha = paste(Día, Mes, Año, sep = "-"))
    # A tibble: 688,468 × 11
       Entidad Municipio Sexo    Edad   Día   Mes   Año Causa Entida…¹ Nombr…² Fecha
       <chr>   <chr>     <chr>  <dbl> <dbl> <dbl> <dbl> <chr> <chr>    <chr>   <chr>
     1 01      001       Mujer   4061     7     1  2017 C259  Aguasca… Aguasc… 7-1-…
     2 01      001       Hombre  4069    18     1  2017 K631  Aguasca… Aguasc… 18-1…
     3 01      001       Hombre  4091    20     1  2017 J441  Aguasca… Aguasc… 20-1…
     4 01      001       Mujer   4076     1     1  2017 I698  Aguasca… Aguasc… 1-1-…
     5 01      001       Hombre  4070    20     1  2017 C61X  Aguasca… Aguasc… 20-1…
     6 01      001       Mujer   4048    20     1  2017 K803  Aguasca… Aguasc… 20-1…
     7 01      001       Hombre  4062    12     1  2017 C61X  Aguasca… Aguasc… 12-1…
     8 01      001       Hombre  4089    13     1  2017 N390  Aguasca… Aguasc… 13-1…
     9 01      001       Mujer   4042     8     1  2017 E117  Aguasca… Aguasc… 8-1-…
    10 01      001       Mujer   4085    14     1  2017 I120  Aguasca… Aguasc… 14-1…
    # … with 688,458 more rows, and abbreviated variable names
    #   ¹​`Entidad federativa`, ²​`Nombre del municipio`

    Una vez que están unidas podemos usar la librería lubridate para convertirlas a fecha usando dmy si es día-mes-año o ymd si es año mes día (mdy ¿para qué será?)

    library(lubridate)
    mortalidad_2017 <- mortalidad_2017 %>%
      mutate(Fecha = dmy(Fecha))

    Una vez es convertida en fecha podemos hacer operaciones con fechas por ejemplo contar cuántos días han pasado desde el 01 de enero del 2017 hasta la fecha:

    mortalidad_2017 <- mortalidad_2017 %>%
      mutate(`Días desde primero de enero` = Fecha - dmy("01/01/2017"))

    o bien obtener la semana epidemiológica y el año epidemiológico:

    mortalidad_2017 <- mortalidad_2017 %>%
      mutate(`Semana epidemiológica` = epiweek(Fecha)) %>%
      mutate(`Año epidemiológico` = epiyear(Fecha))

    6.10 Ejercicio

    El ejercicio consiste en usar las siguientes funciones en una base de datos de tu preferencia al menos una vez para responder preguntas de la base de datos. + filter + group_by + mutate + select + tally + rename + summarise + Al menos una de las siguientes: left_join, right_join, full_join, inner_join + Al menos una de las siguientes: pivot_longer, pivot_wider + Una gráfica con ggplot Si no tienes una base de datos puedes usar la que sigue:

    En el siguiente hipervínculo puedes encontrar la base de datos de Enfermedades Febriles Exantemáticas más reciente de la Dirección General de Epidemiología (Base de Datos) así como el significado de cada uno de los códigos en Diccionario de Datos. Cada renglón de la base de datos representa un caso distinto de una de estas enfermedades.

    Utiliza la base para responder las siguientes preguntas usando al menos una vez (en todo el ejercicio) las funciones:

    • filter
    • group_by
    • mutate
    • select
    • tally
    • rename
    • summarise
    • Al menos una de las siguientes: left_join, right_join, full_join, inner_join
    • Al menos una de las siguientes: pivot_longer, pivot_wider
    • Una gráfica con ggplot
    1. ¿Cuántos casos se han presentado este año?

    2. ¿Cuántos presentaron fiebre?

    3. ¿Cuántos casos en hombres y cuántos en mujeres?

    4. ¿Cuál es la edad promedio de los casos?

    5. De los casos ¿cuántos hombres estaban vacunados y cuántas mujeres vacunadas?. Genera una tabla de 2 por 2 que se vea exactamente así:

      Hombres Mujeres
      Con al menos una vacuna --- ---
      Sin vacuna --- ---
    6. De los casos ¿qué proporción de los hombres estaban vacunados y qué proporción de las mujeres vacunadas?

    7. Utiliza la población del Censo 2020 del INEGI para calcular la incidencia por cada 10000 habitantes por entidad y encontrar la entidad con mayor incidencia.

    8. Grafica la incidencia de casos totales por semana epidemiológica usando ggplot2.

    6.11 Para saber más

    La mayor recomendación es el libro R4DS (R para ciencia de datos) el cual puede encontrarse gratuitamente en línea: nueva edición (inglés): https://r4ds.had.co.nz/ edición previa (español): https://es.r4ds.hadley.nz/