Este análisis se realizó sobre una base de datos de proveedores que contiene información operativa y de costos de cada proveedor. El objetivo del taller es explorar la calidad de los datos, describir las variables, identificar patrones y aportar recomendaciones prácticas para el negocio.
A continuación describimos las variables tal como aparecen en la base:
# Cargar datos
datos <- read_csv("datos_negocios_extra_1_proveedores.csv", show_col_types = FALSE)
# Dimensiones y vista rápida
cat("Número de filas (registros):", nrow(datos), "\n")
## Número de filas (registros): 100
cat("Número de columnas (variables):", ncol(datos), "\n")
## Número de columnas (variables): 4
glimpse(datos)
## Rows: 100
## Columns: 4
## $ Tipo_Proveedor <chr> "Local", "Internacional", "Nacional", "Internaciona…
## $ Pedidos_Realizados <dbl> 16, 11, 12, 20, 38, 42, 39, 15, 44, 15, 14, 7, 9, 1…
## $ Tiempo_Envio_Dias <dbl> 5.7, 3.5, 4.4, 6.6, 9.6, 5.2, 9.3, 6.2, 8.0, 4.5, 7…
## $ Costo_Envio <dbl> 279.07, 488.87, 268.02, 141.31, 390.66, 282.06, 264…
| Nombre | Clase |
|---|---|
| Tipo_Proveedor | character |
| Pedidos_Realizados | numeric |
| Tiempo_Envio_Dias | numeric |
| Costo_Envio | numeric |
A continuación dividimos el análisis en variables numéricas y variables categóricas y desarrollamos una interpretación práctica de cada una.
Las variables numéricas nos permiten cuantificar comportamiento y variabilidad. En esta base son:
Pedidos_Realizados — volumen de actividad del
proveedor.Tiempo_Envio_Dias — eficiencia en días.Costo_Envio — costo económico del envío.Estas medidas son clave para evaluar rendimiento, identificar proveedores costosos o lentos.
| Variable | V1 | V2 | V3 | V4 | V5 | V6 | V7 | V8 | V9 | V10 | V11 | V12 | V13 | V14 | V15 | V16 | V17 | V18 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Var1 | ||||||||||||||||||
| Var2 | Pedidos_Realizados | Pedidos_Realizados | Pedidos_Realizados | Pedidos_Realizados | Pedidos_Realizados | Pedidos_Realizados | Tiempo_Envio_Dias | Tiempo_Envio_Dias | Tiempo_Envio_Dias | Tiempo_Envio_Dias | Tiempo_Envio_Dias | Tiempo_Envio_Dias | Costo_Envio | Costo_Envio | Costo_Envio | Costo_Envio | Costo_Envio | Costo_Envio |
| Freq | Min. : 7.00 | 1st Qu.:15.00 | Median :25.50 | Mean :27.48 | 3rd Qu.:41.00 | Max. :48.00 | Min. : 1.50 | 1st Qu.: 4.75 | Median : 8.25 | Mean : 8.14 | 3rd Qu.:11.22 | Max. :15.00 | Min. : 50.04 | 1st Qu.:143.40 | Median :282.56 | Mean :271.01 | 3rd Qu.:375.64 | Max. :494.13 |
library(gridExtra)
p1 <- ggplot(datos, aes(x = Pedidos_Realizados)) +
geom_histogram(binwidth = 5, fill = "#4E79A7", color = "white") +
labs(title = "Histograma - Pedidos Realizados", x = "Pedidos_Realizados", y = "Frecuencia") + theme_minimal()
p2 <- ggplot(datos, aes(y = Pedidos_Realizados)) +
geom_boxplot(fill = "#4E79A7", alpha = 0.6) + labs(title = "Boxplot - Pedidos Realizados", y = "Pedidos_Realizados") + theme_minimal()
p3 <- ggplot(datos, aes(x = Tiempo_Envio_Dias)) +
geom_histogram(binwidth = 1, fill = "#F28E2B", color = "white") +
labs(title = "Histograma - Tiempo Envío (días)", x = "Tiempo_Envio_Dias", y = "Frecuencia") + theme_minimal()
p4 <- ggplot(datos, aes(y = Tiempo_Envio_Dias)) +
geom_boxplot(fill = "#F28E2B", alpha = 0.6) + labs(title = "Boxplot - Tiempo Envío (días)", y = "Tiempo_Envio_Dias") + theme_minimal()
p5 <- ggplot(datos, aes(x = Costo_Envio)) +
geom_histogram(binwidth = diff(range(datos$Costo_Envio, na.rm=TRUE))/30, fill = "#59A14F", color = "white") +
labs(title = "Histograma - Costo Envío", x = "Costo_Envio", y = "Frecuencia") + theme_minimal()
p6 <- ggplot(datos, aes(y = Costo_Envio)) +
geom_boxplot(fill = "#59A14F", alpha = 0.6) + labs(title = "Boxplot - Costo Envío", y = "Costo_Envio") + theme_minimal()
grid.arrange(p1, p2, p3, p4, p5, p6, ncol = 2)
Interpretación ampliada:
Los histogramas muestran la forma de la distribución (asimetría,
posibles picos), mientras que los boxplots resaltan la mediana, rango
intercuartílico y posibles outliers (puntos por fuera de los
bigotes). Los outliers pueden deberse tanto a errores de registro como a
casos reales extremos (proveedores rápidos o muy lentos, costos
excepcionales). A continuación identificamos y listamos esos casos.
Las variables categóricas definen grupos o etiquetas. En esta base tenemos:
Tipo_Proveedor — clasifica al proveedor por su
tipo.Envio_Rapido como variable binaria
a partir de Tiempo_Envio_Dias).| Tipo_Proveedor | Frecuencia |
|---|---|
| Nacional | 42 |
| Local | 32 |
| Internacional | 26 |
ggplot(datos, aes(x = Tipo_Proveedor, fill = Tipo_Proveedor)) +
geom_bar() + theme_minimal() +
scale_fill_brewer(palette = "Set2") +
labs(title = "Distribución de proveedores por tipo", x = "Tipo_Proveedor", y = "Conteo") +
theme(axis.text.x = element_text(angle = 25, hjust = 1), legend.position = "none")
# Cargar datos
proveedores <- read.csv("datos_negocios_extra_1_proveedores.csv")
# Contar valores faltantes por columna
nas <- colSums(is.na(proveedores))
# Convertir a tabla y mostrar con estilo
nas %>%
tibble::enframe(name = "Variable", value = "NA_Count") %>%
knitr::kable(caption = "Conteo de valores faltantes por variable") %>%
kableExtra::kable_styling(full_width = FALSE, bootstrap_options = c("striped", "condensed"))
| Variable | NA_Count |
|---|---|
| Tipo_Proveedor | 0 |
| Pedidos_Realizados | 0 |
| Tiempo_Envio_Dias | 0 |
| Costo_Envio | 0 |
Interpretación:
Si la tabla anterior muestra ceros en todas las variables, significa que
no hay valores faltantes en la base. Esto es positivo
ya que facilita el análisis y sugiere un proceso de recolección de datos
completo.
detect_outliers <- function(x){ q1 <- quantile(x, 0.25, na.rm=TRUE) q3 <- quantile(x, 0.75, na.rm=TRUE) iqr <- q3 - q1 lower <- q1 - 1.5iqr upper <- q3 + 1.5iqr which(x < lower | x > upper) }
# Función IQR para detectar outliers
detect_outliers <- function(x){
q1 <- quantile(x, 0.25, na.rm=TRUE)
q3 <- quantile(x, 0.75, na.rm=TRUE)
iqr <- q3 - q1
lower <- q1 - 1.5*iqr
upper <- q3 + 1.5*iqr
which(x < lower | x > upper)
}
# Detectar outliers en las variables
out_pedidos <- detect_outliers(proveedores$Pedidos_Realizados)
out_tiempo <- detect_outliers(proveedores$Tiempo_Envio_Dias)
out_costo <- detect_outliers(proveedores$Costo_Envio)
# Construir lista de outliers
out_list <- tibble(
Variable = c(rep("Pedidos_Realizados", length(out_pedidos)),
rep("Tiempo_Envio_Dias", length(out_tiempo)),
rep("Costo_Envio", length(out_costo))),
Row = c(out_pedidos, out_tiempo, out_costo)
)
# Mostrar resultados
if(nrow(out_list) == 0){
cat("No se detectaron outliers con la regla IQR*1.5.")
} else {
out_list %>%
left_join(tibble(Row = 1:nrow(proveedores), proveedores), by = "Row") %>%
kable(caption = "Registros detectados como outliers (IQR*1.5)") %>%
kable_styling(full_width = FALSE, bootstrap_options = c("striped","hover"))
}
## No se detectaron outliers con la regla IQR*1.5.
Interpretación:
Los registros listados deben ser revisados: si corresponden a entradas
reales (por ejemplo, un coste muy alto por tamaño del pedido) deben
mantenerse; si son errores (digitación, unidad equivocada) deben
corregirse o eliminarse.
En esta sección justificamos las elecciones y presentamos cálculos paso a paso.
Tiempo_Envio_Dias. Justificación: es una métrica directa de
eficiencia logística y de servicio al cliente; su media indica el
desempeño medio de la red de proveedores.Envio_Rapido = 1 si
Tiempo_Envio_Dias ≤ 5 (umbral seleccionado por criterios
prácticos), 0 si > 5. Justificación: medir la proporción de
proveedores que cumplen con un tiempo de entrega “rápido” es útil para
indicadores SLA.N <- nrow(proveedores)
# ===============================
# MEDIA MUESTRAL
# ===============================
variable_media <- "Tiempo_Envio_Dias"
media_envio <- mean(proveedores[[variable_media]], na.rm = TRUE) # mu_hat
desviacion_envio <- sd(proveedores[[variable_media]], na.rm = TRUE) # s
tamano_muestra_media <- 40 # n
error_estandar_media <- desviacion_envio / sqrt(tamano_muestra_media) *
sqrt((N - tamano_muestra_media)/(N - 1)) # SE con corrección
# Probabilidades
prob_media_mayor_6 <- 1 - pnorm(6, mean = media_envio, sd = error_estandar_media)
prob_media_entre_4y6 <- pnorm(6, mean = media_envio, sd = error_estandar_media) -
pnorm(4, mean = media_envio, sd = error_estandar_media)
# Tabla resultados media
resultados_media <- tibble(
Medida = c("Media de tiempo de envío", "Desviación estándar", "Tamaño muestral", "Error estándar",
"Probabilidad media > 6", "Probabilidad 4 < media < 6"),
Valor = c(media_envio, desviacion_envio, tamano_muestra_media, error_estandar_media,
prob_media_mayor_6, prob_media_entre_4y6)
)
# ===============================
# PROPORCIÓN MUESTRAL
# ===============================
proveedores <- proveedores %>% mutate(Envio_Rapido = ifelse(Tiempo_Envio_Dias <= 5, 1, 0))
prop_envios_rapidos <- mean(proveedores$Envio_Rapido, na.rm = TRUE) # p_hat
tamano_muestra_prop <- 40 # n_prop
error_estandar_prop <- sqrt(prop_envios_rapidos * (1 - prop_envios_rapidos) / tamano_muestra_prop) *
sqrt((N - tamano_muestra_prop)/(N - 1)) # SE_p
prob_prop_mayor_60 <- 1 - pnorm(0.6, mean = prop_envios_rapidos, sd = error_estandar_prop)
# Tabla resultados proporción
resultados_prop <- tibble(
Medida = c("Proporción de envíos rápidos", "Tamaño muestral", "Error estándar",
"Probabilidad proporción > 0.6"),
Valor = c(prop_envios_rapidos, tamano_muestra_prop, error_estandar_prop, prob_prop_mayor_60)
)
# ===============================
# MOSTRAR TABLAS
# ===============================
resultados_media %>%
kable(caption = "Resultados — Media muestral (nombres descriptivos)") %>%
kable_styling(full_width = FALSE)
| Medida | Valor |
|---|---|
| Media de tiempo de envío | 8.1400000 |
| Desviación estándar | 3.8689909 |
| Tamaño muestral | 40.0000000 |
| Error estándar | 0.4762399 |
| Probabilidad media > 6 | 0.9999965 |
| Probabilidad 4 < media < 6 | 0.0000035 |
resultados_prop %>%
kable(caption = "Resultados — Proporción muestral (nombres descriptivos)") %>%
kable_styling(full_width = FALSE)
| Medida | Valor |
|---|---|
| Proporción de envíos rápidos | 0.2900000 |
| Tamaño muestral | 40.0000000 |
| Error estándar | 0.0558542 |
| Probabilidad proporción > 0.6 | 0.0000000 |
Interpretación práctica:
El promedio muestral refleja el tiempo promedio de entrega de
los proveedores. Dado que la probabilidad de que el promedio sea mayor a
seis días resulta alta, esto significa que, incluso tomando muestras de
cuarenta proveedores, es común observar tiempos de entrega superiores a
seis días. Esta situación representa una alerta operativa negativa
porque implica demoras en la logística.
Por otra parte, la proporción muestral refleja qué parte de los envíos se realizan en cinco días o menos. Como la probabilidad de que más del sesenta por ciento de los proveedores cumpla este estándar es prácticamente nula, podemos concluir que es muy poco factible alcanzar ese nivel de cumplimiento. Esto sugiere una limitación estructural en el servicio, que debería llevar a revisar los acuerdos actuales y negociar mejores estándares de entrega.
Tiempo_Envio_Dias y validar si
corresponden a casos atípicos reales o errores.Costo_Envio, verificar si se deben a tarifas especiales o a
errores de registro.