1 Introducción

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.

2 Ficha técnica resumida

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

3 Carga de datos

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>

4 Proceso de depuración

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)

5 Selección de variables para el análisis

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

6 Análisis de variables cualitativas

6.1 Variable: Añ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.

6.2 Variable: Categoría de tamaño del hato

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.

6.3 Moda de las variables cualitativas

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.


7 Análisis de variables cuantitativas

7.1 Variable: Total de bovinos (Total_bovinos)

7.1.1 Tabla de frecuencia agrupada por intervalos

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)

7.1.2 Indicadores de centro

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.

7.1.3 Indicadores de dispersión

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.

7.1.4 Percentiles

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.

7.1.5 Indicadores de forma

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.

7.2 Variable: Hembras mayores a 3 años (Hembras_mayor3)

Esta variable aproxima el tamaño del hato reproductor/lechero de cada municipio.

7.2.1 Tabla de frecuencia agrupada por intervalos

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

7.2.2 Indicadores de centro, dispersión y forma

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.


8 Análisis cruzado (complementario)

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)

9 Conclusiones

  • Las variables cualitativas Año y Categoría de tamaño del hato resultaron perfectamente balanceadas (33.3% cada categoría) por el diseño del panel y por la construcción por terciles, respectivamente; ambas son multimodales.
  • Las variables cuantitativas Total de bovinos y Hembras mayores a 3 años muestran una dispersión muy alta (CV > 85%), asimetría positiva marcada y curtosis leptocúrtica: la ganadería bovina en Bolívar está concentrada en pocos municipios (p. ej. Magangué, Cartagena, San Juan Nepomuceno), mientras que la mayoría de municipios tiene hatos comparativamente pequeños.
  • La media es sistemáticamente mayor que la mediana en ambas variables cuantitativas, lo que es consistente con la presencia de valores atípicos altos identificados en los diagramas de caja.
  • Se documentó una inconsistencia en el 14.5% de los registros entre el total reportado por la fuente y la suma de las subcategorías de edad/sexo, la cual se reporta como limitación de los datos abiertos originales.