1) Carga de datos
# Cargar el CSV
datos_csv <- read_csv("S5_ASA_estadisticasPasajeros.csv")
## Rows: 216 Columns: 6
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (3): Codigo IATA, Descripcion, Estado
## dbl (3): Anio mes, Pasajeros nacionales, Pasajeros internacionales
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# Limpiar nombres de columnas y asignar a 'datos'
datos <- datos_csv %>% janitor::clean_names()
# Vista de las primeras filas
head(datos)
## # A tibble: 6 × 6
## anio_mes codigo_iata descripcion estado pasajeros_nacionales
## <dbl> <chr> <chr> <chr> <dbl>
## 1 201501 CEN Ciudad Obregon Sonora 17149
## 2 201501 CLQ Colima Colima 8486
## 3 201501 CME Ciudad del Carmen Campeche 56079
## 4 201501 CPE Campeche Campeche 13264
## 5 201501 CTM Chetumal Quintana Roo 13153
## 6 201501 CVM Ciudad Victoria Tamaulipas 4695
## # ℹ 1 more variable: pasajeros_internacionales <dbl>
2) Verificación de estructura y tipos
# Comprobaciones básicas
if (!exists("datos")) stop("El objeto 'datos' no existe. Asegúrate de haber corrido el bloque de carga.")
if (!is.data.frame(datos)) stop("'datos' no es un data frame")
if (ncol(datos) == 0) stop("'datos' no tiene columnas")
# Arreglar nombres vacíos o duplicados
names(datos) <- make.names(names(datos), unique = TRUE)
# Estructura dataframe
str(datos)
## spc_tbl_ [216 × 6] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
## $ anio_mes : num [1:216] 201501 201501 201501 201501 201501 ...
## $ codigo_iata : chr [1:216] "CEN" "CLQ" "CME" "CPE" ...
## $ descripcion : chr [1:216] "Ciudad Obregon" "Colima" "Ciudad del Carmen" "Campeche" ...
## $ estado : chr [1:216] "Sonora" "Colima" "Campeche" "Campeche" ...
## $ pasajeros_nacionales : num [1:216] 17149 8486 56079 13264 13153 ...
## $ pasajeros_internacionales: num [1:216] 721 124 3126 215 0 ...
## - attr(*, "spec")=
## .. cols(
## .. `Anio mes` = col_double(),
## .. `Codigo IATA` = col_character(),
## .. Descripcion = col_character(),
## .. Estado = col_character(),
## .. `Pasajeros nacionales` = col_double(),
## .. `Pasajeros internacionales` = col_double()
## .. )
## - attr(*, "problems")=<externalptr>
# Resumen de NA y tipos
na_resumen <- data.frame(
variable = names(datos),
tipo = sapply(datos, function(x) class(x)[1]),
na = sapply(datos, function(x) sum(is.na(x))),
na_prop = sapply(datos, function(x) mean(is.na(x))),
check.names = FALSE
)
knitr::kable(na_resumen, caption = "NA por variable")
NA por variable
| anio_mes |
anio_mes |
numeric |
0 |
0 |
| codigo_iata |
codigo_iata |
character |
0 |
0 |
| descripcion |
descripcion |
character |
0 |
0 |
| estado |
estado |
character |
0 |
0 |
| pasajeros_nacionales |
pasajeros_nacionales |
numeric |
0 |
0 |
| pasajeros_internacionales |
pasajeros_internacionales |
numeric |
0 |
0 |
3) Resúmenes numéricos
numericas <- names(datos)[vapply(datos, is.numeric, TRUE)]
if (length(numericas) == 0) {
cat("**No se detectaron variables numéricas.**\n")
} else {
resumen_num <- datos %>%
dplyr::summarise(
dplyr::across(
dplyr::all_of(numericas),
list(
min = ~ min(.x, na.rm = TRUE),
q1 = ~ quantile(.x, 0.25, na.rm = TRUE),
media = ~ mean(.x, na.rm = TRUE),
mediana = ~ median(.x, na.rm = TRUE),
q3 = ~ quantile(.x, 0.75, na.rm = TRUE),
max = ~ max(.x, na.rm = TRUE),
na = ~ sum(is.na(.x))
),
.names = "{.col}_{.fn}"
)
)
knitr::kable(resumen_num, caption = "Resumen numérico por variable")
}
Resumen numérico por variable
| 201501 |
201503.8 |
201506.5 |
201506.5 |
201509.2 |
201512 |
0 |
63 |
1198.5 |
10608.42 |
7947 |
14883.75 |
56418 |
0 |
0 |
7 |
818.2454 |
107 |
584 |
7042 |
0 |
4) Tablas de frecuencia (categóricas)
categoricas <- names(datos)[map_lgl(datos, ~ is.character(.x) || is.factor(.x))]
if (length(categoricas) == 0) {
cat("**No se detectaron variables categóricas.**\n")
} else {
top_cats <- head(categoricas, 8)
for (v in top_cats) {
cat("\n## Frecuencia de:", v, "\n")
print(datos %>% count(!!sym(v), sort = TRUE) %>% mutate(prop = n/sum(n)) %>% kable())
}
}
##
## ## Frecuencia de: codigo_iata
##
##
## |codigo_iata | n| prop|
## |:-----------|--:|---------:|
## |CEN | 12| 0.0555556|
## |CLQ | 12| 0.0555556|
## |CME | 12| 0.0555556|
## |CPE | 12| 0.0555556|
## |CTM | 12| 0.0555556|
## |CVM | 12| 0.0555556|
## |GYM | 12| 0.0555556|
## |LTO | 12| 0.0555556|
## |MAM | 12| 0.0555556|
## |NLD | 12| 0.0555556|
## |NOG | 12| 0.0555556|
## |PAZ | 12| 0.0555556|
## |PBC | 12| 0.0555556|
## |PXM | 12| 0.0555556|
## |TCN | 12| 0.0555556|
## |TPQ | 12| 0.0555556|
## |TSL | 12| 0.0555556|
## |UPN | 12| 0.0555556|
##
## ## Frecuencia de: descripcion
##
##
## |descripcion | n| prop|
## |:-----------------|--:|---------:|
## |Campeche | 12| 0.0555556|
## |Chetumal | 12| 0.0555556|
## |Ciudad Obregon | 12| 0.0555556|
## |Ciudad Victoria | 12| 0.0555556|
## |Ciudad del Carmen | 12| 0.0555556|
## |Colima | 12| 0.0555556|
## |Guaymas | 12| 0.0555556|
## |Loreto | 12| 0.0555556|
## |Matamoros | 12| 0.0555556|
## |Nogales | 12| 0.0555556|
## |Nuevo Laredo | 12| 0.0555556|
## |Poza Rica | 12| 0.0555556|
## |Puebla | 12| 0.0555556|
## |Puerto Escondido | 12| 0.0555556|
## |Tamuin | 12| 0.0555556|
## |Tehuacan | 12| 0.0555556|
## |Tepic | 12| 0.0555556|
## |Uruapan | 12| 0.0555556|
##
## ## Frecuencia de: estado
##
##
## |estado | n| prop|
## |:--------------------|--:|---------:|
## |Sonora | 36| 0.1666667|
## |Tamaulipas | 36| 0.1666667|
## |Campeche | 24| 0.1111111|
## |Puebla | 24| 0.1111111|
## |Baja California Sur | 12| 0.0555556|
## |Colima | 12| 0.0555556|
## |Michoacan | 12| 0.0555556|
## |Nayarit | 12| 0.0555556|
## |Oaxaca | 12| 0.0555556|
## |Quintana Roo | 12| 0.0555556|
## |San Luis Potosi | 12| 0.0555556|
## |Veracruz | 12| 0.0555556|
5) Agregaciones interesantes
safe_pick <- function(x) {
x <- unique(x[!is.na(x) & nzchar(x)])
if (length(x) >= 1) x[1] else NULL
}
nms <- names(datos)
# Candidatas por patrón
col_estado_cand <- nms[grepl("estado|entidad", nms, ignore.case = TRUE)]
col_aeropuerto_cand <- nms[grepl("aerop|aeropuerto|airport|terminal", nms, ignore.case = TRUE)]
col_pasajeros_cand <- nms[grepl("pasaj|passenger|pasenger|total", nms, ignore.case = TRUE)]
col_estado <- safe_pick(col_estado_cand)
col_aeropuerto <- safe_pick(col_aeropuerto_cand)
col_pasajeros <- safe_pick(col_pasajeros_cand)
# Intentar construir "total_pasajeros" si no se detectó
cols_nac <- nms[grepl("nac", nms, ignore.case = TRUE)]
# Evitar confundir "int" con "intervalo" o similares
cols_int_all <- nms[grepl("int", nms, ignore.case = TRUE)]
cols_int <- setdiff(cols_int_all, nms[grepl("interval", nms, ignore.case = TRUE)])
if (is.null(col_pasajeros) && length(cols_nac) >= 1 && length(cols_int) >= 1) {
col_pasajeros <- "total_pasajeros_tmp"
datos <- datos %>%
dplyr::mutate(
total_pasajeros_tmp = dplyr::coalesce(.data[[cols_nac[1]]], 0) + dplyr::coalesce(.data[[cols_int[1]]], 0)
)
}
list(
detectado_estado = col_estado,
detectado_aeropuerto = col_aeropuerto,
detectado_pasajeros = col_pasajeros
)
## $detectado_estado
## [1] "estado"
##
## $detectado_aeropuerto
## NULL
##
## $detectado_pasajeros
## [1] "pasajeros_nacionales"
if (!is.null(col_estado) && !is.null(col_pasajeros)) {
agg_estado <- datos %>% group_by(!!sym(col_estado)) %>%
summarise(total_pasajeros = sum(!!sym(col_pasajeros), na.rm = TRUE), .groups = "drop") %>%
arrange(desc(total_pasajeros))
kable(head(agg_estado, 20), caption = "Top estados por total de pasajeros")
}
Top estados por total de pasajeros
| Campeche |
769864 |
| Puebla |
267567 |
| Sonora |
253788 |
| Tamaulipas |
243126 |
| Oaxaca |
181706 |
| Quintana Roo |
179259 |
| Nayarit |
113043 |
| Colima |
112656 |
| Michoacan |
95635 |
| Veracruz |
60575 |
| Baja California Sur |
12602 |
| San Luis Potosi |
1598 |
if (!is.null(col_aeropuerto) && !is.null(col_pasajeros)) {
agg_aer <- datos %>% group_by(!!sym(col_aeropuerto)) %>%
summarise(total_pasajeros = sum(!!sym(col_pasajeros), na.rm = TRUE), .groups = "drop") %>%
arrange(desc(total_pasajeros))
kable(head(agg_aer, 20), caption = "Top aeropuertos por total de pasajeros")
}
6) Gráficos descriptivos
6.1 Histograma
col_nac <- names(datos) %>% keep(~ str_detect(.x, regex("nac", ignore_case = TRUE))) %>% first()
col_int <- names(datos) %>% keep(~ str_detect(.x, regex("int", ignore_case = TRUE))) %>% first()
col_hist <- coalesce(col_nac, col_int, if (length(numericas)>0) numericas[1] else NA_character_)
if (!is.na(col_hist)) {
ggplot(datos, aes(x = .data[[col_hist]])) +
geom_histogram(bins = 30, fill = "skyblue") +
labs(x = col_hist, y = "Frecuencia", title = paste("Histograma de", col_hist))
}

6.2 Barras por estado o aeropuerto
if (!is.null(col_estado) && !is.null(col_pasajeros)) {
top_est <- datos %>% group_by(!!sym(col_estado)) %>% summarise(total = sum(!!sym(col_pasajeros), na.rm=TRUE), .groups="drop") %>% arrange(desc(total)) %>% slice_head(n=15)
ggplot(top_est, aes(x = reorder(.data[[col_estado]], total), y = total)) +
geom_col(fill = "steelblue") +
coord_flip() +
labs(x = "Estado", y = "Total de pasajeros", title = "Top 15 estados por total de pasajeros")
}

6.3 Boxplot por mes
if ("mes" %in% names(datos) && !is.null(col_pasajeros)) {
ggplot(datos, aes(x = as.factor(mes), y = .data[[col_pasajeros]])) +
geom_boxplot(fill = "orange", alpha = 0.6) +
labs(x = "Mes", y = "Pasajeros", title = "Dispersión de pasajeros por mes")
}
6.4 Numérica vs categórica
if (length(numericas) >= 1 && length(categoricas) >= 1) {
vnum <- numericas[1]
vcat <- categoricas[1]
datos %>% group_by(.data[[vcat]]) %>% summarise(prom = mean(.data[[vnum]], na.rm=TRUE), .groups="drop") %>%
slice_max(order_by = prom, n = 20) %>%
ggplot(aes(x = reorder(.data[[vcat]], prom), y = prom)) +
geom_col(fill = "purple") +
coord_flip() +
labs(x = vcat, y = paste("Promedio de", vnum), title = paste("Promedio de", vnum, "por", vcat))
}

6.5 Numérica vs numérica
if (length(numericas) >= 2) {
v1 <- numericas[1]; v2 <- numericas[2]
ggplot(datos, aes(x = .data[[v1]], y = .data[[v2]])) +
geom_point(alpha = 0.6, color = "darkgreen") +
geom_smooth(method = "lm", se = FALSE, color = "red") +
labs(x = v1, y = v2, title = paste("Relación entre", v1, "y", v2))
}
## `geom_smooth()` using formula = 'y ~ x'

7) Conclusión
- El histograma revela la asimetría típica del tráfico aéreo.
- Las barras muestran que el mayor tráfico se concentra en los
principales aeropuertos.
- El boxplot por mes sugiere estacionalidad marcada.
- Las relaciones entre variables permiten explorar correlaciones y
comportamientos atípicos.