7  Limpieza de bases y estadística descriptiva

AdvertenciaEste capítulo usa las bases más pesadas del curso

Trabaja con las bases de defunciones generales del INEGI (varios años, y cada archivo pesa más de 100 MB) y con sus catálogos. Vienen en la descarga de Dropbox igual que el resto de las bases, dentro de datasets/, pero si tienes poco espacio o poca paciencia, considera que este capítulo tarda bastante en correr.

Si sólo vienes a leer, no necesitas descargar nada: los resultados que ves ya están calculados.

8 Estadística descriptiva y limpieza de bases

Existen dos formas de limpiar bases en R. La “clásica” usando sólo las funciones de R (como which, subset e identificadores de columnas) y la “nueva” (y más sencilla) usando el paquete de tidyverse. Yo estoy seguro que si ya conoces otro programa estadístico (por ejemplo STATA) te será mucho más fácil continuar limpiando tu base en èl. Aprenderemos a hacerlo en R de todas formas para entender cómo funciona ¡capaz que te convence!

Primero que nada, carguemos la librería de tidyverse:

# No olvides instalarla con install.packages si aún
# no lo has hecho
library("tidyverse")

9 Descripción de una base 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:

# No olvides el directorio
mortalidad.2017 <- read.csv("conjunto_de_datos_defunciones_generales_2017.CSV")

Aquí sólo muestro las primeras columnas de la base y sus primeras entradas:

ent_regis mun_regis ent_resid mun_resid tloc_resid loc_resid
1 1 1 1 15 1
1 9 1 9 1 16
1 1 1 1 15 1
1 6 1 6 8 1
1 1 1 1 15 1
1 1 1 1 15 1

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

mortalidad.2017 %>% glimpse()
Rows: 703,047
Columns: 7
$ ent_regis  <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,…
$ mun_regis  <dbl> 1, 9, 1, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,…
$ ent_resid  <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,…
$ mun_resid  <dbl> 1, 9, 1, 6, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1,…
$ tloc_resid <int> 15, 1, 15, 8, 15, 15, 15, 15, 15, 5, 15, 1, 15, 15, 1, 15, …
$ loc_resid  <dbl> 1, 16, 1, 1, 1, 1, 1, 1, 1, 1025, 1, 55, 1, 1, 7777, 1, 1, …
$ ent_ocurr  <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,…

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

ncol(mortalidad.2017) # Columnas
[1] 59
nrow(mortalidad.2017) # Filas
[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" 
 [ reached 'max' / getOption("max.print") -- omitted 9 entries ]

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

NEMÓNICO NOMBRE_CAMPO
ent_regis Entidad Registro
mun_regis Municipio Registro
ent_resid Entidad Residencia
mun_resid Municipio Residencia
tloc_resid Tamaño Localidad Residencia
loc_resid Clave Localidad de Residencia
ent_ocurr Entidad Ocurrencia
mun_ocurr Municipio Ocurrencia
tloc_ocurr Tamaño de Localidad Ocurrencia
loc_ocur Clave Localidad de Ocurrencia
causa_def Causa Defunción (Lista Detallada)
lista_mex Causa Defunción (Lista Mexicana)
sexo Sexo
edad Edad
dia_ocurr Día Defunción
mes_ocurr Mes Defunción
anio_ocur Año Defunción
dia_regis Día Registro
mes_regis Mes Registro
anio_regis Año Registro
dia_nacim Día Nacimiento
mes_nacim Mes Nacimiento
anio_nacim Año Nacimiento
ocupacion Ocupación
escolarida Escolaridad
edo_civil Estado Conyugal
presunto Presunto
ocurr_trab Ocurrió Trabajo
lugar_ocur Sitio donde Ocurrio la Lesión
necropsia Necropsia
asist_medi Asistencia Médica
sitio_ocur Sitio donde Ocurrio la Defunción
cond_cert Certificada Por
nacionalid Nacionalidad
derechohab Derechohabiencia
embarazo Condición de embarazo
rel_emba Causas relacionadas con embarazo
horas Hora de la defunción
minutos Minuto de la defunción
capitulo Capitulo
grupo Grupo
lista1 Lista1
gr_lismex Grupos lista mexicana
vio_fami Violencia Familiar
area_ur Area Urbano Rural
edad_agru Edad agrupada
complicaro Complicaron el embarazo
dia_cert Día de Certificación
mes_cert Mes de Certificación
anio_cert Año de Certificación
maternas Maternas
lengua Lengua indígena
cond_act Condición de Actividad económica
par_agre Parentesco del presunto agresor
ent_ocules Entidad Ocurrencia de la lesión
mun_ocules Municipio Ocurrencia de la lesión
loc_ocules Clave Localidad de Ocurrencia de la lesión
razon_m Razón Materna
dis_re_oax Distritos de Oaxaca

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"]
[1] 2 2 1 2 2 1

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

# Me regresa las observaciones de la columna 2
# dada por mun_regis
mortalidad.2017[, 2]
[1] 1 9 1 6 1 1

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

mortalidad.2017[3, ]
  ent_regis mun_regis ent_resid mun_resid tloc_resid loc_resid
3         1         1         1         1         15         1

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

mortalidad.2017[1, "lista1"]
[1] 69

En resumen, la notación siempre es de la siguiente forma: \[ \text{Base.de.datos}[\underbrace{f}_{fila},\overbrace{c}^{columna}] \] Esta notación notación matricial estándar en el mundo de computación y de las matemáticas. Siempre siempre primero es fila luego columna. ¡No lo olvides pues nos será útil para los modelos!

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{Base.de.datos}\$\text{Columna}[\underbrace{f}_{\text{Fila}}] \]

Una última opción es con select:

mortalidad.2017 %>% select(c("edo_civil"))
[1] 3 5 3 3 2 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"))
  edo_civil
1         3
2         5
3         3
4         3
5         2
6         5

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

mortalidad.2017$edo_civil[7]
[1] 5

Lo cual es equivalente a la forma anterior:

mortalidad.2017[7, "edo_civil"]

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)
     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
 [ reached 'max' / getOption("max.print") -- omitted 9 columns ]
 [ reached 'max' / getOption("max.print") -- omitted 1 rows ]

Podemos combinar multiples argumentos con %>%1:

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

mortalidad.2017 %>%
  select(c("sexo", "edo_civil")) %>%
  slice(11:20)
   sexo edo_civil
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 data.frames con un agregado: ¡sólo hay filas, no hay columnas!

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")]
  sexo edad
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")]
  sexo edad
1    2 4068
7    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")]
  sexo edad
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(c("sexo", "edad")) %>%
  slice(1:7)
  sexo edad
1    2 4068
2    2 4090
3    1 4088
4    2 4096
5    2 4051
6    1 4078
7    1 4070

NOTA Los dos puntos no funcionan para seleccionar columnas usando los nombres de las columnas como caracteres:

# Selecciona renglones del 2 al 7
# y las columnas 5 a 9
mortalidad.2017[2:7, 5:9]
  tloc_resid loc_resid ent_ocurr mun_ocurr tloc_ocurr
2          1        16         1         9          1
3         15         1         1         1         15
4          8         1         1         6          8
5         15         1         1         1         15
6         15         1         1         1         15
7         15         1         1         1         15

Los : son una forma corta de hacer vectores, por eso los usamos:

9:15
[1]  9 10 11 12 13 14 15

9.1 Ejercicios

  1. Lee el archivo diversidad_dieta_adultos_251116.dta el cual contiene el cuestionario de frecuencia de consumo de nutrimentos de la encuesta nacional de salud y nutrición (ENSANUT) 2016. Para ello usa el comando read_dta de la librería haven o bien en RStudio > Import Dataset > From STATA.
Nota

Este archivo no viene con las bases del curso porque es de la ENSANUT 2016 y se descarga aparte. Si no lo tienes, puedes hacer todo el ejercicio con cualquier otra base que sí tengas (por ejemplo datasets/diabetes.csv con read_csv): lo que se practica son los comandos, no esta base en particular.

library(haven)
ffq.2016 <- read_dta("diversidad_dieta_adultos_251116.dta")
  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 columnas totales de la base.
  3. Obtén el valor de folio_sel que está en la fila 1234 y después encuentra en qué fila vuelve a aparecer ese mismo valor.
  4. Regresa todas las mediciones de la penúltima fila (la que está diez lugares antes de la última).
  5. Regresa la 5a columna.
  6. Obtén el nombre de la penúltima columna.
  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 <- data.frame(
  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 `[.data.frame`:
! columnas no definidas seleccionadas
  1. ¿Por qué da NA?
# NA
base.inventada[1000, ]
   Tiempo Enfermo
NA     NA      NA
  1. ¿Por qué dice esto?
# Primer error
base.inventada[0, 0]
data frame with 0 columns and 0 rows
  1. ¿Por qué da NULL?
# NULL
base.inventada[2, c("tiempo")]
NULL
  1. Arregla este código para que no dé error
base.inventada %>% select("Tiempo")
               %>% slice(2)

10 Limpieza de la base de datos

De la base de mortalidad comencemos por quedarnos sólo con las columnas ent_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.editada <- mortalidad.2017 %>%
  select(c(
    "ent_regis", "sexo", "edad",
    "dia_ocurr", "mes_ocurr", "anio_ocur", "causa_def"
  ))

Ojo anio_ocur tiene sólo una r.

Utilicemos colnames para mejorar los nombres de las variables:

colnames(mortalidad.2017.editada) <- c(
  "Entidad", "Sexo", "Edad",
  "Día", "Mes", "Año", "Causa"
)

Vamos a asociar a cada uno de los registros la variable correspondiente. Para ello leemos las bases. Comencemos con leer la base de causas de la defunción:

# Base mal leída
dic.causa <- read.csv("Catalogo_datos_inegi/decatcausa.csv")
   CVE                                                 DESCRIP
1 A000 C\xf3lera debido a Vibrio cholerae 01, biotipo cholerae
2 A001   C\xf3lera debido a Vibrio cholerae 01, biotipo el Tor
3 A009                              C\xf3lera, no especificado
4 A010                                         Fiebre tifoidea
5 A011                                   Fiebre paratifoidea A
6 A012                                   Fiebre paratifoidea B

Según estés en Mac o Windows y el archivo provenga de la otra plataforma o de otro país puede que te llegues a topar con problemas como éste: las tildes se leen como quiere (seguro te ha pasado con Excel). Para leerlas correctamente, R contiene la variable encoding. Usualmente el encoding es UTF-8 pero Windows es Windows… En mi experiencia con bases de datos mexicanas los encodings suelen ser UTF-8, latin1 ó WINDOWS-1252 así que siempre pruebo esos.3

3  No existe forma de detectar el encoding de un archivo. Y todos los programas se enfrentan a él. Mientras no haya una estandarización, seguiremos con estos problemas.

Probemos el encoding latin1:

dic.causa <- read.csv("Catalogo_datos_inegi/decatcausa.csv",
  encoding = "latin1"
)
   CVE                                              DESCRIP
1 A000 Cólera debido a Vibrio cholerae 01, biotipo cholerae
2 A001   Cólera debido a Vibrio cholerae 01, biotipo el Tor
3 A009                              Cólera, no especificado
4 A010                                      Fiebre tifoidea
5 A011                                Fiebre paratifoidea A
6 A012                                Fiebre paratifoidea B

Repetimos el proceso con las otras bases:

# Base con información de sexo
dic.edad <- read.csv("Catalogo_datos_inegi/deedad.csv",
  encoding = "latin1"
)

# Base con información de sexo
dic.sexo <- read.csv("Catalogo_datos_inegi/desexo.csv",
  encoding = "latin1"
)

# Base con información de los estados
dic.lugar <- read.csv("Catalogo_datos_inegi/decateml.csv",
  encoding = "latin1"
)

Vamos a pegar la base de edad. Para ello lo que necesitamos hacer un merge. merge combina dos bases de datos según identificadores en común. Para el merge especificamos la columna (o vector de columnas) que contienen el identificador común.

# Juntamos sexo con su identificador
mortalidad.2017.editada.v2 <- merge(mortalidad.2017.editada, dic.sexo,
  by.x = "Sexo", by.y = "CVE",
  all.x = TRUE, all.y = FALSE
)

Para no tener dos columnas con sexo, borramos una de ellas y renombramos, usando rename la segunda de ellas:

# Eliminamos la columna de sexo
mortalidad.2017.editada.v2 <- mortalidad.2017.editada.v2 %>%
  select(-c("Sexo"))

# Renombramos DESCRIP como Sexo
mortalidad.2017.editada.v2 <- mortalidad.2017.editada.v2 %>%
  rename("Sexo" = "DESCRIP")

10.0.1 Ejercicio

Repite el proceso con las bases deedad.csv para la edad y decatcausa.csv para la causa de muerte, a fin de obtener una base de mortalidad.2017.editada.v2 que se vea así:

Entidad Día Mes Año Sexo Edad Causa
15 9 7 2017 Mujeres Setenta y tres años Fiebre tifoidea
17 22 8 2017 Hombres Sesenta y tres años Fiebre tifoidea
7 26 4 2017 Mujeres Treinta y tres años Fiebre tifoidea
11 18 8 2017 Mujeres Ochenta y ocho años Fiebre tifoidea
7 16 10 2017 Mujeres Once años Fiebre tifoidea
21 30 1 2017 Hombres Treinta y cinco años Fiebre tifoidea

Finalmente, podemos unir los identificadores de entidad y localidad. Nota que el nombre de la entidad se puede obtener a partir de aquellos en dic.lugar que tienen en ceros el identificador de municipio y de localidad. Por lo que crearemos una sub-base que contenga sólo el nombre de las entidades. Para ello, utilizamos el comando filter:

dic.entidad <- dic.lugar %>%
  filter(cve_mun == 0 & cve_loc == 0) %>%
  select(c("cve_ent", "nom_loc"))

Asignamos la entidad a la base:

# Juntamos con la base
mortalidad.2017.editada.v2 <- merge(mortalidad.2017.editada.v2,
  dic.entidad,
  by.x = "Entidad",
  by.y = "cve_ent", all.x = TRUE,
  all.y = FALSE
)

# Eliminamos la columna de edad
mortalidad.2017.editada.v2 <- mortalidad.2017.editada.v2 %>%
  select(-c("Entidad"))

# Renombramos DESCRIP como Sexo
mortalidad.2017.editada.v2 <- mortalidad.2017.editada.v2 %>%
  rename("Entidad" = "nom_loc")

Nota que el comando filter lo que hace es seleccionar elementos de la base que cumplan con los criterios especificados. Por ejemplo, podemos generar una base sólo para Sonora:

# Sólo Sonora
mortalidad.2017.editada.v2 %>% filter(Entidad == "Sonora")

El comando distinct te permite encontrar todos los valores que toma una variable:

# Vemos cuáles valores toma Entidad
mortalidad.2017.editada.v2 %>% distinct(Entidad)
                           Entidad
1                   Aguascalientes
2                  Baja California
3              Baja California Sur
4                         Campeche
5             Coahuila de Zaragoza
6                           Colima
7                          Chiapas
8                        Chihuahua
9                 Ciudad de México
10                         Durango
11                      Guanajuato
12                        Guerrero
13                         Hidalgo
14                         Jalisco
15                          México
16             Michoacán de Ocampo
17                         Morelos
18                         Nayarit
19                      Nuevo León
20                          Oaxaca
21                          Puebla
22                       Querétaro
23                    Quintana Roo
24                 San Luis Potosí
25                         Sinaloa
26                          Sonora
27                         Tabasco
28                      Tamaulipas
29                        Tlaxcala
30 Veracruz de Ignacio de la Llave
31                         Yucatán
32                       Zacatecas

Por otro lado, el comando count cuenta el número de observaciones agrupadas por una variable.

mortalidad.2017.editada.v2 %>% count(Entidad)

Así se obtienen los datos que forman esta tabla:

Entidad n
Aguascalientes 6320
Baja California 20820
Baja California Sur 3984
Campeche 4524
Chiapas 26629
Chihuahua 24033
Ciudad de México 75648
Coahuila de Zaragoza 16715
Colima 4917
Durango 9256
Guanajuato 34832
Guerrero 19787
Hidalgo 15283
Jalisco 47430
Michoacán de Ocampo 26679
Morelos 12385
México 75170
Nayarit 6866
Nuevo León 27919
Oaxaca 24528
Puebla 37873
Querétaro 10692
Quintana Roo 6531
San Luis Potosí 16260
Sinaloa 16436
Sonora 17069
Tabasco 13384
Tamaulipas 20131
Tlaxcala 6408
Veracruz de Ignacio de la Llave 52047
Yucatán 13097
Zacatecas 9394

Podemos combinar los comandos de filter y count para, por ejemplo, contar la cantidad de registros de hombres:

mortalidad.2017.editada.v2 %>%
  filter(Sexo == "Hombres") %>%
  count(Entidad)
                Entidad     n
1        Aguascalientes  3469
2       Baja California 13318
3   Baja California Sur  2637
4              Campeche  2556
5               Chiapas 14530
6             Chihuahua 14195
7      Ciudad de México 39419
8  Coahuila de Zaragoza  9165
9                Colima  3087
10              Durango  5259
11           Guanajuato 19797
12             Guerrero 11667
13              Hidalgo  8298
14              Jalisco 26865
15  Michoacán de Ocampo 15291
16              Morelos  6753
17               México 41763
18              Nayarit  4068
19           Nuevo León 15649
20               Oaxaca 13023
21               Puebla 20325
22            Querétaro  5984
23         Quintana Roo  4034
24      San Luis Potosí  9050
25              Sinaloa 10023
 [ reached 'max' / getOption("max.print") -- omitted 7 rows ]

O bien los de mujeres:

mortalidad.2017.editada.v2 %>%
  filter(Sexo == "Hombres") %>%
  count(Entidad)
                Entidad     n
1        Aguascalientes  3469
2       Baja California 13318
3   Baja California Sur  2637
4              Campeche  2556
5               Chiapas 14530
6             Chihuahua 14195
7      Ciudad de México 39419
8  Coahuila de Zaragoza  9165
9                Colima  3087
10              Durango  5259
11           Guanajuato 19797
12             Guerrero 11667
13              Hidalgo  8298
14              Jalisco 26865
15  Michoacán de Ocampo 15291
16              Morelos  6753
17               México 41763
18              Nayarit  4068
19           Nuevo León 15649
20               Oaxaca 13023
21               Puebla 20325
22            Querétaro  5984
23         Quintana Roo  4034
24      San Luis Potosí  9050
25              Sinaloa 10023
 [ reached 'max' / getOption("max.print") -- omitted 7 rows ]

El comando group_by te permite generar una única tabla:

mortalidad.2017.editada.v2 %>%
  group_by(Sexo) %>%
  count(Entidad)
# A tibble: 96 × 3
# Groups:   Sexo [3]
   Sexo    Entidad                  n
   <chr>   <chr>                <int>
 1 Hombres Aguascalientes        3469
 2 Hombres Baja California      13318
 3 Hombres Baja California Sur   2637
 4 Hombres Campeche              2556
 5 Hombres Chiapas              14530
 6 Hombres Chihuahua            14195
 7 Hombres Ciudad de México     39419
 8 Hombres Coahuila de Zaragoza  9165
 9 Hombres Colima                3087
10 Hombres Durango               5259
# ℹ 86 more rows

Podemos agrupar por múltiples variables:

mortalidad.2017.editada.v2 %>%
  group_by(Sexo, Mes) %>%
  count(Entidad)
# A tibble: 989 × 4
# Groups:   Sexo, Mes [39]
   Sexo      Mes Entidad                  n
   <chr>   <int> <chr>                <int>
 1 Hombres     1 Aguascalientes         313
 2 Hombres     1 Baja California       1174
 3 Hombres     1 Baja California Sur    207
 4 Hombres     1 Campeche               211
 5 Hombres     1 Chiapas               1296
 6 Hombres     1 Chihuahua             1288
 7 Hombres     1 Ciudad de México      3639
 8 Hombres     1 Coahuila de Zaragoza   936
 9 Hombres     1 Colima                 286
10 Hombres     1 Durango                507
# ℹ 979 more rows

Finalmente, podemos utilizar el comando arrange para reordenar la base de mayor a menor (desc). Así, podemos analizar los estados con mayor cantidad de defunciones:

mortalidad.2017.editada.v2 %>%
  count(Entidad) %>%
  arrange(desc(n))
                           Entidad     n
1                 Ciudad de México 75648
2                           México 75170
3  Veracruz de Ignacio de la Llave 52047
4                          Jalisco 47430
5                           Puebla 37873
6                       Guanajuato 34832
7                       Nuevo León 27919
8              Michoacán de Ocampo 26679
9                          Chiapas 26629
10                          Oaxaca 24528
11                       Chihuahua 24033
12                 Baja California 20820
13                      Tamaulipas 20131
14                        Guerrero 19787
15                          Sonora 17069
16            Coahuila de Zaragoza 16715
17                         Sinaloa 16436
18                 San Luis Potosí 16260
19                         Hidalgo 15283
20                         Tabasco 13384
21                         Yucatán 13097
22                         Morelos 12385
23                       Querétaro 10692
24                       Zacatecas  9394
25                         Durango  9256
 [ reached 'max' / getOption("max.print") -- omitted 7 rows ]

10.1 Ejercicio

Responde las siguientes preguntas respecto a la mortalidad en México 2017:

  1. ¿Cuántas mujeres murieron en Aguascalientes?

  2. ¿Cuántos registros de hombres, mujeres y no especificado se tienen con Causa dada por "Contacto traumático con maquinaria agrícola en calles y carreteras"?

  3. ¿Cuál es el estado donde hubo mayores registros de defunciones por "Paniculitis, no especificada" ?

  4. Genera una gráfica como la siguiente (usando ggplot2) de mortalidad por Enfermedad renal hipertensiva con insuficiencia renal por Entidad y Sexo:

11 Ejemplo de análisis: Mortalidad por infarto del miocardio de 2010 a 2017.

Se desea hacer un análisis de la mortalidad por infarto del miocardio por estado de la república, sexo, año y mes. Para ello usaremos la función str_detect que detecta si en un conjunto de caracteres (string) está la palabra:

mortalidad.2017.editada.v2 %>%
  distinct(Causa) %>%
  filter(str_detect(Causa, "Infarto|infarto"))
                                                                                      Causa
1                                      Infarto agudo del miocardio, sin otra especificación
2                               Infarto transmural agudo del miocardio de la pared anterior
3                                                              Secuelas de infarto cerebral
4     Infarto cerebral debido a oclusión o estenosis no especificada de arterias cerebrales
5                                                         Infarto cerebral, no especificado
6                                  Infarto cerebral debido a embolia de arterias cerebrales
7                               Infarto transmural agudo del miocardio de la pared inferior
8                                Infarto cerebral debido a trombosis de arterias cerebrales
9                               Infarto subsecuente del miocardio, de parte no especificada
10                                   Infarto agudo transmural del miocardio de otros sitios
11                         Infarto transmural agudo del miocardio, de sitio no especificado
12                                                 Demencia vascular por infartos múltiples
13                              Infarto cerebral debido a embolia de arterias precerebrales
14                                                                Otros Infartos cerebrales
15                                                            Infarto isquémico del músculo
16                                   Infarto subsecuente del miocardio de la pared inferior
17                                                                         Infarto del bazo
18                                   Infarto subsecuente del miocardio de la pared anterior
19                            Infarto cerebral debido a trombosis de arterias precerebrales
20 Infarto cerebral debido a oclusión o estenosis no especificada de arterias precerebrales
21                                               Infarto subendocárdico agudo del miocardio
22                                                             Isquemia e infarto del riñón
23                                                                       Infarto del hígado
24                      Infarto cerebral debido a trombosis de venas cerebrales, no piógeno

donde el comando "Infarto|infarto" busca la palabra con mayúscula o con minúscula. Esto nos permite obtener las categorías que nos interesan, aquellas con infarto al miocardio:

causas.miocardio <- c(
  "Infarto agudo del miocardio, sin otra especificación",
  "Infarto transmural agudo del miocardio de la pared anterior",
  "Infarto transmural agudo del miocardio de la pared inferior",
  "Infarto subsecuente del miocardio, de parte no especificada",
  "Infarto agudo transmural del miocardio de otros sitios",
  "Infarto transmural agudo del miocardio, de sitio no especificado",
  "Infarto subsecuente del miocardio de la pared inferior",
  "Infarto subsecuente del miocardio de la pared anterior",
  "Infarto subendocárdico agudo del miocardio"
)

Finalmente, asociamos:

mortalidad.miocardio <- mortalidad.2017.editada.v2 %>%
  filter(Causa %in% causas.miocardio) %>%
  count(Sexo, Mes, Entidad)

El inicio de la base se ve así:

     Sexo Mes             Entidad   n
1 Hombres   1      Aguascalientes  41
2 Hombres   1     Baja California 123
3 Hombres   1 Baja California Sur  22
4 Hombres   1            Campeche  30
5 Hombres   1             Chiapas 143
6 Hombres   1           Chihuahua 165

Queremos repetir el mismo análisis para las bases de 2012 hasta 2017. Para ello resumiremos sólo los pasos necesarios para juntar las causas:

mi.base <- "conjunto_de_datos_defunciones_generales_2017.CSV"
# 1 Leemos la base
mortalidad.2017 <- read.csv(mi.base)

# 2 Elegimos sólo las variables que nos interesan
mortalidad.2017.editada <- mortalidad.2017 %>%
  select(c(
    "ent_regis", "sexo", "edad",
    "dia_ocurr", "mes_ocurr", "anio_ocur", "causa_def"
  ))

# Cambiamos los nombres de las variables
colnames(mortalidad.2017.editada) <- c(
  "Entidad", "Sexo", "Edad",
  "Día", "Mes", "Año", "Causa"
)

# 3 Una vez que leímos previamente las bases de sexo dic.sexo
#   las de estados, dic.lugar y las de causa, dic.causa las asociamos:

# SEXO
#-----------------------------------------------------
mortalidad.2017.editada.v2 <- merge(mortalidad.2017.editada, dic.sexo,
  by.x = "Sexo", by.y = "CVE",
  all.x = TRUE, all.y = FALSE
)

# Eliminamos la columna de sexo
mortalidad.2017.editada.v2 <- mortalidad.2017.editada.v2 %>%
  select(-c("Sexo"))

# Renombramos DESCRIP como Sexo
mortalidad.2017.editada.v2 <- mortalidad.2017.editada.v2 %>%
  rename("Sexo" = "DESCRIP")

# CAUSA
#-----------------------------------------------------
mortalidad.2017.editada.v2 <- merge(mortalidad.2017.editada.v2,
  dic.causa,
  by.x = "Causa",
  by.y = "CVE", all.x = TRUE,
  all.y = FALSE
)

# Eliminamos la columna de edad
mortalidad.2017.editada.v2 <- mortalidad.2017.editada.v2 %>%
  select(-c("Causa"))

# Renombramos DESCRIP como Sexo
mortalidad.2017.editada.v2 <- mortalidad.2017.editada.v2 %>%
  rename("Causa" = "DESCRIP")

# ENTIDAD
#-----------------------------------------------------
mortalidad.2017.editada.v2 <- merge(mortalidad.2017.editada.v2,
  dic.entidad,
  by.x = "Entidad",
  by.y = "cve_ent", all.x = TRUE,
  all.y = FALSE
)

# Eliminamos la columna de edad
mortalidad.2017.editada.v2 <- mortalidad.2017.editada.v2 %>%
  select(-c("Entidad"))

# Renombramos DESCRIP como Sexo
mortalidad.2017.editada.v2 <- mortalidad.2017.editada.v2 %>%
  rename("Entidad" = "nom_loc")

# 4 Filtramos
mortalidad.miocardio <- mortalidad.2017.editada.v2 %>%
  filter(Causa %in% causas.miocardio) %>%
  count(Sexo, Mes, Entidad)

# 5 Agregaré una columna a la base que se llame año con 2017
mortalidad.miocardio[, "Año"] <- 2017

# Renombraremos la columna n como defunciones
mortalidad.miocardio.2017 <- mortalidad.miocardio %>%
  rename("Defunciones" = "n")

Observa que el código correspondiente a Sexo, Causa y Entidad es prácticamente el mismo y sólo cambian pequeñas cosas. Lo mismo ocurrirá si queremos usar la base de 2016, tenemos que hacer copy-paste de lo que llevamos y cambiar sólo el año de la base:

mi.base <- "conjunto_de_datos_defunciones_generales_2016.CSV"
# 1 Leemos la base
mortalidad.2016 <- read.csv(mi.base)

# 2 Elegimos sólo las variables que nos interesan
mortalidad.2016.editada <- mortalidad.2016 %>%
  select(c(
    "ent_regis", "sexo", "edad",
    "dia_ocurr", "mes_ocurr", "anio_ocur", "causa_def"
  ))

# Cambiamos los nombres de las variables
colnames(mortalidad.2016.editada) <- c(
  "Entidad", "Sexo", "Edad",
  "Día", "Mes", "Año", "Causa"
)

# 3 Una vez que leímos previamente las bases de sexo dic.sexo
#   las de estados, dic.lugar y las de causa, dic.causa las asociamos:

# SEXO
#-----------------------------------------------------
mortalidad.2016.editada.v2 <- merge(mortalidad.2016.editada, dic.sexo,
  by.x = "Sexo", by.y = "CVE",
  all.x = TRUE, all.y = FALSE
)

# Eliminamos la columna de sexo
mortalidad.2016.editada.v2 <- mortalidad.2016.editada.v2 %>%
  select(-c("Sexo"))

# Renombramos DESCRIP como Sexo
mortalidad.2016.editada.v2 <- mortalidad.2016.editada.v2 %>%
  rename("Sexo" = "DESCRIP")

# CAUSA
#-----------------------------------------------------
mortalidad.2016.editada.v2 <- merge(mortalidad.2016.editada.v2,
  dic.causa,
  by.x = "Causa",
  by.y = "CVE", all.x = TRUE,
  all.y = FALSE
)

# Eliminamos la columna de edad
mortalidad.2016.editada.v2 <- mortalidad.2016.editada.v2 %>%
  select(-c("Causa"))

# Renombramos DESCRIP como Sexo
mortalidad.2016.editada.v2 <- mortalidad.2016.editada.v2 %>%
  rename("Causa" = "DESCRIP")

# ENTIDAD
#-----------------------------------------------------
mortalidad.2016.editada.v2 <- merge(mortalidad.2016.editada.v2,
  dic.entidad,
  by.x = "Entidad",
  by.y = "cve_ent", all.x = TRUE,
  all.y = FALSE
)

# Eliminamos la columna de edad
mortalidad.2016.editada.v2 <- mortalidad.2016.editada.v2 %>%
  select(-c("Entidad"))

# Renombramos DESCRIP como Sexo
mortalidad.2016.editada.v2 <- mortalidad.2016.editada.v2 %>%
  rename("Entidad" = "nom_loc")

# 4 Filtramos
mortalidad.miocardio <- mortalidad.2016.editada.v2 %>%
  filter(Causa %in% causas.miocardio) %>%
  count(Sexo, Mes, Entidad)

# 5 Agregaré una columna a la base que se llame año con 2016
mortalidad.miocardio[, "Año"] <- 2016

# Renombraremos la columna n como defunciones
mortalidad.miocardio.2016 <- mortalidad.miocardio %>%
  rename("Defunciones" = "n")

Hacer copy-paste de comandos es un error muy común cuando se está empezando a programar. ¡Imagínate si tuvieras que hacer la mortalidad desde 1990! Seguro nos vamos a equivocar. Peor aún, imagina que decidimos agregar localidad en las variables ¡tendríamos que modificar cada uno de los copy pastes!

Quienes nos dedicamos a programar somos muy flojos y para ello inventamos el concepto de función. Éste nos permitirá repetir el mismo proceso para diferentes datos.

12 Funciones en R

Una función la podemos pensar como un pedazo de código que transforma un poco de código en otra cosa.

Una función toma ciertos valores de input y regresa ciertos outputs

Por si te lo preguntabas, sí, también el diagrama lo hicimos con ggplot2 ;)

Por ejemplo la siguiente función toma como Input un número y le suma 5 (yo sé que es una función muy inútil pero vamos paso a paso):

# Defino mi función
suma.5 <- function(mi.numero) {
  return(mi.numero + 5)
}

# Pruebo mi función
suma.5(10)
[1] 15
suma.5(1)
[1] 6
suma.5("Pingüino")
Error in `mi.numero + 5`:
! argumento no-numérico para operador binario

La estructura básica de una función en R es como sigue: \[ \begin{aligned} \text{Nombre.de.la.function}& \leftarrow\textrm{function}(\overbrace{\textrm{Inputs}}^{\text{Lo que necesita para funcionar}})\{ \\ & \text{Código} \\ & \text{return}(\underbrace{\text{Output}}_{\textrm{Lo que resulta}}) \\ \} \end{aligned} \] Veamos otra función:

# Función que dice ¡Hola ----! donde ---- es el nommbre que se mete
mi.saludo <- function(nombre) {
  saludo <- paste0("¡Hola ", nombre, "!")
  return(saludo)
}

# Ejemplos
mi.saludo("Ana")
[1] "¡Hola Ana!"
mi.saludo("Jesús")
[1] "¡Hola Jesús!"

Una función puede tener múltiples parámetros, por ejemplo la función que resta un número a otro:

resta.numeros <- function(num.1, num.2) {
  mi.resta <- num.1 - num.2
  return(mi.resta)
}

# Restamos dos números
resta.numeros(10, 3)
[1] 7
# Observa cómo el orden importa
resta.numeros(3, 10)
[1] -7

En general las buenas prácticas de R te piden que utilices el formato roxygen2 para documentar la función ¡lo mejor es siempre poner qué hace tu función pues la idea es reciclarla cuantas veces sea necesaria!

resta.numeros <- function(num.1, num.2) {
  #' resta.numeros
  #'
  #' Función que calcula num.1 - num.2
  #' @param num.1 Número que se va a restar
  #' @param num.2 Número que se resta de num.1
  #' @return num.1 - num.2

  mi.resta <- num.1 - num.2
  return(mi.resta)
}

En este caso, quizá no tiene mucho sentido documentar la función. Pero cuando uno trabaja con proyectos más grandes (o con más personas) ¡es bastante importante saber qué hace una función!

Por último, una función también puede regresar múltiples valores. Para ello está el comando list. Por ejemplo, la función que regresa la media y desviación estándar de un vector:

media.y.varianza <- function(mi.vector) {
  #' media.y.varianza
  #'
  #' Función que calcula la media y desviación estándar de un vector
  #' @param mi.vector Un vector de R al cual calcular media y desviación
  #' @return mi.lista Lista de parámetros que contiene:
  #'           media    Media del vector
  #'           desv.est Desviación estándar del mismo

  # Calculamos la media
  media <- mean(mi.vector)

  # Calculamos la desviación estándar
  desv.est <- sd(mi.vector)

  return(list(promedio = media, desviacion = desv.est))
}

# Veamos un ejemplo:
un.vector <- c(0.27, -0.34, 0.11, -0.6, 0.82, -0.41)

# Podemos calcular ambas
media.y.varianza(un.vector)
$promedio
[1] -0.025

$desviacion
[1] 0.5286492
# Para acceder a un valor hay que usar $
media.y.varianza(un.vector)$promedio
[1] -0.025

donde mean es una función de R que calcula la media de un vector:

# Cremos un vector
x <- c(1, 0.5, 2, 0.6, 0.4, 0, 0.2)
mean(x)
[1] 0.6714286

y sd calcula su desviación estándar:

sd(x)
[1] 0.6651172

12.1 Ejercicios

  1. Construye una función que dada la altura (en metros) y peso (en kilogramos) de una persona, calcule su índice de masa corporal IMC. Recuerda que éste está dado por la fórmula: \[ \text{IMC} = \dfrac{\text{Peso}}{(\text{Altura})^2} \]
  2. Construye una función que se llame grafica.linea que dado una base de datos (data.frame) que contiene las variables x y y cree una gráfica de línea con ggplot de x contra y. Prueba que con los siguientes datos funcione como en los ejemplos:
# Primera base de datos
datos1 <- data.frame(x = 1:10, y = 1:10)
grafica.linea(datos1)

# Segunda base de datos
x <- seq(0, 10 * pi, length.out = 250)
datos2 <- data.frame(x = x, y = sin(x))
grafica.linea(datos2)

  1. Utiliza las funciones de cos(), sin() y log() para crear una única función que dado un número regrese su coseno, su seno y su logaritmo natural. El ‘output’ de la función debe ser algo así:
# Así debe de correr:
ejercicio.3(12)
$coseno
[1] 0.843854

$seno
[1] -0.5365729

$logaritmo
[1] 2.484907

12.2 De vuelta al análisis de bases

Armados con el concepto de función podemos abstraer lo que tienen en común las secciones de Sexo, Entidad y Causa del apartado anterior:

# SEXO
#-----------------------------------------------------
mortalidad.2016.editada.v2 <- merge(mortalidad.2016.editada, dic.sexo,
  by.x = "Sexo", by.y = "CVE",
  all.x = TRUE, all.y = FALSE
)

# Eliminamos la columna de sexo
mortalidad.2016.editada.v2 <- mortalidad.2016.editada.v2 %>%
  select(-c("Sexo"))

# Renombramos DESCRIP como Sexo
mortalidad.2016.editada.v2 <- mortalidad.2016.editada.v2 %>%
  rename("Sexo" = "DESCRIP")

# CAUSA
#-----------------------------------------------------
mortalidad.2016.editada.v2 <- merge(mortalidad.2016.editada.v2,
  dic.causa,
  by.x = "Causa",
  by.y = "CVE", all.x = TRUE,
  all.y = FALSE
)

# Eliminamos la columna de edad
mortalidad.2016.editada.v2 <- mortalidad.2016.editada.v2 %>%
  select(-c("Causa"))

# Renombramos DESCRIP como Sexo
mortalidad.2016.editada.v2 <- mortalidad.2016.editada.v2 %>%
  rename("Causa" = "DESCRIP")

# ENTIDAD
#-----------------------------------------------------
mortalidad.2016.editada.v2 <- merge(mortalidad.2016.editada.v2,
  dic.entidad,
  by.x = "Entidad",
  by.y = "cve_ent", all.x = TRUE,
  all.y = FALSE
)

# Eliminamos la columna de edad
mortalidad.2016.editada.v2 <- mortalidad.2016.editada.v2 %>%
  select(-c("Entidad"))

# Renombramos DESCRIP como Sexo
mortalidad.2016.editada.v2 <- mortalidad.2016.editada.v2 %>%
  rename("Entidad" = "nom_loc")

Nota que en todos los casos aparecen los mismos tres comandos. Podemos abstraerlos para generar una función:

indicadores.mortalidad <- function(base.mortalidad, base.indicadores,
                                   indicador.x, indicador.y, nombre.y) {
  # SEXO
  #-----------------------------------------------------
  nueva.base <- merge(base.mortalidad, base.indicadores,
    by.x = indicador.x, by.y = indicador.y,
    all.x = TRUE, all.y = FALSE
  )

  # Eliminamos la columna de sexo
  nueva.base <- nueva.base %>% select(-c(!!indicador.x))

  # Renombramos DESCRIP como Sexo
  nueva.base <- nueva.base %>% rename(!!indicador.x := nombre.y)

  return(nueva.base)
}

Veamos que funciona con lo que habíamos hecho para 2016:

# 1 Leemos la base
mortalidad.2016 <- read.csv(mi.base)

# 2 Elegimos sólo las variables que nos interesan
mortalidad.2016.editada <- mortalidad.2016 %>%
  select(c(
    "ent_regis", "sexo", "edad",
    "dia_ocurr", "mes_ocurr", "anio_ocur", "causa_def"
  ))

# Cambiamos los nombres de las variables
colnames(mortalidad.2016.editada) <- c(
  "Entidad", "Sexo", "Edad",
  "Día", "Mes", "Año", "Causa"
)

# Aquí cambiamos lo de sexo
mortalidad.2016.editada.v2 <-
  indicadores.mortalidad(
    mortalidad.2016.editada, dic.sexo,
    "Sexo", "CVE", "DESCRIP"
  )

# Aquí cambiamos lo de causa
mortalidad.2016.editada.v2 <-
  indicadores.mortalidad(
    mortalidad.2016.editada.v2, dic.causa,
    "Causa", "CVE", "DESCRIP"
  )

# Aquí cambiamos lo de estado
mortalidad.2016.editada.v2 <-
  indicadores.mortalidad(
    mortalidad.2016.editada.v2, dic.entidad,
    "Entidad", "cve_ent", "nom_loc"
  )

# 4 Filtramos
mortalidad.miocardio <- mortalidad.2016.editada.v2 %>%
  filter(Causa %in% causas.miocardio) %>%
  count(Sexo, Mes, Entidad)

# 5 Agregaré una columna a la base que se llame año con 2016
mortalidad.miocardio[, "Año"] <- 2016

# Renombraremos la columna n como defunciones
mortalidad.miocardio.2016 <- mortalidad.miocardio %>%
  rename("Defunciones" = "n")

¿Será que podemos abstraer aún más esta función? ¡Por supuesto! Vamos a crear una función que nos permita leer las bases de datos para cada uno de los años de tal manera que podamos hacer el análisis mucho más rápido.

analisis.mortalidad <- function(base, anio, causas) {
  # 1 Leemos la base
  mortalidad <- read.csv(base)

  # 2 Elegimos sólo las variables que nos interesan
  mortalidad <- mortalidad %>%
    select(c(
      "ent_regis", "sexo", "edad",
      "dia_ocurr", "mes_ocurr", "anio_ocur", "causa_def"
    ))

  # Cambiamos los nombres de las variables
  colnames(mortalidad) <- c(
    "Entidad", "Sexo", "Edad",
    "Día", "Mes", "Año", "Causa"
  )

  # Aquí cambiamos lo de sexo
  mortalidad <-
    indicadores.mortalidad(
      mortalidad, dic.sexo,
      "Sexo", "CVE", "DESCRIP"
    )

  # Aquí cambiamos lo de causa
  mortalidad <-
    indicadores.mortalidad(
      mortalidad, dic.causa,
      "Causa", "CVE", "DESCRIP"
    )

  # Aquí cambiamos lo de estado
  mortalidad <-
    indicadores.mortalidad(
      mortalidad, dic.entidad,
      "Entidad", "cve_ent", "nom_loc"
    )

  # 4 Filtramos
  mortalidad.causas <- mortalidad %>%
    filter(Causa %in% !!causas) %>%
    count(Sexo, Mes, Entidad, Día)

  # 5 Agregaré una columna a la base que se llame año con 2016
  mortalidad.causas[, "Año"] <- anio

  # Renombraremos la columna n como defunciones
  mortalidad.causas <- mortalidad.causas %>%
    rename("Defunciones" = "n")

  return(mortalidad.causas)
}
datos.2016 <- "conjunto_de_datos_defunciones_generales_2016.CSV"

Veamos que sí sirve:

base.2016 <- analisis.mortalidad(datos.2016, 2016, causas.miocardio)

Podemos, fácilmente, hacer los análisis para el resto de los años usando estas funciones:

datos.2017 <- "conjunto_de_datos_defunciones_generales_2017.CSV"
datos.2015 <- "conjunto_de_datos_defunciones_generales_2015.CSV"
datos.2014 <- "conjunto_de_datos_defunciones_generales_2014.CSV"
datos.2013 <- "conjunto_de_datos_defunciones_generales_2013.CSV"
datos.2012 <- "conjunto_de_datos_defunciones_generales_2012.CSV"
base.2017 <- analisis.mortalidad(
  datos.2017, 2017,
  causas.miocardio
)
base.2015 <- analisis.mortalidad(
  datos.2015, 2015,
  causas.miocardio
)
base.2014 <- analisis.mortalidad(
  datos.2014, 2014,
  causas.miocardio
)
base.2013 <- analisis.mortalidad(
  datos.2013, 2013,
  causas.miocardio
)
base.2012 <- analisis.mortalidad(
  datos.2012, 2012,
  causas.miocardio
)

Finalmente, podemos juntar todos los datos en una sola base que contenga todos los años usando bind_rows:

mortalidad <- base.2017 %>%
  bind_rows(base.2016) %>%
  bind_rows(base.2015) %>%
  bind_rows(base.2014) %>%
  bind_rows(base.2013) %>%
  bind_rows(base.2012)

Sobre esta base, podemos hacer mas análisis, por ejemplo, analizar las muertes totales por año:

mortalidad %>%
  group_by(Año) %>%
  summarise(Defunciones = sum(Defunciones))

O bien graficar la evolución de las muertes totales por año, mes y sexo. Para ello usaremos pegamos la fecha y usamos as.Date:

# Eliminamos los registros que no tienen fecha
mortalidad.con.fecha <- mortalidad %>%
  filter(Mes < 13 & Día < 32)

# Hacemos que R sepa que estamos hablando de una fecha
mortalidad.con.fecha$Fecha <- as.Date(paste(mortalidad.con.fecha$Año,
  mortalidad.con.fecha$Mes,
  mortalidad.con.fecha$Día,
  sep = "-"
))

# Eliminamos aquellos que quedaron sin fecha
mortalidad.con.fecha <- mortalidad.con.fecha %>%
  filter(!is.na(Fecha))

# Creamos la base agrupada por fecha y sexo
mortalidad.plot <- mortalidad.con.fecha %>%
  group_by(Sexo, Fecha) %>%
  summarise(Defunciones = sum(Defunciones))

# Graficamos
ggplot(mortalidad.plot) +
  geom_point(aes(x = Fecha, y = Defunciones, color = Sexo)) +
  theme_linedraw() +
  theme(
    plot.background = element_rect(fill = "#fffff8"),
    panel.background = element_rect(fill = "#fffff8"),
    legend.background = element_rect(fill = "#fffff8")
  ) +
  ggtitle("Defunciones por infarto al miocardio en México (INEGI)")

O ajustar un modelo Loess que nos describa la mortalidad por mes y año gráficamente:

# Eliminaremos a las personas de `Sexo no especificado` pues no
# es fácil describirlas (pocas mediciones relativamente):

# Creamos la base agrupada por fecha y sexo sin no especificado
mortalidad.plot <- mortalidad.plot %>%
  filter(Sexo != "Sexo no especificado")

# Agregamos el loess
ggplot(mortalidad.plot) +
  geom_point(aes(x = Fecha, y = Defunciones, color = Sexo),
    alpha = 0.1
  ) +
  geom_smooth(aes(x = Fecha, y = Defunciones, color = Sexo),
    method = "loess", span = 0.1,
    method.args = list(degree = 1)
  ) +
  ggtitle("Defunciones de infarto miocardio ajustadas") +
  theme_linedraw() +
  theme(
    plot.background = element_rect(fill = "#fffff8"),
    panel.background = element_rect(fill = "#fffff8"),
    legend.background = element_rect(fill = "#fffff8")
  )

Finalmente, podemos utilizar la función summarise para obtener estadísticas descriptivas como pueden ser la media mean, varianza var, cuantiles quantile, mínimo min, máximo max, mediana median de defunciones por año y sexo:

# Generamos la base de datos
resumen.mortalidad <-
  mortalidad.con.fecha %>%
  group_by(Año, Sexo) %>%
  summarise(
    Promedio = mean(Defunciones),
    Varianza = var(Defunciones),
    Cuantil75 = quantile(Defunciones, 0.75),
    Mínimo = min(Defunciones),
    Máximo = max(Defunciones),
    Mediana = median(Defunciones)
  )

Así obtenemos la siguiente tabla:

Año Sexo Promedio Varianza Cuantil75 Mínimo Máximo Mediana
2012 Hombres 3.786345 9.992030 5 1 25 3
2012 Mujeres 3.301106 8.975015 4 1 28 2
2012 Sexo no especificado 1.000000 0.000000 1 1 1 1
2013 Hombres 4.058740 11.505108 5 1 27 3
2013 Mujeres 3.460832 9.530942 4 1 24 2
2013 Sexo no especificado 1.000000 0.000000 1 1 1 1
2014 Hombres 4.205994 12.412800 5 1 28 3
2014 Mujeres 3.574806 10.398984 4 1 26 3
2014 Sexo no especificado 1.000000 NA 1 1 1 1
2015 Hombres 4.432604 13.583240 6 1 27 3
2015 Mujeres 3.763781 11.999110 5 1 28 3
2015 Sexo no especificado 1.000000 0.000000 1 1 1 1
2016 Hombres 4.857295 17.568506 6 1 32 4
2016 Mujeres 4.095724 14.836622 5 1 30 3
2016 Sexo no especificado 1.000000 0.000000 1 1 1 1
2017 Hombres 4.998373 17.508660 7 1 30 4
2017 Mujeres 4.249974 14.918720 5 1 30 3
2017 Sexo no especificado 1.000000 0.000000 1 1 1 1

Finalmente guardamos la base de datos ya sea en un RDS (formato de base de datos de R) ó en un csv para leerlo con nuestro programa favorito (Excel, Stata, SPSS, etc).

# Lee con readRDS
saveRDS(mortalidad.con.fecha,
  file = "MortalidadMiocardio.rds"
)

# Lee con Excel
write.csv(mortalidad.con.fecha,
  file = "MortalidadMiocardio.csv"
)

12.3 Ejercicio

Describe la mortalidad por tus causas favoritas (NO enfermedad miocardio, ej diabetes, cólera, tumor) en México durante los años 2012 a 2017 y realiza una gráfica de la evolución de la enfermedad por sexo y por estado. ¿Qué puedes concluir? ¿Cuál es el mínimo mensual por sexo?¿Y la varianza por estado? ¿Cómo se ven los cuartiles quartiles por año? ¿En qué entidad federativa hubo la mayor cantidad de defunciones por dicha causa en el periodo 2013-2016?