1. Contextualización de la base de datos y descripción de variables

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:


2. Características generales de la base de datos

# 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…

2.1 Nombres y tipos de variables (tabla)

Variables y tipos en la base
Nombre Clase
Tipo_Proveedor character
Pedidos_Realizados numeric
Tiempo_Envio_Dias numeric
Costo_Envio numeric

3. Análisis de variables según su tipo

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.

3.1 Variables numéricas (qué son y cuáles están presentes)

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.

3.1.1 Resumen estadístico (numéricas)

Resumen estadístico para variables numéricas
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

3.1.2 Gráficos: histogramas + boxplots.

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.

3.2 Variables categóricas (qué son y cuáles están presentes)

Las variables categóricas definen grupos o etiquetas. En esta base tenemos:

  • Tipo_Proveedor — clasifica al proveedor por su tipo.
    (Además podríamos crear Envio_Rapido como variable binaria a partir de Tiempo_Envio_Dias).

3.2.1 Resumen y frecuencia (categóricas)

Frecuencia por Tipo de Proveedor
Tipo_Proveedor Frecuencia
Nacional 42
Local 32
Internacional 26

3.2.2 Gráfico categórico (Barras)

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")


4. Revisión de valores faltantes (NA)

# 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"))
Conteo de valores faltantes por variable
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.


5. Detección y listado de valores atípicos (outliers)

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.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.


6. Distribuciones muestrales: media y proporción (justificación y cálculo)

En esta sección justificamos las elecciones y presentamos cálculos paso a paso.

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)
Resultados — Media muestral (nombres descriptivos)
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)
Resultados — Proporción muestral (nombres descriptivos)
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.


7. Recomendaciones y conclusiones detalladas (por hallazgo)