# No olvides instalarla con install.packages si aún
# no lo has hecho
library("tidyverse")7 Limpieza de bases y estadística descriptiva
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:
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
- Lee el archivo
diversidad_dieta_adultos_251116.dtael 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 comandoread_dtade la libreríahaveno bien enRStudio > Import Dataset > From STATA.
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")- 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 columnas totales de la base.
- Obtén el valor de
folio_selque está en la fila1234y después encuentra en qué fila vuelve a aparecer ese mismo valor. - Regresa todas las mediciones de la penúltima fila (la que está diez lugares antes de la última).
- Regresa la 5a columna.
- Obtén el nombre de la penúltima columna.
- Obtén la entrada en la columna
5y fila14.
- 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:
- ¿Por qué da error?
# Primer error
base.inventada[, 200]Error in `[.data.frame`:
! columnas no definidas seleccionadas
- ¿Por qué da
NA?
# NA
base.inventada[1000, ] Tiempo Enfermo
NA NA NA
- ¿Por qué dice esto?
# Primer error
base.inventada[0, 0]data frame with 0 columns and 0 rows
- ¿Por qué da
NULL?
# NULL
base.inventada[2, c("tiempo")]NULL
- 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:
¿Cuántas mujeres murieron en Aguascalientes?
¿Cuántos registros de hombres, mujeres y no especificado se tienen con
Causadada por"Contacto traumático con maquinaria agrícola en calles y carreteras"?¿Cuál es el estado donde hubo mayores registros de defunciones por
"Paniculitis, no especificada"?Genera una gráfica como la siguiente (usando
ggplot2) de mortalidad porEnfermedad renal hipertensiva con insuficiencia renalporEntidadySexo:

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.

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
- 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} \] - Construye una función que se llame
grafica.lineaque dado una base de datos (data.frame) que contiene las variablesxyycree una gráfica de línea conggplotdexcontray. 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)
- Utiliza las funciones de
cos(),sin()ylog()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?