El presente trabajo tiene como objetivo realizar un análisis exploratorio de la base de datos suministrada, la cual contiene información relacionada con distintos aspectos de la logística de transporte. A partir de esta información se busca identificar las características principales de los datos, revisar su calidad y comprender mejor el comportamiento de las variables. Para ello, se desarrollan etapas que incluyen la contextualización de las variables, la descripción general de la base, el análisis según el tipo de variable, la revisión de valores faltantes y la detección de posibles valores atípicos.
En esta sección presentamos la base de datos utilizada para el taller y describimos cada variable de forma clara y operacional. El análisis fue orientado a obtener información práctica para la gestión logística: identificar rutas con mayores costos, evaluar tiempos de entrega y detectar patrones inusuales que requieran intervención.
La base de datos proviene de un conjunto de registros de operaciones logísticas con 100 observaciones. Cada fila representa un recorrido o servicio efectuado por la empresa durante el periodo de estudio. El objetivo de este análisis es explorar la distribución de kilómetros recorridos, tiempos de entrega y costos operativos por ruta, y a partir de ello realizar inferencias muestrales sobre costos y proporciones de presencia en una ruta específica.
# Cargar datos
datos <- read_csv(params$data_file, show_col_types = FALSE) %>% clean_names()
# Mostrar primeras filas
datos %>% slice_head(n = 8)
## # A tibble: 8 × 4
## ruta km_recorridos tiempo_entrega_horas costos_operativos
## <chr> <dbl> <dbl> <dbl>
## 1 Ruta Sur 1796 17.2 17459.
## 2 Ruta Norte 4856 29.8 9828.
## 3 Ruta Sur 2909 13.3 11964.
## 4 Ruta Oeste 3643 12.7 18626.
## 5 Ruta Este 4753 23.1 12812.
## 6 Ruta Oeste 4354 1.1 19844.
## 7 Ruta Oeste 3956 46.8 9429.
## 8 Ruta Oeste 2001 45.5 12759.
A continuación describimos cada variable, qué mide y sus unidades, con un breve comentario sobre su utilidad para la toma de decisiones:
| variable | tipo | descripcion | comentario |
|---|---|---|---|
| ruta | Categórica (texto) | Identifica la ruta o zona correspondiente al recorrido (ej: ‘Ruta Sur’, ‘Ruta Norte’, etc.). Útil para segmentar desempeño por zona. | Variable que usaremos para recodificar una binaria (ej. es_ruta_sur). |
| km_recorridos | Numérica (entera, km) | Distancia total recorrida en kilómetros para el servicio. Indicador clave para estimar consumo de combustible y desgaste de flota. | Se evaluará su distribución y presencia de valores atípicos. |
| tiempo_entrega_horas | Numérica (continuo, horas) | Tiempo total de entrega medido en horas. Permite analizar eficiencia y cumplimiento de ventanas de servicio. | Relacionaremos con kilómetros y costos para entender eficiencia. |
| costos_operativos | Numérica (continuo, monetary units) | Costos operativos asociados al recorrido (transporte, combustible, peajes, mantenimiento). Métrica principal para evaluar rentabilidad y eficiencia. | Se utilizará como variable continua para el análisis de media muestral. |
En este punto se presentan las dimensiones exactas, nombres y tipos de variables encontrados en la base de datos. Esta información es de suma importancia para la documentación del trabajo.
# Dimensiones
dims <- dim(datos)
n_filas <- dims[1]; n_columnas <- dims[2]
# Tabla de resumen con nombres y tipos (sin repetir información)
tabla_tipos <- tibble(
Variable = names(datos),
Tipo = sapply(datos, function(x) class(x)[1]),
Ejemplo = sapply(datos, function(x) as.character(head(na.omit(x),1))[1])
)
# Mostrar resultados
tibble(Clave = c("Número de filas", "Número de columnas"),
Valor = c(n_filas, n_columnas)) %>%
kable() %>% kable_styling(full_width = FALSE) %>% row_spec(0, background = "#F7F7F7")
| Clave | Valor |
|---|---|
| Número de filas | 100 |
| Número de columnas | 4 |
tabla_tipos %>% kable(caption = "Nombres de variables y tipos detectados") %>%
kable_styling(full_width = FALSE) %>% row_spec(0, bold = TRUE, background = "#E8F6EF")
| Variable | Tipo | Ejemplo |
|---|---|---|
| ruta | character | Ruta Sur |
| km_recorridos | numeric | 1796 |
| tiempo_entrega_horas | numeric | 17.2 |
| costos_operativos | numeric | 17458.55 |
La base contiene exactamente 100 observaciones y 4 variables.
En esta sección hacemos un análisis separado para variables numéricas y categóricas. Primero aclaramos cuáles son y qué representan.
Estas variables cuantifican magnitudes continuas o discretas (km enteros) relacionadas con la operación logística. A continuación presentamos medidas resumen, gráficos y una explicación interpretativa de cada resultado.
library(psych)
datos_num <- datos %>%
select(km_recorridos, tiempo_entrega_horas, costos_operativos) %>%
rename(
"Kilómetros recorridos" = km_recorridos,
"Tiempo de entrega (horas)" = tiempo_entrega_horas,
"Costos operativos" = costos_operativos
)
describe(datos_num)
## vars n mean sd median trimmed mad
## Kilómetros recorridos 1 100 2575.72 1385.56 2729.0 2568.32 1651.62
## Tiempo de entrega (horas) 2 100 25.54 14.89 25.9 25.83 19.57
## Costos operativos 3 100 11048.70 5736.23 10407.5 11031.21 8318.61
## min max range skew kurtosis se
## Kilómetros recorridos 166.00 4948.00 4782.00 0.03 -1.09 138.56
## Tiempo de entrega (horas) 1.10 47.60 46.50 -0.04 -1.28 1.49
## Costos operativos 1008.57 19844.28 18835.71 -0.01 -1.35 573.62
La tabla de variables numéricas muestra que, en promedio, los recorridos son de 2.575 km, el tiempo de entrega es de unas 25,5 horas y los costos operativos alcanzan 11.048. Estos valores reflejan las características generales de las operaciones y permiten tener una idea del nivel de distancia, tiempo y gasto involucrado en los envíos.
datos %>%
pivot_longer(cols = c(km_recorridos, tiempo_entrega_horas, costos_operativos),
names_to = "variable", values_to = "valor") %>%
ggplot(aes(x = valor)) +
geom_histogram(bins = 20, fill = "skyblue", color = "black") +
facet_wrap(~variable, scales = "free") +
theme_minimal()
La variable ruta identifica la zona de operación; es esencial para segmentar los resultados. A continuación mostramos frecuencias y una explicación interpretativa por categoría.
tabla_ruta <- datos %>% count(ruta, name = "freq") %>% mutate(prop = freq / sum(freq))
tabla_ruta %>% arrange(desc(freq)) %>% kable(caption = "Frecuencia por ruta") %>%
kable_styling(full_width = FALSE) %>% row_spec(0, background = "#FDEBD0")
| ruta | freq | prop |
|---|---|---|
| Ruta Oeste | 30 | 0.30 |
| Ruta Sur | 29 | 0.29 |
| Ruta Norte | 21 | 0.21 |
| Ruta Este | 20 | 0.20 |
Al observar qué rutas concentran más servicios se puede priorizar auditorías de eficiencia o campañas para optimizar costos en las rutas más frecuentes.
faltantes <- sapply(datos, function(x) sum(is.na(x)))
tibble(variable = names(faltantes), n_na = as.integer(faltantes), prop_na = n_na / nrow(datos)) %>%
arrange(desc(prop_na)) %>%
kable(caption = "Conteo de valores faltantes por variable") %>%
kable_styling(full_width = FALSE) %>% row_spec(0, background = "#F7EEF8")
| variable | n_na | prop_na |
|---|---|---|
| ruta | 0 | 0 |
| km_recorridos | 0 | 0 |
| tiempo_entrega_horas | 0 | 0 |
| costos_operativos | 0 | 0 |
Luego de un análisis se puede decir que no existen valores faltantes, es decir, todas las variables están completas y listas para su análisis. Esto indica que la base de datos está completa, lo cual facilita la realización de análisis estadísticos y modelos posteriores sin necesidad de imputación de datos.
A continuación presentamos boxplots para identificar outliers en las variables numéricas. Después de se explica el significado y cómo interpretar los posibles outliers.
# Definir las variables numéricas antes de pivot_longer
vars_num <- names(datos)[sapply(datos, is.numeric)]
datos %>%
pivot_longer(all_of(vars_num), names_to = "variable", values_to = "valor") %>%
ggplot(aes(x = variable, y = valor)) +
geom_boxplot()
Interpretación detallada sobre boxplots y outliers:
El boxplot muestra la mediana (línea central), el primer y tercer
cuartil (caja) y los “bigotes” que suelen extenderse hasta 1.5×IQR desde
los cuartiles. Los puntos fuera de los bigotes se consideran
outliers potenciales. Un outlier puede deberse a
errores de registro, un caso extremo válido (por ejemplo, un servicio
muy largo) o a variabilidad natural. Para
costos_operativos, outliers altos indicarían recorridos con
costos anómalamente altos, por lo tanto, se debe priorizar la
investigación para confirmar si corresponde a mayor distancia, peajes, o
errores contables.
Antes de calcular las distribuciones muestrales explicamos la elección de variables y parámetros.
costos_operativos. Justificación: Los costos son
la métrica central para toma de decisiones en logística; conocer su
promedio y su variabilidad ayuda a estimar presupuestos y detectar rutas
no rentables. Además, es una variable continua y adecuada para análisis
de medias.es_ruta_sur definida como 1 si ruta == “Ruta
Sur”, 0 en otro caso. Justificación: Interesa conocer la
proporción de servicios que se realizan en una ruta específica para
priorizar recursos o aplicar políticas regionales.# Preparar variables
datos <- datos %>% mutate(es_ruta_sur = if_else(str_to_lower(ruta) == "ruta sur", 1, 0))
var_cont <- "costos_operativos"
var_bin <- "es_ruta_sur"
N <- nrow(datos)
n <- 30
x <- datos[[var_cont]]
pvar <- datos[[var_bin]]
list(N=N, n=n, var_cont=var_cont, var_bin=var_bin)
## $N
## [1] 100
##
## $n
## [1] 30
##
## $var_cont
## [1] "costos_operativos"
##
## $var_bin
## [1] "es_ruta_sur"
mu_hat <- mean(x, na.rm = TRUE)
s_hat <- sd(x, na.rm = TRUE)
SE_xbar <- s_hat / sqrt(n) * sqrt((N - n) / (N - 1)) # FPC
tibble(mu_hat = mu_hat, s_hat = s_hat, SE_xbar = SE_xbar)
## # A tibble: 1 × 3
## mu_hat s_hat SE_xbar
## <dbl> <dbl> <dbl>
## 1 11049. 5736. 881.
Explicación del procedimiento:
1. Estimamos la media y desviación estándar de la variable en la
población completa (mu_hat y s_hat).
2. Calculamos el error estándar de la media para muestras de tamaño n,
aplicando la corrección por población finita (FPC)
porque extraemos sin reemplazo de una población relativamente pequeña:
\(SE_{\bar X}=\dfrac{s}{\sqrt{n}}\sqrt{\dfrac{N-n}{N-1}}\).
3. Asumimos la aproximación normal: \(\bar X \approx
\mathcal{N}(\hat{\mu}, SE_{\bar X}^2)\).
Elegimos umbrales contextualizados para responder probabilidades: -
(c\) = la media observada \(\hat{\mu}\) (probabilidad de obtener una
muestra con media mayor que la observada). - (a\) y (b\) = percentiles
40 y 60 de costos_operativos (rango central moderado).
c <- mu_hat
a <- quantile(x, 0.4, na.rm = TRUE)
b <- quantile(x, 0.6, na.rm = TRUE)
p_mayor_c <- 1 - pnorm(c, mean = mu_hat, sd = SE_xbar)
p_entre_ab <- pnorm(b, mean = mu_hat, sd = SE_xbar) - pnorm(a, mean = mu_hat, sd = SE_xbar)
tibble(umbral_c = c, a = a, b = b, `P(Xbar > c)` = p_mayor_c, `P(a < Xbar < b)` = p_entre_ab)
## # A tibble: 1 × 5
## umbral_c a b `P(Xbar > c)` `P(a < Xbar < b)`
## <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 11049. 9433. 13244. 0.5 0.960
Interpretación: Si P(X̄ > c) es
cercana a 0.5 es esperable; valores extremos (muy cercanos a 0 o 1)
indican que observar una media así con n=30 es muy improbable, lo que
sugiere que la media poblacional real sería diferente o que la
variabilidad es baja/alta. Para la gestión: si la probabilidad de que la
media muestral supere cierto umbral es alta, la empresa debe preparar
presupuesto adicional para cubrir esos costos promedio.
p_hat <- mean(pvar, na.rm = TRUE)
SE_phat <- sqrt(p_hat * (1 - p_hat) / n) * sqrt((N - n) / (N - 1))
tibble(p_hat = p_hat, SE_phat = SE_phat)
## # A tibble: 1 × 2
## p_hat SE_phat
## <dbl> <dbl>
## 1 0.29 0.0697
Explicación del procedimiento:
1. Calculamos la proporción poblacional aproximada (\hat p\) (fracción
de observaciones en Ruta Sur).
2. Calculamos el error estándar con FPC: \(SE_{\hat p}=\sqrt{\dfrac{\hat
p(1-\hat p)}{n}}\sqrt{\dfrac{N-n}{N-1}}\).
3. Aproximamos la distribución muestral por normal: \(\hat p \approx
\mathcal{N}(\hat p, SE_{\hat p}^2)\).
Evaluamos probabilidades de interés: (P(\hat p > 0.5)\) y (P(0.4 < \hat p < 0.6)\).
c_prop <- 0.5; a_prop <- 0.4; b_prop <- 0.6
p_mayor_c_prop <- 1 - pnorm(c_prop, mean = p_hat, sd = SE_phat)
p_entre_ab_prop <- pnorm(b_prop, mean = p_hat, sd = SE_phat) - pnorm(a_prop, mean = p_hat, sd = SE_phat)
tibble(umbral_c = c_prop, a = a_prop, b = b_prop, `P(phat > c)` = p_mayor_c_prop, `P(a < phat < b)` = p_entre_ab_prop)
## # A tibble: 1 × 5
## umbral_c a b `P(phat > c)` `P(a < phat < b)`
## <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 0.5 0.4 0.6 0.00129 0.0572
Interpretación: Estas probabilidades informan qué tan plausible es que una muestra de tamaño n muestre una proporción de servicios en Ruta Sur mayor al 50% (u otra banda). Si es improbable, no se esperaría que Ruta Sur concentre más de la mitad de los servicios, y la organización puede decidir asignar recursos en función de esta evidencia.
A partir de la información de la base de datos y las distribuciones muestrales, se puede evidenciar que los datos están completos, sin valores faltantes, lo que facilita el análisis. Se recomenda revisar los outliers de costos para determinar si corresponden a recorridos válidos o requieren ajustes, así como optimizar las rutas con tiempos de entrega elevados teniendo en cuenta congestión y horarios pico. También conviene monitorear la proporción por ruta para evaluar concentración de recursos y riesgo operativo, mejorar la calidad de los datos documentando fechas y estandarizando categorías, y, en decisiones críticas, considerar muestras más grandes o análisis adicionales.