Análisis exploratorio de datos con tidyverse
Parte 1: Fundamentos de análisis exploratorio en R
dplyr
para filtrar (filter
), seleccionar (select
), mutar (mutate
), agrupar (group_by
), y resumir (summarise
) bases de datos en R
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:
- 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.
- Análisis de datos incluye tres pasos que fluyen en cualquier orden:
- Formulación de preguntas ¿qué me gustaría saber de mis datos?_
- Visualización de los datos ¿puede una gráfica ayudarme a responder mi pregunta u orientarme hacia qué analizar?
- 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?
- 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:
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.
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 deR
usados. Si eliges la opciónrenv
, cualquier otra persona que use el proyecto se le instalarán los paquetes que tú usaste y las versiones específicas (digamos tuggplot2
es del 2021 entonces esa persona tendrá eseggplot2
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 (puesctrl Z
es limitado).Open in new session
cierra la ventana actual deRStudio
y te abre el proyecto en un nuevo lienzo en blanco para que comiences tu trabajo.
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!
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:
<- read_csv("casos_covid_agosto_2022.csv") casos_covid
Para los archivos delimitados por espacios podemos usar read_tsv
:
<- read_tsv("embarazo_adolescente.txt") adolescentes
Finalmente archivos con delimitadores que no son comas ni tabs (como los |
) puedes usar read_delim
y especificar el separador delim
:
<- read_delim("covid_sinave_bc_bcs.txt", delim = "|") covid
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:
- Los acentos en algunos equipos no se leen bien
- 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,Poblaci
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:
<- read_csv("zapopan.csv",
zapopan 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:
<- read_excel("persona_cigarros.xlsx") cigarros
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:
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:
<- read_excel("Poblacion_01.xlsx", range = "A5:C38") poblacion
3.3 Ejercicios
- Lee las bases de datos
ile-2019-2021.csv
,IME_2020.xls
yniñ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:
<- read_csv("conjunto_de_datos_defunciones_generales_2017.csv") mortalidad_2017
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:
%>% glimpse() mortalidad_2017
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
, |>
:
|> glimpse() mortalidad_2017
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.
%>% ncol() #Columnas mortalidad_2017
[1] 59
%>% tally() #Filas mortalidad_2017
# 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.
%>% nrow() #Filas mortalidad_2017
[1] 703047
Podemos ver los nombres de las columnas de la base de datos con colnames
:
#Mostramos las columnas
%>% colnames() mortalidad_2017
[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
"sexo"] mortalidad_2017[ ,
# 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
2] mortalidad_2017[ ,
# 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:
3, ] mortalidad_2017[
# 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í:
1, "lista1"] mortalidad_2017[
# 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:
$edo_civil mortalidad_2017
[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
:
%>% select(edo_civil) mortalidad_2017
# 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
%>% select(contains("civil")) mortalidad_2017
# 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:
$edo_civil[7] mortalidad_2017
[1] 5
Lo cual es similar (mas no equivalente) a la forma anterior:
7, "edo_civil"] mortalidad_2017[
# 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
%>% slice(11) mortalidad_2017
# 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 c
2. Un vector es una lista ordenada de variables del mismo tipo. Por ejemplo:
2 Se llama c
por concatenate
(concatenar).
<- c(1, 141, 12) mi_vector
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!
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!
2] #entrada 2 mi_vector[
[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
<- c("Alejandro", "Beatriz", "Alejandro", "Carla")
nombres_de_amigos
#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
:
c("sexo", "edad")] mortalidad_2017[ ,
# 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
c(1, 7), c("sexo", "edad")] mortalidad_2017[
# 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
1:7, c("sexo", "edad")] mortalidad_2017[
# 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
2:7, 5:9] mortalidad_2017[
# 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
- Lee la hoja
MCV2
del archivounicef_vacunas.xlsx
el cual contiene información sobre vacunasMCV2
dada por la UNICEF. Responde las siguientes preguntas:
- Determina los nombres de todas las columnas de las variables usando
R
(no vale ver el archivo). - Determina el número de renglones y el número de filas totales de la base.
- Encuentra cuál fila contiene a México en la columna de
country
. - Regresa todas las mediciones para la fila de Colombia.
- Regresa la 5a columna.
- Obtén el nombre de la columna
9
. - Obtén la entrada en la columna
5
y fila14
.
- Considera la base de datos creada por el siguiente código:
<- tibble(Tiempo = rexp(100),
base_inventada Enfermo = rbinom(100, 83, 1/3))
Determina qué ocasionó los resultados siguientes:
- ¿Por qué da error?
#Primer error
200] base_inventada[ ,
Error in `base_inventada[, 200]`:
! Can't subset columns past the end.
ℹ Location 200 doesn't exist.
ℹ There are only 2 columns.
- ¿Por qué da
NA
?
#NA
1000, ] base_inventada[
# A tibble: 1 × 2
Tiempo Enfermo
<dbl> <int>
1 NA NA
- ¿Por qué dice esto?
#Primer error
0,0] base_inventada[
# A tibble: 0 × 0
- ¿Por qué da error`?
2, c("tiempo")] base_inventada[
Error in `base_inventada[2, c("tiempo")]`:
! Can't subset columns that don't exist.
✖ Column `tiempo` doesn't exist.
- Arregla este código para que no dé error
%>% select("Tiempo")
base.inventada %>% 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.
#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 %>%
mortalidad_2017_pedazo 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
%>% tally() mortalidad_2017
# 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:
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:
- ¿Cuántos países están registrados para la región
ROSA
? - ¿Cuántos países en
2020
lograron una cobertura mayor al 90%? - Dentro de la región de Latinoamérica y el Caribe (
LACR
) ¿cuántos países lograron una cobertura menor a 80%? - ¿Cuál fue la cobertura de México, Colombia y Uruguay en
2020
? - ¿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
<- mortalidad_2017 %>%
conteo_sexo_entidad 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(
~ VALOR1,
CONDICION1 ~ VALOR2,
CONDICION2 ~ VALOR3,
CONDICION3 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
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
<- read_csv("decateml.csv",
codigos_entidad 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
:
<- codigos_entidad %>%
base_entidades 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:
%>% left_join(pequeña) grande
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
:
<- codigos_entidad %>%
base_municipios 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)
<- mortalidad_2017 %>%
formato_largo 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_largo %>%
formato_ancho 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 conggplot
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
¿Cuántos casos se han presentado este año?
¿Cuántos presentaron fiebre?
¿Cuántos casos en hombres y cuántos en mujeres?
¿Cuál es la edad promedio de los casos?
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 --- --- De los casos ¿qué proporción de los hombres estaban vacunados y qué proporción de las mujeres vacunadas?
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.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/