Siguiendo la metodología de la Guía 1.2 / Recursos 1.2 / Código 1.2 del curso, en este documento se realiza el análisis de al menos dos variables cualitativas y dos variables cuantitativas de la base de datos seleccionada en la Actividad 112, apoyado en tablas de frecuencia e indicadores estadísticos (centro, dispersión y forma).
La base de datos corresponde al open-data del Ministerio de Agricultura y Desarrollo Rural: “Evaluación Bovinos — Departamento de Bolívar”, con el inventario bovino por municipio, discriminado por edad y sexo, para los años 2018, 2019 y 2020.
| Campo | Descripción |
|---|---|
| Tema / Dominio | Agricultura y desarrollo rural — Inventario bovino |
| Fuente | Datos Abiertos Colombia — Ministerio de Agricultura y Desarrollo Rural |
| Cobertura | 46 municipios del departamento de Bolívar |
| Periodo | 2018, 2019 y 2020 (panel municipio-año) |
| Unidad de observación | Un municipio, en un año determinado |
| Número de registros | 138 (46 municipios × 3 años) |
| Número de variables originales | 14 |
Las columnas numéricas del archivo original vienen con coma
como separador de miles (p. ej. "18,732") y los
campos Año y CodMunicipio vienen con
punto como separador de miles (p. ej.
"2.018", "13.006"), por lo cual se leen
inicialmente como texto y se convierten explícitamente.
raw <- read_csv("basededatos.csv",
col_types = cols(.default = "c"),
locale = locale(encoding = "UTF-8"))
names(raw) <- c("CodDpto", "Departamento", "CodMunicipio", "Municipio", "Anio",
"Terneras_menor1", "Terneros_menor1", "Hembras_1_2", "Machos_1_2",
"Hembras_2_3", "Machos_2_3", "Hembras_mayor3", "Machos_mayor3",
"Total_bovinos_original")
head(raw, 5)
## # A tibble: 5 × 14
## CodDpto Departamento CodMunicipio Municipio Anio Terneras_menor1
## <chr> <chr> <chr> <chr> <chr> <chr>
## 1 13 Bolívar 13.006 Achí 2.018 4,695
## 2 13 Bolívar 13.030 Altos Del Rosario 2.018 2,628
## 3 13 Bolívar 13.042 Arenal 2.018 1,048
## 4 13 Bolívar 13.052 Arjona 2.018 4,17
## 5 13 Bolívar 13.062 Arroyohondo 2.018 1,535
## # ℹ 8 more variables: Terneros_menor1 <chr>, Hembras_1_2 <chr>,
## # Machos_1_2 <chr>, Hembras_2_3 <chr>, Machos_2_3 <chr>,
## # Hembras_mayor3 <chr>, Machos_mayor3 <chr>, Total_bovinos_original <chr>
1. Conversión de tipos. Las columnas numéricas se
limpiaron eliminando los separadores de miles (, y
.) y convirtiéndolas a tipo entero.
clean_num <- function(x) as.integer(gsub("[.,]", "", x))
subcols <- c("Terneras_menor1", "Terneros_menor1", "Hembras_1_2", "Machos_1_2",
"Hembras_2_3", "Machos_2_3", "Hembras_mayor3", "Machos_mayor3")
bov <- raw %>%
mutate(
CodDpto = as.integer(CodDpto),
Departamento = trimws(Departamento),
CodMunicipio = gsub("\\.", "", CodMunicipio),
Anio = factor(as.integer(gsub("\\.", "", Anio))),
Municipio = trimws(Municipio),
Total_bovinos = clean_num(Total_bovinos_original)
)
bov[subcols] <- lapply(bov[subcols], clean_num)
2. Normalización de texto. Se detectaron inconsistencias de mayúsculas/tildes en el nombre de algunos municipios entre los distintos años (p. ej. “Cartagena De Indias” vs. “Cartagena de Indias”, “Simití” vs. “Simiti”). Se normalizó cada nombre a una única forma canónica por municipio.
clave <- toupper(iconv(bov$Municipio, from = "UTF-8", to = "ASCII//TRANSLIT"))
canon <- bov %>%
mutate(clave = clave) %>%
count(clave, Municipio, sort = TRUE) %>%
group_by(clave) %>%
slice_max(n, n = 1, with_ties = FALSE) %>%
select(clave, Municipio_limpio = Municipio)
bov <- bov %>%
mutate(clave = clave) %>%
left_join(canon, by = "clave") %>%
select(-clave)
cat("Municipios únicos antes de normalizar :", length(unique(bov$Municipio)), "\n")
## Municipios únicos antes de normalizar : 58
cat("Municipios únicos después de normalizar:", length(unique(bov$Municipio_limpio)), "\n")
## Municipios únicos después de normalizar: 46
cat("Estructura panel -> 46 municipios x 3 años =", 46 * 3, "registros\n")
## Estructura panel -> 46 municipios x 3 años = 138 registros
3. Validación de consistencia lógica. Se comparó la
columna Total_bovinos reportada por la fuente contra la
suma de las 8 subcategorías de edad/sexo.
bov$Total_calculado <- rowSums(bov[subcols])
bov$Diferencia <- bov$Total_bovinos - bov$Total_calculado
n_incons <- sum(bov$Diferencia != 0)
cat("Registros con diferencia entre el total reportado y la suma de subcategorías:",
n_incons, "de", nrow(bov),
sprintf("(%.1f%%)", 100 * n_incons / nrow(bov)), "\n")
## Registros con diferencia entre el total reportado y la suma de subcategorías: 20 de 138 (14.5%)
Se documenta esta inconsistencia como una limitación propia de la
fuente (posibles ajustes o categorías adicionales no desagregadas en el
reporte oficial) y se conserva la variable
Total_bovinos tal como la reporta la fuente, sin
alterarla, ya que es el indicador oficial usado en los reportes del
Ministerio.
4. Creación de variable derivada. A partir de
Total_bovinos se crea la variable categórica
Categoria_Tamano_Hato, que clasifica cada municipio-año en
terciles de tamaño del hato bovino.
brks <- quantile(bov$Total_bovinos, probs = c(0, 1/3, 2/3, 1), na.rm = TRUE)
bov$Categoria_Tamano_Hato <- cut(bov$Total_bovinos,
breaks = brks,
labels = c("Pequeño", "Mediano", "Grande"),
include.lowest = TRUE)
| Tipo | Variable | Descripción |
|---|---|---|
| Cualitativa | Anio |
Año de la observación (2018 / 2019 / 2020) |
| Cualitativa (derivada) | Categoria_Tamano_Hato |
Tamaño del hato bovino del municipio: Pequeño / Mediano / Grande |
| Cuantitativa | Total_bovinos |
Total de bovinos del municipio en el año (cabezas) |
| Cuantitativa | Hembras_mayor3 |
Hembras mayores a 3 años — hato reproductor/lechero (cabezas) |
datos <- bov %>%
select(Municipio_limpio, Anio, Total_bovinos, Hembras_mayor3, Categoria_Tamano_Hato)
head(datos, 10)
## # A tibble: 10 × 5
## Municipio_limpio Anio Total_bovinos Hembras_mayor3 Categoria_Tamano_Hato
## <chr> <fct> <int> <int> <fct>
## 1 Achí 2018 41855 18732 Grande
## 2 Altos del Rosario 2018 18548 751 Mediano
## 3 Arenal 2018 8994 3755 Pequeño
## 4 Arjona 2018 49093 14505 Grande
## 5 Arroyohondo 2018 15256 5687 Mediano
## 6 Barranco de Loba 2018 21289 6842 Mediano
## 7 Calamar 2018 22385 7317 Mediano
## 8 Cantagallo 2018 10172 3565 Pequeño
## 9 Cartagena de Indias 2018 14083 3237 Mediano
## 10 Cicuco 2018 10541 4061 Pequeño
tabla_anio <- datos %>%
count(Anio, name = "Frec.Abs") %>%
mutate(`Frec.Rel (%)` = round(100 * Frec.Abs / sum(Frec.Abs), 2))
tabla_anio
## # A tibble: 3 × 3
## Anio Frec.Abs `Frec.Rel (%)`
## <fct> <int> <dbl>
## 1 2018 46 33.3
## 2 2019 46 33.3
## 3 2020 46 33.3
ggplot(datos, aes(x = Anio)) +
geom_bar(fill = "#2c7fb8") +
labs(title = "Registros por año", x = "Año", y = "Frecuencia") +
theme_minimal(base_size = 12)
Como la base cubre 46 municipios en cada uno de los 3 años, la variable Año se distribuye de forma perfectamente equilibrada (33.3% en cada categoría); es decir, no hay meses/años con sub-representación y cualquier comparación entre años se hace sobre el mismo número de municipios.
tabla_tamano <- datos %>%
count(Categoria_Tamano_Hato, name = "Frec.Abs") %>%
mutate(`Frec.Rel (%)` = round(100 * Frec.Abs / sum(Frec.Abs), 2))
tabla_tamano
## # A tibble: 3 × 3
## Categoria_Tamano_Hato Frec.Abs `Frec.Rel (%)`
## <fct> <int> <dbl>
## 1 Pequeño 46 33.3
## 2 Mediano 46 33.3
## 3 Grande 46 33.3
ggplot(datos, aes(x = Categoria_Tamano_Hato, fill = Categoria_Tamano_Hato)) +
geom_bar(show.legend = FALSE) +
scale_fill_manual(values = c("#a1dab4", "#41b6c4", "#225ea8")) +
labs(title = "Municipios según tamaño del hato bovino",
x = "Categoría", y = "Frecuencia") +
theme_minimal(base_size = 12)
Por construcción (terciles), cada categoría agrupa el mismo número de observaciones (46). Esto es útil porque permite comparar, en partes iguales, municipios con hatos pequeños, medianos y grandes en los análisis cruzados posteriores.
Mode <- function(x) {
ux <- unique(x)
tab <- tabulate(match(x, ux))
ux[tab == max(tab)]
}
cat("Moda de Año:", paste(Mode(datos$Anio), collapse = ", "), "\n")
## Moda de Año: 2018, 2019, 2020
cat("Moda de Categoria_Tamano_Hato:", paste(as.character(Mode(datos$Categoria_Tamano_Hato)), collapse = ", "), "\n")
## Moda de Categoria_Tamano_Hato: Grande, Mediano, Pequeño
Al estar las tres categorías empatadas en frecuencia (46 cada una), ambas variables son multimodales: no hay un valor que predomine sobre los demás, lo cual es un resultado esperado dado el diseño balanceado del panel y de los terciles.
Total_bovinos)h <- hist(datos$Total_bovinos, breaks = "Sturges", plot = FALSE)
LI <- head(h$breaks, -1)
LS <- tail(h$breaks, -1)
ni <- h$counts
hi <- round(100 * ni / sum(ni), 2)
Ni <- cumsum(ni)
Hi <- round(100 * Ni / sum(ni), 2)
tabla_freq_total <- data.frame(LI, LS, Marca_Clase = (LI + LS) / 2,
Frec.Abs = ni, `Frec.Rel(%)` = hi,
Frec.Abs.Ac = Ni, `Frec.Rel.Ac(%)` = Hi,
check.names = FALSE)
tabla_freq_total
## LI LS Marca_Clase Frec.Abs Frec.Rel(%) Frec.Abs.Ac Frec.Rel.Ac(%)
## 1 0 20000 10000 76 55.07 76 55.07
## 2 20000 40000 30000 36 26.09 112 81.16
## 3 40000 60000 50000 15 10.87 127 92.03
## 4 60000 80000 70000 6 4.35 133 96.38
## 5 80000 100000 90000 2 1.45 135 97.83
## 6 100000 120000 110000 0 0.00 135 97.83
## 7 120000 140000 130000 3 2.17 138 100.00
ggplot(datos, aes(x = Total_bovinos)) +
geom_histogram(breaks = h$breaks, fill = "#2c7fb8", color = "white") +
labs(title = "Distribución del total de bovinos por municipio-año",
x = "Total de bovinos (cabezas)", y = "Frecuencia") +
theme_minimal(base_size = 12)
media_t <- mean(datos$Total_bovinos)
mediana_t <- median(datos$Total_bovinos)
cat("Media :", round(media_t, 1), "cabezas\n")
## Media : 26166.6 cabezas
cat("Mediana :", mediana_t, "cabezas\n")
## Mediana : 18073.5 cabezas
La media (2.6167^{4}) es notoriamente mayor que la mediana (1.80735^{4}), lo que ya anticipa una distribución con sesgo hacia la derecha: unos pocos municipios (como Cartagena o Magangué) tienen hatos muy grandes que “jalan” el promedio hacia arriba.
rango_t <- diff(range(datos$Total_bovinos))
varianza_t <- var(datos$Total_bovinos)
sd_t <- sd(datos$Total_bovinos)
cv_t <- sd_t / media_t * 100
cat("Rango :", rango_t, "cabezas\n")
## Rango : 127534 cabezas
cat("Varianza :", round(varianza_t, 0), "cabezas^2\n")
## Varianza : 538341874 cabezas^2
cat("Desviación estándar :", round(sd_t, 1), "cabezas\n")
## Desviación estándar : 23202.2 cabezas
cat("Coeficiente de variación:", round(cv_t, 2), "%\n")
## Coeficiente de variación: 88.67 %
Un coeficiente de variación de 88.7% (muy por encima del umbral del 20% habitualmente usado como referencia) indica que el tamaño del hato bovino es altamente heterogéneo entre los municipios de Bolívar.
quantile(datos$Total_bovinos, c(.10, .25, .50, .75, .90))
## 10% 25% 50% 75% 90%
## 8117.60 10702.75 18073.50 36114.75 49701.70
ggplot(datos, aes(x = "", y = Total_bovinos)) +
geom_boxplot(fill = "#41b6c4") +
coord_flip() +
labs(title = "Diagrama de caja — Total de bovinos", x = "", y = "Cabezas") +
theme_minimal(base_size = 12)
El diagrama de caja confirma la presencia de valores atípicos altos: los municipios con mayor actividad ganadera (Magangué, Cartagena, San Juan Nepomuceno) se alejan considerablemente del resto del grupo.
sk_t <- skewness(datos$Total_bovinos)
ku_t <- kurtosis(datos$Total_bovinos)
cat("Coeficiente de asimetría:", round(sk_t, 3), "\n")
## Coeficiente de asimetría: 2.183
cat("Coeficiente de curtosis :", round(ku_t, 3), "\n")
## Coeficiente de curtosis : 5.847
El coeficiente de asimetría es positivo (2.18), confirmando una asimetría a la derecha (muchos municipios con pocos bovinos, pocos municipios con muchos). La curtosis positiva (5.85) indica una distribución leptocúrtica: más apuntada que la normal, con colas pesadas producto de esos municipios con hatos muy grandes.
Hembras_mayor3)Esta variable aproxima el tamaño del hato reproductor/lechero de cada municipio.
h2 <- hist(datos$Hembras_mayor3, breaks = "Sturges", plot = FALSE)
LI2 <- head(h2$breaks, -1); LS2 <- tail(h2$breaks, -1)
ni2 <- h2$counts
hi2 <- round(100 * ni2 / sum(ni2), 2)
Ni2 <- cumsum(ni2); Hi2 <- round(100 * Ni2 / sum(ni2), 2)
tabla_freq_hembras <- data.frame(LI = LI2, LS = LS2, Marca_Clase = (LI2 + LS2) / 2,
Frec.Abs = ni2, `Frec.Rel(%)` = hi2,
Frec.Abs.Ac = Ni2, `Frec.Rel.Ac(%)` = Hi2,
check.names = FALSE)
tabla_freq_hembras
## LI LS Marca_Clase Frec.Abs Frec.Rel(%) Frec.Abs.Ac Frec.Rel.Ac(%)
## 1 0 5000 2500 52 37.68 52 37.68
## 2 5000 10000 7500 42 30.43 94 68.12
## 3 10000 15000 12500 24 17.39 118 85.51
## 4 15000 20000 17500 8 5.80 126 91.30
## 5 20000 25000 22500 7 5.07 133 96.38
## 6 25000 30000 27500 2 1.45 135 97.83
## 7 30000 35000 32500 0 0.00 135 97.83
## 8 35000 40000 37500 0 0.00 135 97.83
## 9 40000 45000 42500 2 1.45 137 99.28
## 10 45000 50000 47500 1 0.72 138 100.00
media_h <- mean(datos$Hembras_mayor3)
mediana_h <- median(datos$Hembras_mayor3)
sd_h <- sd(datos$Hembras_mayor3)
cv_h <- sd_h / media_h * 100
sk_h <- skewness(datos$Hembras_mayor3)
ku_h <- kurtosis(datos$Hembras_mayor3)
data.frame(
Indicador = c("Media", "Mediana", "Desv. estándar", "Coef. variación (%)",
"Asimetría", "Curtosis"),
Valor = round(c(media_h, mediana_h, sd_h, cv_h, sk_h, ku_h), 2)
)
## Indicador Valor
## 1 Media 8720.75
## 2 Mediana 6148.00
## 3 Desv. estándar 7877.55
## 4 Coef. variación (%) 90.33
## 5 Asimetría 2.26
## 6 Curtosis 6.53
ggplot(datos, aes(x = Hembras_mayor3)) +
geom_density(fill = "#a1dab4", alpha = 0.7) +
geom_vline(xintercept = media_h, linetype = "dashed", color = "#225ea8") +
geom_vline(xintercept = mediana_h, linetype = "dashed", color = "#d95f0e") +
labs(title = "Densidad — Hembras mayores a 3 años",
subtitle = "Línea azul = media | Línea naranja = mediana",
x = "Cabezas", y = "Densidad") +
theme_minimal(base_size = 12)
Al igual que con el total de bovinos, esta variable presenta CV muy alto (90.3%), asimetría positiva (2.26) y curtosis positiva (6.53): unos pocos municipios concentran una proporción desproporcionada del hato reproductor departamental.
Como valor agregado, se compara el total de bovinos según la categoría de tamaño de hato, para verificar la coherencia de la variable derivada.
datos %>%
group_by(Categoria_Tamano_Hato) %>%
summarise(
n = n(),
Media_Total = round(mean(Total_bovinos), 0),
Mediana_Total = median(Total_bovinos),
Media_Hembras_mayor3 = round(mean(Hembras_mayor3), 0)
)
## # A tibble: 3 × 5
## Categoria_Tamano_Hato n Media_Total Mediana_Total Media_Hembras_mayor3
## <fct> <int> <dbl> <dbl> <dbl>
## 1 Pequeño 46 8648 9148 3781
## 2 Mediano 46 18909 18074. 5883
## 3 Grande 46 50943 41064. 16499
ggplot(datos, aes(x = Categoria_Tamano_Hato, y = Total_bovinos, fill = Categoria_Tamano_Hato)) +
geom_boxplot(show.legend = FALSE) +
scale_fill_manual(values = c("#a1dab4", "#41b6c4", "#225ea8")) +
labs(title = "Total de bovinos según categoría de tamaño de hato",
x = "Categoría", y = "Total de bovinos (cabezas)") +
theme_minimal(base_size = 12)