Esta publicación tiene dos objetivos, uno personal y otro general. El objetivo personal es poder tener un apunte en limpio sobre el cálculo del indicador de rezago habitacional con base en el Censo de Población y Vivienda 2020 utilizando R, pues no suelo usar esta base a menudo para mis propios análisis. El segundo objetivo, el general, es simplemente compartirlo con todo aquel que guste y tampoco esté familiarizado con su uso.
No asumo que mi código sea el más eficiente o esté libre de errores, así que cualquier corrección o comentario házmelo saber por este medio o a través de mi twitter ecodiegoale.
Recomiendo leer antes la documentación de la Comisión Nacional de Vivienda en este enlace.
Además, nunca está de más revisar stackoverflow, github, rpubs, entre otros.
Aviso: No soy experto en vivienda ni nada parecido.
En este blog se hará uso de tidyverse principalmente,
pues únicamente voy a replicar la metodología descrita por
CONAVI en este enlace.
Voy a calcular el número de hogares con rezago habitacional en México
utilizando únicamente el Censo de Población y Vivienda 2020 de
INEGI.
rm(list = ls())#para borrar los objetos guardados de sesiones anteriores
options(scipen=999) #para desactivar la notación científica
library(tidyverse)
library(MetBrewer)
library(rnaturalearth)
Voy a seguir paso a paso la documentación. Así que vamos con las consideraciones previas.
“El instrumento utilizado en el cálculo del Rezago habitacional es el Cuestionario ampliado del Censo de Población y Vivienda 2020. Para realizar la cuantificación del Rezago habitacional se consideran únicamente 34,892,977 viviendas particulares habitadas. En el análisis se omiten las 94,938 viviendas que pertenecen a las clases de vivienda particular “Local no construido para habitación”, “Vivienda móvil” y “Refugio” debido a que son hogares censales con necesidad de vivienda. Para ello se utiliza el código que se le asigna en la base de datos a la variable CLAVIVP” (CONAVI, p. 5).
Primero vamos a descargar el Cuestionario ampliado del Censo de Población y Vivienda 2020.
.csv. Posteriormente se descargará un archivo comprimido
tipo zip.Viviendas00.csv.base <- read.csv("Viviendas00.csv")
También recomiendo descargar el archivo
Descripción de la base de datos.
El cual es un libro de excel que luce así.
glimpse(base$CLAVIVP) #para ver el tipo de variable
## int [1:4016627] 1 1 1 1 1 1 1 1 1 1 ...
unique(base$CLAVIVP) #para conocer los valores únicos
## [1] 1 2 7 99 4 5 3 9 6 8
Como vemos, es una variable que contiene diez números enteros
diferentes. Siguiendo la metodología, tenemos que excluir a las clases
de vivienda particular “Local no construido para habitación”, “Vivienda
móvil” y “Refugio”. De acuerdo con el archivo
Descripción de la base de datos estas clases de hogares son
identificados con el número 7, 8 y 9 respectivamente. Así que vamos a
filtrar nuestra base para poder excluirlos.
excluded_values <- c(7,8,9)
df <- base%>%
filter(!CLAVIVP %in% excluded_values)
El proceso de cálculo es el siguiente: se identifican las viviendas por sus materiales en paredes, en techo y pisos para generar la variable de materiales deteriorados. Después se calculan los residentes por cuarto en cada vivienda y se clasifican las que presentan hacinamiento. Luego, se identifican las viviendas que no cuentan con excusado. Por último, se genera una variable que clasifica cada vivienda según su condición de rezago habitacional y se aplican los factores de expansión de la base de datos para conocer la estimación poblacional. (CONAVI, p. 7).
Recomiendo ver el nombre de cada una de las variables dentro de la base.
names(df)
## [1] "ENT" "MUN" "LOC50K" "ID_VIV"
## [5] "COBERTURA" "ESTRATO" "UPM" "FACTOR"
## [9] "CLAVIVP" "PAREDES" "TECHOS" "PISOS"
## [13] "COCINA" "CUADORM" "TOTCUART" "LUG_COC"
## [17] "COMBUSTIBLE" "ESTUFA" "ELECTRICIDAD" "FOCOS"
## [21] "FOCOS_AHORRA" "AGUA_ENTUBADA" "ABA_AGUA_ENTU" "ABA_AGUA_NO_ENTU"
## [25] "TINACO" "CISTERNA" "BOMBA_AGUA" "REGADERA"
## [29] "BOILER" "CALENTADOR_SOLAR" "AIRE_ACON" "PANEL_SOLAR"
## [33] "SERSAN" "CONAGUA" "USOEXC" "DRENAJE"
## [37] "SEPARACION1" "SEPARACION2" "SEPARACION3" "SEPARACION4"
## [41] "DESTINO_BAS" "REFRIGERADOR" "LAVADORA" "HORNO"
## [45] "AUTOPROP" "MOTOCICLETA" "BICICLETA" "RADIO"
## [49] "TELEVISOR" "COMPUTADORA" "TELEFONO" "CELULAR"
## [53] "INTERNET" "SERV_TV_PAGA" "SERV_PEL_PAGA" "CON_VJUEGOS"
## [57] "TENENCIA" "ESCRITURAS" "FORMA_ADQUI" "FINANCIAMIENTO1"
## [61] "FINANCIAMIENTO2" "FINANCIAMIENTO3" "DEUDA" "NUMPERS"
## [65] "DUE1_NUM" "DUE2_NUM" "MCONMIG" "MNUMPERS"
## [69] "INGR_PEROTROPAIS" "INGR_PERDENTPAIS" "INGR_AYUGOB" "INGR_JUBPEN"
## [73] "ALIMENTACION" "ALIM_ADL1" "ALIM_ADL2" "ING_ALIM_ADL1"
## [77] "ING_ALIM_ADL2" "ING_ALIM_ADL3" "TIPOHOG" "INGTRHOG"
## [81] "JEFE_SEXO" "JEFE_EDAD" "TAMLOC"
De acuerdo con la metodología, ciertos materiales son considerados
como deteriorados. El código de la imagen a continuación es el mismo que
el del archivo Descripción de la base de datos, por lo que
podemos proceder sin preocupación.
Necesitamos generar tres variables nuevas. La primera debe contener las paredes construidas con materiales deteriorados, la segunda los techos y la tercera debe contener ambas.
Paredes deterioradas:
\[ \text{pared_det} = \begin{cases} \text{0} & \text{si (paredes = 3)} \cup \text{(paredes} \geq 6) \\ \text{1} & \text{si (paredes = 1)} \cup \text{(paredes = 2)} \cup \text{(paredes = 4)} \cup \text{(paredes = 5)} \cup \text{(paredes = 9)} \end{cases} \]
Techos deteriorados:
\[ \text{techo_det} = \begin{cases} \text{0} & \text{si (techos = 3)} \cup \text{(techos = 4}) \cup \text{(techos = 5}) \cup \text{(techos} \geq 7) \\ \text{1} & \text{si (techos} \leq 2) \cup \text{(techos = 6)} \cup \text{(techos = 99)} \end{cases} \]
Por lo tanto, la variable de materiales deteriorados
toma un valor de 1 cuando pared_det, o
techo_det tienen valores de 1:
\[ \text{mat_det} = \begin{cases} \text{0} & \text{si (pared_det = 0)} \cap \text{(techo_det = 0}) \\ \text{1} & \text{si (pared_det = 1)} \cup \text{(techo_det = 1}) \end{cases} \]
Dadas las condiciones anteriores vamos a usar el operador
%in% y la función if_else().
El operador %in% en
R, especialmente en el contexto deltidyverse, se utiliza para verificar si los elementos de un vector están presentes en otro vector. Puedes pensar en él como una forma de realizar una búsqueda o coincidencia de elementos.
La función
if_else()enRy, en particular, en el contexto deltidyverse, es una herramienta poderosa para realizar transformaciones condicionales en conjuntos de datos. Permite asignar valores en función de una condición especificada.
#if_else(condición, valor_si_verdadero, valor_si_falso)
| Operaciones booleanas | |
|---|---|
| y & !x | quita a x de la selección y solo deja a y |
| x & y | intersección de x y y |
| x & !y | quita a y de la selección y solo deja a x |
| x | y | selecciona todos los x y y |
| x or (x, y) | selecciona todo menos la intersección de x y y |
Para pared_det. Si en la variable
PAREDES se encuentran los valores 1, 2, 4, 5 y 9, vamos a
generar una nueva variable (pared_det) cuyo valor sea 1, de
lo contrario su valor será 0.
Para techo_det. Si en la variable
TECHOS se encuentran los valores 1, 2, 6 y 99, vamos a
generar una nueva variable (techo_det) cuyo valor sea 1, de
lo contrario su valor será 0.
Para mat_det. Si en la unión de
pared_det y techo_det cuando ambas son iguales
a 0 -cuando los techos y paredes no están construidas con materiales
deteriorados- la nueva variable mat_det tomará valor de 0,
es decir, no hay ningún material deteriorado, de lo contrario su valor
será 1.
df <- df %>%
mutate(pared_det = if_else
(PAREDES %in% c(1, 2, 4, 5, 9), 1, 0))%>%
mutate(techo_det = if_else
(TECHOS %in% c(1, 2, 6, 99), 1, 0))%>%
mutate(mat_det =
if_else(pared_det == 0 & techo_det == 0, 0, 1))
Necesitamos generar cuatro variables nuevas. La primera debe contener las paredes construidas con materiales regulares según las definiciones de la imagen anterior, la segunda los techos, la tercera los pisos y la cuarta las tres anteriores.
Paredes regulares:
\[ \text{pared_reg} = \begin{cases} \text{0} & \text{si (paredes} \leq 2) \cup \text{(paredes = 4)} \cup \text{(paredes = 5)} \cup \text{(paredes} \geq 7) \\ \text{1} & \text{si (paredes = 3)} \cup \text{(paredes = 6)} \end{cases} \]
Techos regulares:
\[ \text{techo_reg} = \begin{cases} \text{0} & \text{si (techos} \leq 2) \cup \text{(techos = 5)} \cup \text{(techos = 6)} \cup \text{(techos = 8)} \cup \text{(techos} \geq 10) \\ \text{1} & \text{si (techos = 3)} \cup \text{(techos = 4)} \cup \text{(techos = 7)} \cup \text{(techos = 9)} \end{cases} \]
Pisos regulares:
\[ \text{piso_reg} = \begin{cases} \text{0} & \text{si (pisos} > 1) \\ \text{1} & \text{si (pisos = 1)} \cup \text{(pisos = 9)} \end{cases} \]
Por lo tanto, la variable de materiales regulares
toma valor de 1 cuando pared_reg, techo_reg
o piso_reg tienen valores de 1:
\[ \text{mat_reg} = \begin{cases} \text{0} & \text{si (pared_reg = 0)} \cap \text{(techo_reg = 0}) \cap \text{(piso_reg = 0}) \\ \text{1} & \text{si (pared_reg = 1)} \cup \text{(techo_reg = 1}) \cup \text{(piso_reg = 1}) \end{cases} \]
Para pared_reg. Si en la variable
PAREDES se encuentran los valores 3 y 6, vamos a generar
una nueva variable (pared_reg) cuyo valor sea 1, de lo
contrario su valor será 0.
Para techo_reg. Si en la variable
TECHOS se encuentran los valores 3, 4, 7 y 9, vamos a
generar una nueva variable (techo_reg) cuyo valor sea 1, de
lo contrario su valor será 0.
Para piso_reg. Si en la variable PISOS
se encuentran los valores 1 y 9, vamos a generar una nueva variable
(piso_reg) cuyo valor sea 1, de lo contrario su valor será
0.
Para mat_reg. Si en la intersección de
pared_reg, techo_reg y piso_reg
cuando las tres son iguales a 0 -cuando los techos, paredes y pisos no
están construidas con materiales regulares- la nueva variable
mat_reg tomará valor de 0, es decir, no hay ningún material
regular, de lo contrario su valor será 1.
df <- df %>%
mutate(pared_reg = if_else
(PAREDES %in% c(3, 6), 1, 0))%>%
mutate(techo_reg = if_else
(TECHOS %in% c(3, 4, 7, 9), 1, 0))%>%
mutate(piso_reg = if_else
(PISOS %in% c(1,9), 1, 0))%>%
mutate(mat_reg =
if_else(pared_reg == 0 & techo_reg == 0 & piso_reg == 0, 0, 1))
Para conocer el promedio de residentes por cuarto se utilizan las
variables TOTCUART y NUMPERS.
\(\text{res_cuarto}= \frac{NUMPERS}{TOTCUART}\)
df <- df %>%
mutate(
res_cuarto = NUMPERS/TOTCUART
)
Partiendo del criterio mencionado, se crea la variable
hacin para asignar con el valor de 1 cuando el hogar se
encuentra en estas condiciones y 0 cuando no lo está:
\[ \text{hacin} = \begin{cases} \text{0} & \text{si (res_cuarto}\leq2.5)\\ \text{1} & \text{si (res_cuarto > 2.5)} \cup \text{(totcuart = 99}) \end{cases} \]
df <- df %>%
mutate(hacin = if_else
(res_cuarto > 2.5 | TOTCUART == 99, 1, 0))
El segundo elemento considerado en la precariedad de espacios es no contar con servicio sanitario.
Para identificar la carencia de servicio sanitario, se genera la
variable excu y se le asignan los valores de 0 y 1 según
los siguientes criterios:
\[ \text{excu} = \begin{cases} \text{0} & \text{si (sersan}<3)\\ \text{1} & \text{si (sersan = 1)} \cup \text{(sersan = 9}) \end{cases} \]
df <- df %>%
mutate(excu = if_else
(SERSAN < 3, 0, 1))
Para determinar la precariedad de espacios en la vivienda, se genera
la variable prec_esp y se le asignan los valores de 0 y 1
de acuerdo con los siguientes criterios:
\[ \text{prec_esp} = \begin{cases} \text{0} & \text{si (hacin}=0) \cap \text{si (excu}=0)\\ \text{1} & \text{si (hacin = 1)} \cup \text{(excu = 1}) \end{cases} \]
df <- df %>%
mutate(prec_esp =
if_else(
hacin == 0 & excu ==0, 0, 1))
“Para calcular las viviendas en rezago habitacional (
rezago) se consideran las variables de materiales deteriorados y la precariedad de espacios para identificar las viviendas con estas características. Se considera que un hogar tiene rezago habitacional cuandomat_det,mat_regyprec_esptiene valores de 1. Por el contrario, se considera que no tiene rezago habitacional cuando ninguno de sus materiales está deteriorado, ni cuenta con materiales considerados como regulares y no tiene precariedad de espacios.” (CONAVI, p. 11).
\[ \text{rezago} = \begin{cases} \text{0} & \text{si (mat_det}=0) \cap \text{(mat_reg}=0) \cap \text{(prec_esp}=0)\\ \text{1} & \text{si (mat_det}=1) \cup \text{(mat_reg}=1) \cup \text{(prec_esp}=1) \end{cases} \]
df <- df %>%
mutate(rezago =
if_else(
mat_det == 1 | mat_reg == 1 | prec_esp == 1, 1, 0))
Es hora de comprobar que hemos replicado de manera correcta la metodología propuesta por CONAVI.
De acuerdo con la imagen anterior, el cuestionario ampliado contempla 34,892,977 viviendas.
sum(df$FACTOR)
## [1] 34892977
Se aplican los factores de expansión de la base de datos para conocer la estimación de hogares.
Primero, agrupamos conforme a la variable rezago.
Esta variable solo tiene dos opciones: 0 para aquellos hogares que no se
encuentran en rezago y 1 para aquellos que sí.
Segundo, sumamos todos los hogares que valen 0 según
rezago, y sumamos todos los hogares que valen 1.
df %>%
group_by(rezago) %>%
summarize(cantidad = sum(FACTOR))
## # A tibble: 2 × 2
## rezago cantidad
## <dbl> <int>
## 1 0 26388553
## 2 1 8504424
Ahora, agrupamos por entidad federativa y multiplicamos por los factores de expansión. De esta manera, replicamos el Cuadro 7 del documento.
rezago_df <- df%>%
select(ENT, FACTOR, rezago)%>%
group_by(ENT, rezago)%>%
summarise(total_hogares = sum(FACTOR))
rezago_final <- rezago_df %>%
group_by(ENT) %>%
summarise(
total_de_hogares = sum(total_hogares),
hogares_sin_rezago = sum(total_hogares * (rezago == 0)),
hogares_con_rezago = sum(total_hogares * (rezago == 1)),
tasa_rezago = round((hogares_con_rezago/total_de_hogares)*100,2),
tasa_sin_rezago = round((hogares_sin_rezago/total_de_hogares)*100, 2)
)%>%
arrange(desc(tasa_rezago))
Primero voy a crear un dataframe con el nombre de cada entidad federativa y su respectivo número.
nombres <- c("Aguascalientes","Baja California","Baja California Sur","Campeche","Coahuila","Colima","Chiapas","Chihuahua","Ciudad de México","Durango","Guanajuato","Guerrero","Hidalgo","Jalisco","México","Michoacán","Morelos","Nayarit","Nuevo León","Oaxaca","Puebla","Querétaro","Quintana Roo","San Luis Potosí","Sinaloa","Sonora","Tabasco","Tamaulipas","Tlaxcala","Veracruz","Yucatán","Zacatecas")
ENT <- seq(1,32, by = 1)
nombres_df <- data.frame(ENT, nombres)
Luego, usamos este nuevo dataframe para agregar los nombres al
dataframe que hicimos anteriormente, rezago_final, para eso
usaremos la función left_join(), así tomaremos la variable
ENT de nombres_df y ENT
de rezago_final como criterio de búsqueda y nos pondrá el
nombre del estado que viene en nombres_df, es como si
usáramos un =BUSCARV en excel.
rezago_final <- rezago_final%>%
left_join(nombres_df, by = c("ENT" = "ENT"))
Finalmente, veremos la tabla:
rezago_final %>%
select(nombres,tasa_rezago)
## # A tibble: 32 × 2
## nombres tasa_rezago
## <chr> <dbl>
## 1 Chiapas 68.2
## 2 Tabasco 59.4
## 3 Oaxaca 53.2
## 4 Guerrero 51.5
## 5 Veracruz 47.5
## 6 Campeche 44.1
## 7 Baja California 42.0
## 8 Chihuahua 37.1
## 9 Michoacán 27.6
## 10 Sonora 27.0
## # … with 22 more rows
Usaremos la librería rnaturalearth.
# Carga los datos geoespaciales de los estados de México
mexico <- ne_states(country = "Mexico", returnclass = "sf")
# Cambia "Distrito Federal" a "Ciudad de México" en la columna 'name'
mexico$name <- ifelse(mexico$name == "Distrito Federal", "Ciudad de México", mexico$name)
Luego, usamos la función left_join() para anexar al
dataframe mexico que creamos anteriormente los valores
de la tasa de rezago habitacional por entidad federativa.
merged_data <- mexico %>%
left_join(rezago_final, by = c("name" = "nombres"))
Finalmente, graficamos.
plot.map<-ggplot(data = merged_data) +
geom_sf(aes(fill = tasa_rezago)) +
scale_fill_gradientn(colors = met.brewer("Greek"), trans = "reverse")+
labs() +
labs(title="Rezago Habitacional 2020 por entidad federativa",
fill = " %",
caption="Fuente: Censo de Población y Vivienda 2020, INEGI. | @ecodiegoale")+
theme_void()+
theme(plot.caption=element_text(hjust=0.5,size=9),
plot.title=element_text(hjust=0.5, size=14,face="bold"))
plot.map