Examen de Manipulación y visualización de datos en R
La base cuenta con las variables: folioviv, foliohog, numrem, FVH_numrem, Entidad_cod, Entidad,Zona, parentesco, sexo_cod, edad, ingresos provenientes de las bases población e ingreso. (Puedeconsultar el catalogo para entender qué hace y es cada variable).
1.Base de datos y librerías
library(readxl)
datos_enigh_examen <- read_excel("C:/Users/alani/Downloads/datos_enigh_examen.xlsx")
View(datos_enigh_examen)
library(tidyverse)
## Warning: package 'tidyverse' was built under R version 4.5.1
## Warning: package 'ggplot2' was built under R version 4.5.2
## Warning: package 'tibble' was built under R version 4.5.1
## Warning: package 'tidyr' was built under R version 4.5.2
## Warning: package 'readr' was built under R version 4.5.2
## Warning: package 'purrr' was built under R version 4.5.2
## Warning: package 'dplyr' was built under R version 4.5.1
## Warning: package 'forcats' was built under R version 4.5.2
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr 1.1.4 ✔ readr 2.1.5
## ✔ forcats 1.0.1 ✔ stringr 1.6.0
## ✔ ggplot2 4.0.0 ✔ tibble 3.3.0
## ✔ lubridate 1.9.4 ✔ tidyr 1.3.1
## ✔ purrr 1.1.0
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(ggplot2)
library(dplyr)
Ver la structura de datos
str(datos_enigh_examen)
## tibble [194,510 × 11] (S3: tbl_df/tbl/data.frame)
## $ folioviv : num [1:194510] 1e+08 1e+08 1e+08 1e+08 1e+08 ...
## $ foliohog : num [1:194510] 1 1 1 1 1 1 1 1 1 1 ...
## $ numren : num [1:194510] 1 2 1 3 1 2 1 1 1 1 ...
## $ FVH_numrem : chr [1:194510] "10001360511" "10001360512" "10001360611" "10001360613" ...
## $ Entidad_cod: num [1:194510] 1 1 1 1 1 1 1 1 1 1 ...
## $ Entidad : chr [1:194510] "Aguascalientes" "Aguascalientes" "Aguascalientes" "Aguascalientes" ...
## $ Zona : chr [1:194510] "Centro" "Centro" "Centro" "Centro" ...
## $ parentesco : num [1:194510] 101 301 101 301 101 201 101 101 101 101 ...
## $ sexo_cod : chr [1:194510] "Mujer" "Mujer" "Hombre" "Hombre" ...
## $ edad : num [1:194510] 48 17 46 17 26 26 29 63 33 60 ...
## $ ingreso : num [1:194510] 6295 5410 21639 1574 23607 ...
glimpse(datos_enigh_examen)
## Rows: 194,510
## Columns: 11
## $ folioviv <dbl> 100013605, 100013605, 100013606, 100013606, 100017801, 100…
## $ foliohog <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1…
## $ numren <dbl> 1, 2, 1, 3, 1, 2, 1, 1, 1, 1, 3, 1, 2, 1, 2, 1, 3, 1, 2, 4…
## $ FVH_numrem <chr> "10001360511", "10001360512", "10001360611", "10001360613"…
## $ Entidad_cod <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1…
## $ Entidad <chr> "Aguascalientes", "Aguascalientes", "Aguascalientes", "Agu…
## $ Zona <chr> "Centro", "Centro", "Centro", "Centro", "Centro", "Centro"…
## $ parentesco <dbl> 101, 301, 101, 301, 101, 201, 101, 101, 101, 101, 301, 101…
## $ sexo_cod <chr> "Mujer", "Mujer", "Hombre", "Hombre", "Hombre", "Mujer", "…
## $ edad <dbl> 48, 17, 46, 17, 26, 26, 29, 63, 33, 60, 30, 76, 73, 74, 68…
## $ ingreso <dbl> 6295.08, 5409.83, 21639.34, 1573.77, 23606.55, 983.60, 678…
class(datos_enigh_examen)
## [1] "tbl_df" "tbl" "data.frame"
head(datos_enigh_examen)
## # A tibble: 6 × 11
## folioviv foliohog numren FVH_numrem Entidad_cod Entidad Zona parentesco
## <dbl> <dbl> <dbl> <chr> <dbl> <chr> <chr> <dbl>
## 1 100013605 1 1 10001360511 1 Aguascalie… Cent… 101
## 2 100013605 1 2 10001360512 1 Aguascalie… Cent… 301
## 3 100013606 1 1 10001360611 1 Aguascalie… Cent… 101
## 4 100013606 1 3 10001360613 1 Aguascalie… Cent… 301
## 5 100017801 1 1 10001780111 1 Aguascalie… Cent… 101
## 6 100017801 1 2 10001780112 1 Aguascalie… Cent… 201
## # ℹ 3 more variables: sexo_cod <chr>, edad <dbl>, ingreso <dbl>
tail(datos_enigh_examen)
## # A tibble: 6 × 11
## folioviv foliohog numren FVH_numrem Entidad_cod Entidad Zona parentesco
## <dbl> <dbl> <dbl> <chr> <dbl> <chr> <chr> <dbl>
## 1 3260770717 1 1 326077071711 32 Zacatecas Cent… 101
## 2 3260770717 1 3 326077071713 32 Zacatecas Cent… 301
## 3 3260770717 1 4 326077071714 32 Zacatecas Cent… 301
## 4 3260770718 1 1 326077071811 32 Zacatecas Cent… 101
## 5 3260770718 1 2 326077071812 32 Zacatecas Cent… 301
## 6 3260770718 1 3 326077071813 32 Zacatecas Cent… 301
## # ℹ 3 more variables: sexo_cod <chr>, edad <dbl>, ingreso <dbl>
2.Realice un análisis descriptivo de la variable ingreso trimestral.
summary(datos_enigh_examen$ingreso)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 5.000e-01 2.374e+03 8.609e+03 1.378e+04 1.790e+04 1.069e+07
Ahora calculamos las medidas de tendencia central y dispersión
ingreso_stats <- datos_enigh_examen %>%
summarise(
Observaciones = n(),
Media = mean(ingreso),
Mediana = median(ingreso),
Desviacion_Estandar = sd(ingreso),
Minimo = min(ingreso),
Maximo = max(ingreso),
Q1 = quantile(ingreso, 0.25),
Q3 = quantile(ingreso, 0.75),
IQR = IQR(ingreso),
CV = (sd(ingreso) / mean(ingreso)) * 100
)
print(ingreso_stats)
## # A tibble: 1 × 10
## Observaciones Media Mediana Desviacion_Estandar Minimo Maximo Q1 Q3
## <int> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 194510 13785. 8609. 35525. 0.48 10688918. 2374. 17902.
## # ℹ 2 more variables: IQR <dbl>, CV <dbl>
Se presenta un histograma me permite visualizar la forma de la distribución para ver si es simétrica o sesgada. Y complementa las medidas anteriores.
ggplot(datos_enigh_examen, aes(x = ingreso)) +
geom_histogram(bins = 50, fill = "steelblue", color = "white", alpha = 0.7) +
labs(title = "Distribución del Ingreso Trimestral - ENIGH",
subtitle = paste("N =", format(nrow(datos_enigh_examen), big.mark = ","), "observaciones"),
x = "Ingreso Trimestral",
y = "Frecuencia") +
theme_minimal()
Ahora se presenta un boxplot me ayuda a identificar valores atípicos y
entender la dispersión a través de los cuartiles. Muestra claramente la
mediana y la caja representa el 50% central de los datos:
ggplot(datos_enigh_examen, aes(y = ingreso)) +
geom_boxplot(fill = "lightblue", alpha = 0.7) +
labs(title = "Boxplot del Ingreso Trimestral",
y = "Ingreso Trimestral") +
theme_minimal() +
scale_y_continuous(labels = scales::comma)
Use el siguiente filtro específico porque quiero analizar la población con ingresos medios-bajos. El primer cuartil representa el 25% más pobre, y al tomar valores mayores a este pero limitando a 30,000, me enfoco en la clase media baja:
Q1 <- quantile(datos_enigh_examen$ingreso, 0.25)
cat("\nPrimer cuartil (Q1):", Q1, "\n")
##
## Primer cuartil (Q1): 2373.62
datos_filtrados <- datos_enigh_examen %>%
filter(ingreso > Q1 & ingreso <= 30000)
4.Puede realizar una selección (SELECT) de sus variables con respecto al análisis que va a realizar, asícomo utilizar group_by o cualquier otro verbo que hayamos visto en clase o tengan en sus diapositivas.
A continuación, seleccioné estas variables porque son relevantes para analizar diferencias demográficas y socioeconómicas. Transformé la edad en grupos categóricos para facilitar el análisis. También categoricé el parentesco para entender mejor la estructura familiar. Estas transformaciones hacen los datos más interpretables:
analisis_completo <- datos_filtrados %>%
select(folioviv, foliohog, numren, FVH_numrem, Entidad_cod, Entidad, Zona,
parentesco, sexo_cod, edad, ingreso) %>%
mutate(
sexo = sexo_cod,
grupo_edad = case_when(
edad < 18 ~ "Menor 18",
edad < 25 ~ "18-24",
edad < 35 ~ "25-34",
edad < 45 ~ "35-44",
edad < 55 ~ "45-54",
edad < 65 ~ "55-64",
TRUE ~ "65+"
),
tipo_parentesco = case_when(
parentesco == 101 ~ "Jefe/a de hogar",
parentesco == 201 ~ "Cónyuge/Pareja",
parentesco == 301 ~ "Hijo/a",
parentesco == 401 ~ "Yerno/nuera",
parentesco == 501 ~ "Nieto/a",
parentesco == 601 ~ "Padre/madre",
parentesco == 701 ~ "Suegro/a",
parentesco == 801 ~ "Hermano/a",
parentesco == 901 ~ "Cuñado/a",
parentesco >= 1000 ~ "Otro familiar/No familiar",
TRUE ~ "Otro"
),
zona_simplificada = case_when(
Zona == "Centro" ~ "Urbana",
Zona == "Rural" ~ "Rural",
TRUE ~ Zona
)
)
Y ahora las rectifico:
table(analisis_completo$tipo_parentesco)
##
## Cónyuge/Pareja Hijo/a Jefe/a de hogar Nieto/a Otro
## 21595 32829 57976 640 12185
## Padre/madre
## 1535
table(analisis_completo$zona_simplificada)
##
## Norte Sur Urbana
## 42673 24943 59144
table(analisis_completo$grupo_edad)
##
## 18-24 25-34 35-44 45-54 55-64 65+ Menor 18
## 18037 25271 22957 20371 13880 18681 7563
5.Utilice las métricas, visualizaciones y comandos que considere necesarios y útiles.
ingreso_entidad <- analisis_completo %>%
group_by(Entidad) %>%
summarise(
n = n(),
ingreso_promedio = mean(ingreso),
ingreso_mediano = median(ingreso),
desviacion = sd(ingreso),
error_estandar = desviacion / sqrt(n)
) %>%
arrange(desc(ingreso_promedio))
print(ingreso_entidad, n = 32)
## # A tibble: 32 × 6
## Entidad n ingreso_promedio ingreso_mediano desviacion error_estandar
## <chr> <int> <dbl> <dbl> <dbl> <dbl>
## 1 Baja Califo… 5668 14978. 15344. 7904. 105.
## 2 Nuevo León 4874 14232. 14087. 7953. 114.
## 3 Coahuila 5913 13976. 13891. 7636. 99.3
## 4 Jalisco 4181 13880. 13279. 7563. 117.
## 5 Chihuahua 6445 13799. 14087. 7560. 94.2
## 6 Aguascalien… 4326 13545. 13055. 7575. 115.
## 7 Querétaro 5442 13503. 12984. 7542. 102.
## 8 Baja Califo… 3873 13475. 12892. 7863. 126.
## 9 CDMX 4105 13298. 11868. 7638. 119.
## 10 Colima 5005 13028. 11868. 7687. 109.
## 11 Sinaloa 5110 12933. 11739. 7792. 109.
## 12 Sonora 3334 12907. 11803. 7506. 130.
## 13 Tamaulipas 3101 12721. 11803. 7303. 131.
## 14 Guanajuato 5186 12619. 11803. 7215. 100.
## 15 México 5223 12396. 11739. 7332. 101.
## 16 Durango 4355 12221. 11318. 7286. 110.
## 17 Michoacán 2926 12128. 10681. 7454. 138.
## 18 Nayarit 2869 12080. 10623. 7479. 140.
## 19 San Luis Po… 3522 11801. 10328. 7511. 127.
## 20 Morelos 3551 11624. 10467. 7200. 121.
## 21 Quintana Roo 2868 11575. 10027. 7477. 140.
## 22 Campeche 3061 11459. 9890. 7353. 133.
## 23 Zacatecas 3456 11455. 10328. 7265. 124.
## 24 Hidalgo 3187 11393. 9978. 7278. 129.
## 25 Tabasco 2620 11346. 9709. 7304. 143.
## 26 Tlaxcala 3247 11239. 10174. 6954. 122.
## 27 Puebla 2918 10850. 9391. 6970. 129.
## 28 Yucatán 3705 10775. 9391. 6838. 112.
## 29 Oaxaca 3067 10370. 8100. 7400. 134.
## 30 Veracruz 3434 10238. 8790. 6697. 114.
## 31 Guerrero 3245 10100. 8071. 7059. 124.
## 32 Chiapas 2943 9316. 7337. 6559. 121.
Gráfico de ingresos por Entidad (Top 15) Este análisis cruzado me permite identificar brechas de género en diferentes contextos geográficos (urbano/rural), lo que puede revelar patrones de desigualdad.
top_entidades <- ingreso_entidad %>%
arrange(desc(ingreso_promedio)) %>%
head(15)
ggplot(top_entidades, aes(x = reorder(Entidad, ingreso_promedio), y = ingreso_promedio)) +
geom_col(fill = "skyblue") +
geom_errorbar(aes(ymin = ingreso_promedio - error_estandar,
ymax = ingreso_promedio + error_estandar),
width = 0.2) +
coord_flip() +
labs(title = "Top 15 Entidades por Ingreso Promedio Trimestral",
subtitle = "Filtro: Q1 < ingreso ≤ 30,000",
x = "Entidad",
y = "Ingreso Promedio") +
theme_minimal()
B) Análisis por Zona y Sexo
ingreso_zona_sexo <- analisis_completo %>%
group_by(zona_simplificada, sexo) %>%
summarise(
n = n(),
ingreso_promedio = mean(ingreso),
ingreso_mediano = median(ingreso),
desviacion = sd(ingreso),
error_estandar = desviacion / sqrt(n)
) %>%
arrange(zona_simplificada, desc(ingreso_promedio))
## `summarise()` has grouped output by 'zona_simplificada'. You can override using
## the `.groups` argument.
print(ingreso_zona_sexo)
## # A tibble: 6 × 7
## # Groups: zona_simplificada [3]
## zona_simplificada sexo n ingreso_promedio ingreso_mediano desviacion
## <chr> <chr> <int> <dbl> <dbl> <dbl>
## 1 Norte Hombre 24196 14820. 14754. 7692.
## 2 Norte Mujer 18477 11973. 10623. 7433.
## 3 Sur Hombre 14671 11392. 9836. 7122.
## 4 Sur Mujer 10272 9535. 7239. 6953.
## 5 Urbana Hombre 33620 13657. 13207. 7450.
## 6 Urbana Mujer 25524 10890. 8951. 7163.
## # ℹ 1 more variable: error_estandar <dbl>
Gráfico de ingresos por Zona y Sexo:
ggplot(ingreso_zona_sexo, aes(x = zona_simplificada, y = ingreso_promedio, fill = sexo)) +
geom_col(position = "dodge") +
geom_errorbar(aes(ymin = ingreso_promedio - error_estandar,
ymax = ingreso_promedio + error_estandar),
position = position_dodge(0.9), width = 0.2) +
labs(title = "Ingreso Promedio por Zona y Sexo",
x = "Zona",
y = "Ingreso Promedio",
fill = "Sexo") +
theme_minimal()
C) Análisis por Grupo de Edad:
ingreso_edad <- analisis_completo %>%
group_by(grupo_edad) %>%
summarise(
n = n(),
ingreso_promedio = mean(ingreso),
ingreso_mediano = median(ingreso),
desviacion = sd(ingreso)
) %>%
mutate(grupo_edad = factor(grupo_edad,
levels = c("Menor 18", "18-24", "25-34", "35-44", "45-54", "55-64", "65+")))
print(ingreso_edad)
## # A tibble: 7 × 5
## grupo_edad n ingreso_promedio ingreso_mediano desviacion
## <fct> <int> <dbl> <dbl> <dbl>
## 1 18-24 18037 11987. 11739. 6779.
## 2 25-34 25271 14558. 14234. 7520.
## 3 35-44 22957 14512. 14164. 7561.
## 4 45-54 20371 13875. 13292. 7588.
## 5 55-64 13880 12510. 11262. 7466.
## 6 65+ 18681 8479. 6457. 6280.
## 7 Menor 18 7563 6623. 4721. 4647.
Gráfico de ingresos por grupo de edad:
ggplot(ingreso_edad, aes(x = grupo_edad, y = ingreso_promedio)) +
geom_col(fill = "lightgreen") +
labs(title = "Ingreso Promedio por Grupo de Edad",
x = "Grupo de Edad",
y = "Ingreso Promedio") +
theme_minimal()
D)Análisis por Tipo de Parentesco:
ingreso_parentesco <- analisis_completo %>%
group_by(tipo_parentesco) %>%
summarise(
n = n(),
ingreso_promedio = mean(ingreso),
ingreso_mediano = median(ingreso)
) %>%
arrange(desc(ingreso_promedio))
print(ingreso_parentesco)
## # A tibble: 6 × 4
## tipo_parentesco n ingreso_promedio ingreso_mediano
## <chr> <int> <dbl> <dbl>
## 1 Jefe/a de hogar 57976 13523. 12717.
## 2 Nieto/a 640 12977. 11803.
## 3 Hijo/a 32829 12114. 11446.
## 4 Cónyuge/Pareja 21595 11391. 9664.
## 5 Otro 12185 11063. 9391.
## 6 Padre/madre 1535 7305. 5283.
Gráfico de ingresos por parentesco:
ggplot(ingreso_parentesco, aes(x = reorder(tipo_parentesco, ingreso_promedio), y = ingreso_promedio)) +
geom_col(fill = "orange", alpha = 0.7) +
coord_flip() +
labs(title = "Ingreso Promedio por Tipo de Parentesco",
x = "Tipo de Parentesco",
y = "Ingreso Promedio") +
theme_minimal()
6. Análisis adicional (Correlación entre edad e ingreso):
correlacion <- cor(analisis_completo$edad, analisis_completo$ingreso, use = "complete.obs")
Gráfico de dispersión edad vs ingreso:
ggplot(analisis_completo, aes(x = edad, y = ingreso)) +
geom_point(alpha = 0.1, color = "blue") +
geom_smooth(method = "lm", color = "red") +
labs(title = "Relación entre Edad e Ingreso Trimestral",
subtitle = paste("Correlación:", round(correlacion, 3), "| N =", format(nrow(analisis_completo), big.mark = ",")),
x = "Edad",
y = "Ingreso Trimestral") +
theme_minimal()
## `geom_smooth()` using formula = 'y ~ x'