1. Introducción

Adidas vende a través de distribuidores y minoristas de distintos tamaños, en varias regiones y por canales con lógicas muy diferentes (tienda física, outlet y online). En este informe asumimos el rol de analistas de datos de la compañía y analizamos 9.648 registros de ventas con técnicas de analítica descriptiva, exploratoria y diagnóstica; al final proponemos recomendaciones básicas (analítica prescriptiva) para el equipo directivo.

Pregunta guía:

¿Dónde, cómo y qué le conviene priorizar a Adidas para crecer en utilidad y no solo en ventas?

Alcance. La base no tiene fecha, así que no se calculan tasas de crecimiento ni estacionalidad: es una “foto” del desempeño. Tampoco trae costos ni descuentos, por lo que las causas de las diferencias de rentabilidad se presentan como hipótesis. Los valores se muestran en dólares (la base no especifica la moneda; se asume USD).

Cómo leer los gráficos. Todos los títulos dicen la conclusión principal. Como código de colores usamos siempre lo mismo: azul = por encima del promedio de la compañía (bueno) y naranja = por debajo del promedio (a revisar). Debajo de cada gráfico se explica por qué se eligió ese tipo de visualización.

2. Preparación de los datos

PASO 1. Cargar librerías

library(readxl)
library(dplyr)
library(tidyr)
library(ggplot2)
library(forcats)
library(scales)
library(knitr)
library(kableExtra)

PASO 2. Cargar la base de datos

Nota: el archivo DatosCaso1.xlsx y la imagen logo_adidas.png deben estar en la misma carpeta que este .Rmd.

datos <- read_excel("DatosCaso1.xlsx", sheet = 1)

dim(datos)
## [1] 9648   11
glimpse(datos)
## Rows: 9,648
## Columns: 11
## $ distribuidor       <chr> "Foot Locker", "Foot Locker", "Foot Locker", "Foot …
## $ region             <chr> "Northeast", "Northeast", "Northeast", "Northeast",…
## $ estado             <chr> "New York", "New York", "New York", "New York", "Ne…
## $ ciudad             <chr> "New York", "New York", "New York", "New York", "Ne…
## $ producto           <chr> "Men's Street Footwear", "Men's Athletic Footwear",…
## $ precio_unidad      <dbl> 50, 50, 40, 45, 60, 50, 50, 50, 40, 45, 60, 50, 50,…
## $ unidades_vendidas  <dbl> 1200, 1000, 1000, 850, 900, 1000, 1250, 900, 950, 8…
## $ ventas_total       <dbl> 60000, 50000, 40000, 38250, 54000, 50000, 62500, 45…
## $ utilidad_operativa <dbl> 30000.00, 15000.00, 14000.00, 13387.50, 16200.00, 1…
## $ margen_operativo   <dbl> 0.50, 0.30, 0.35, 0.35, 0.30, 0.25, 0.50, 0.30, 0.3…
## $ metodo_venta       <chr> "In-store", "In-store", "In-store", "In-store", "In…
head(datos)
distribuidor region estado ciudad producto precio_unidad unidades_vendidas ventas_total utilidad_operativa margen_operativo metodo_venta
Foot Locker Northeast New York New York Men’s Street Footwear 50 1200 60000 30000.0 0.50 In-store
Foot Locker Northeast New York New York Men’s Athletic Footwear 50 1000 50000 15000.0 0.30 In-store
Foot Locker Northeast New York New York Women’s Street Footwear 40 1000 40000 14000.0 0.35 In-store
Foot Locker Northeast New York New York Women’s Athletic Footwear 45 850 38250 13387.5 0.35 In-store
Foot Locker Northeast New York New York Men’s Apparel 60 900 54000 16200.0 0.30 In-store
Foot Locker Northeast New York New York Women’s Apparel 50 1000 50000 12500.0 0.25 In-store

PASO 3. Auditoría de calidad de los datos

Antes de analizar verificamos que los datos sean confiables: valores faltantes, coherencia de las variables calculadas, duplicados y consistencia geográfica.

# 1. Valores faltantes
cat("Valores faltantes en toda la base:", sum(is.na(datos)), "\n")
## Valores faltantes en toda la base: 0
# 2. ¿ventas_total = precio x unidades en todos los registros?
cat("ventas_total coincide con precio x unidades:",
    all(abs(datos$ventas_total - datos$precio_unidad * datos$unidades_vendidas) < 1e-6), "\n")
## ventas_total coincide con precio x unidades: TRUE
# 3. ¿margen_operativo = utilidad / ventas? (solo donde hay ventas)
con_ventas <- datos %>% filter(ventas_total > 0)
cat("margen_operativo coincide con utilidad / ventas:",
    all(abs(con_ventas$utilidad_operativa / con_ventas$ventas_total - con_ventas$margen_operativo) < 0.01), "\n")
## margen_operativo coincide con utilidad / ventas: TRUE
# 4. Registros con cero unidades vendidas
datos %>% filter(unidades_vendidas == 0)
distribuidor region estado ciudad producto precio_unidad unidades_vendidas ventas_total utilidad_operativa margen_operativo metodo_venta
Foot Locker Midwest Nebraska Omaha Women’s Athletic Footwear 35 0 0 0 0.40 Outlet
Foot Locker Midwest Nebraska Omaha Women’s Athletic Footwear 30 0 0 0 0.40 Outlet
Foot Locker Midwest Nebraska Omaha Women’s Athletic Footwear 33 0 0 0 0.55 Online
Foot Locker Midwest Nebraska Omaha Women’s Athletic Footwear 27 0 0 0 0.53 Online
# 5. Duplicados exactos
n_dup_extra <- sum(duplicated(datos))
cat("Copias exactas repetidas:", n_dup_extra, "\n")
## Copias exactas repetidas: 262
# 6. Consistencia geográfica: ciudades que aparecen en más de un estado
datos %>% distinct(ciudad, estado) %>% count(ciudad) %>% filter(n > 1)
ciudad n
Charleston 2
Portland 2

Hallazgos de la auditoría y decisiones tomadas:

  • No hay valores faltantes y las variables calculadas (ventas_total y margen_operativo) son coherentes con sus componentes.
  • 4 registros tienen 0 unidades vendidas (todos de Women’s Athletic Footwear, Foot Locker, Omaha). Aportan ventas y utilidad de 0, así que no distorsionan los totales; se conservan.
  • Hay 262 copias exactas de registros (la mayor parte, en Foot Locker). Como la base no trae fecha ni número de factura, no se puede saber si son errores de captura o ventas repetidas legítimas. Decisión: se conservan y se hace una prueba de sensibilidad para verificar que las conclusiones no cambian.
  • La base tiene 50 estados pero 52 ciudades porque Portland (Oregon y Maine) y Charleston (Carolina del Sur y Virginia Occidental) se repiten en estados distintos. Decisión: para el análisis geográfico usamos ubicacion = ciudad, estado, así no se mezclan ciudades distintas.
datos <- datos %>%
  mutate(
    ubicacion = paste(ciudad, estado, sep = ", "),
    distribuidor = as.factor(distribuidor),
    region = as.factor(region),
    producto = as.factor(producto),
    metodo_venta = as.factor(metodo_venta)
  )

# Totales globales que se usan como referencia en todo el informe
ventas_tot  <- sum(datos$ventas_total)
util_tot    <- sum(datos$utilidad_operativa)
margen_glob <- util_tot / ventas_tot
unid_tot    <- sum(datos$unidades_vendidas)

# Paleta y tema visual (mismo código de colores en todo el informe)
col_alto  <- "#0072B2"   # por encima del promedio
col_bajo  <- "#D55E00"   # por debajo del promedio
col_gris  <- "#BFBFBF"
col_negro <- "#111111"
pal_canal <- c("Online" = "#111111", "Outlet" = "#8A8A8A", "In-store" = "#C9C9C9")

theme_adidas <- function(base_size = 14) {
  theme_minimal(base_size = base_size) +
    theme(plot.title = element_text(face = "bold", size = base_size + 2, color = col_negro),
          plot.subtitle = element_text(color = "grey35", size = base_size - 2),
          plot.title.position = "plot",
          panel.grid.minor = element_blank(),
          panel.grid.major = element_line(color = "grey92"),
          axis.title = element_text(color = "grey35", size = base_size - 2),
          legend.position = "bottom",
          legend.title = element_blank())
}

# Resumen por segmento
resumen_seg <- function(df, ...) {
  df %>%
    group_by(...) %>%
    summarise(registros = n(),
              ventas = sum(ventas_total),
              utilidad = sum(utilidad_operativa),
              unidades = sum(unidades_vendidas),
              precio_prom = mean(precio_unidad),
              margen_simple = mean(margen_operativo),
              margen_pond = sum(utilidad_operativa) / sum(ventas_total),
              .groups = "drop") %>%
    mutate(part_ventas = ventas / sum(ventas),
           part_utilidad = utilidad / sum(utilidad)) %>%
    arrange(desc(ventas))
}

formato_seg <- function(df) {
  df %>%
    mutate(across(any_of(c("ventas", "utilidad")), ~ dollar(.x / 1e6, accuracy = 0.1, suffix = "M")),
           across(any_of("unidades"), ~ comma(.x)),
           across(any_of("precio_prom"), ~ dollar(.x, accuracy = 0.01)),
           across(any_of(c("margen_simple", "margen_pond", "part_ventas", "part_utilidad")),
                  ~ percent(.x, accuracy = 0.1)))
}

tabla <- function(df, ...) {
  kable(df, format.args = list(big.mark = ","), ...) %>%
    kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
                  full_width = FALSE)
}

# Gráfico estándar por segmento: % de las ventas vs % de la utilidad.
# Si la barra de utilidad es azul, el segmento aporta más utilidad de lo que vende; si es naranja, menos.
graf_part <- function(df, var, titulo, subtitulo = NULL) {
  d <- df %>%
    mutate(cat = as.character(.data[[var]]),
           etiqueta = paste0(cat, "\n(margen ", percent(margen_pond, accuracy = 0.1), ")"),
           mas = part_utilidad >= part_ventas) %>%
    arrange(ventas)
  d$etiqueta <- factor(d$etiqueta, levels = d$etiqueta)

  niveles <- c("% de la utilidad (aporta más de lo que vende)",
               "% de la utilidad (aporta menos de lo que vende)",
               "% de las ventas")
  largo <- bind_rows(
    d %>% transmute(etiqueta, tipo = "% de las ventas", valor = part_ventas),
    d %>% transmute(etiqueta,
                    tipo = ifelse(mas, niveles[1], niveles[2]),
                    valor = part_utilidad)
  ) %>% mutate(tipo = factor(tipo, levels = niveles))

  ggplot(largo, aes(x = etiqueta, y = valor, fill = tipo)) +
    geom_col(position = position_dodge(width = 0.8), width = 0.75) +
    geom_text(aes(label = percent(valor, accuracy = 0.1)),
              position = position_dodge(width = 0.8), hjust = -0.12, size = 4) +
    coord_flip() +
    scale_y_continuous(labels = percent_format(accuracy = 1), expand = expansion(mult = c(0, 0.15))) +
    scale_fill_manual(values = setNames(c(col_alto, col_bajo, col_gris), niveles), drop = FALSE) +
    labs(title = titulo, subtitle = subtitulo, x = NULL, y = NULL) +
    guides(fill = guide_legend(nrow = 3, reverse = FALSE)) +
    theme_adidas() +
    theme(panel.grid.major.y = element_blank())
}

Prueba de sensibilidad frente a los duplicados.

sin_dup <- distinct(datos)

sens <- bind_rows(
  datos %>% summarise(Escenario = "Con duplicados (base completa)", Registros = n(),
                      Ventas = sum(ventas_total), Utilidad = sum(utilidad_operativa)),
  sin_dup %>% summarise(Escenario = "Sin duplicados exactos", Registros = n(),
                        Ventas = sum(ventas_total), Utilidad = sum(utilidad_operativa))
) %>%
  mutate(`Margen ponderado` = percent(Utilidad / Ventas, accuracy = 0.1),
         Ventas = dollar(Ventas / 1e6, accuracy = 0.1, suffix = "M"),
         Utilidad = dollar(Utilidad / 1e6, accuracy = 0.1, suffix = "M"))
tabla(sens)
Escenario Registros Ventas Utilidad Margen ponderado
Con duplicados (base completa) 9,648 $120.2M $47.2M 39.3%
Sin duplicados exactos 9,386 $114.4M $45.2M 39.5%
orden_con <- resumen_seg(datos, region) %>% arrange(desc(margen_pond)) %>% pull(region) %>% as.character()
orden_sin <- resumen_seg(sin_dup, region) %>% arrange(desc(margen_pond)) %>% pull(region) %>% as.character()
cat("Orden de regiones por margen (con duplicados):", orden_con, "\n")
## Orden de regiones por margen (con duplicados): South Midwest Southeast Northeast West
cat("Orden de regiones por margen (sin duplicados):", orden_sin, "\n")
## Orden de regiones por margen (sin duplicados): South Midwest Southeast Northeast West

Los totales y el ranking de regiones prácticamente no cambian: los duplicados no alteran las conclusiones y se mantiene la base completa.

3. Análisis descriptivo

3.1 Panorama general

$120.2M
Ventas totales
$47.2M
Utilidad operativa
39.3%
Margen operativo ponderado
2,478,861
Unidades vendidas

Por cada dólar que vende Adidas en esta base, quedan $0.39 de utilidad operativa.

Una precisión importante: el margen promedio simple (42.3%) es mayor que el ponderado (39.3%) porque el promedio simple trata igual a una venta pequeña y a una grande. Para hablar de la rentabilidad de un segmento usamos el margen ponderado (utilidad total / ventas totales), que refleja cuánto se gana realmente por cada dólar vendido.

3.2 Medidas de tendencia central y variabilidad

vars <- c(precio_unidad = "Precio por unidad", unidades_vendidas = "Unidades vendidas",
          ventas_total = "Ventas totales", utilidad_operativa = "Utilidad operativa",
          margen_operativo = "Margen operativo")

desc <- datos %>%
  select(all_of(names(vars))) %>%
  pivot_longer(everything(), names_to = "v", values_to = "x") %>%
  group_by(v) %>%
  summarise(Media = mean(x), Mediana = median(x), DE = sd(x), CV = sd(x) / mean(x),
            Min = min(x), Q1 = quantile(x, 0.25), Q3 = quantile(x, 0.75), Max = max(x),
            Asimetria = mean((x - mean(x))^3) / sd(x)^3,
            Atipicos = sum(x < quantile(x, 0.25) - 1.5 * IQR(x) | x > quantile(x, 0.75) + 1.5 * IQR(x)),
            .groups = "drop") %>%
  mutate(`% atípicos` = percent(Atipicos / nrow(datos), accuracy = 0.1),
         Variable = factor(vars[v], levels = vars)) %>%
  arrange(Variable) %>%
  select(Variable, Media, Mediana, DE, CV, Min, Q1, Q3, Max, Asimetria, Atipicos, `% atípicos`)

kable(desc, digits = 2, format.args = list(big.mark = ",")) %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed"), full_width = FALSE)
Variable Media Mediana DE CV Min Q1 Q3 Max Asimetria Atipicos % atípicos
Precio por unidad 45.22 45.00 14.71 0.33 7.0 35.00 55.00 110.0 0.36 104 1.1%
Unidades vendidas 256.93 176.00 214.25 0.83 0.0 106.00 350.00 1,275.0 1.46 508 5.3%
Ventas totales 12,455.08 7,803.50 12,716.39 1.02 0.0 4,065.25 15,864.50 82,500.0 1.96 799 8.3%
Utilidad operativa 4,894.79 3,262.98 4,866.46 0.99 0.0 1,753.44 6,192.36 39,000.0 2.33 694 7.2%
Margen operativo 0.42 0.41 0.10 0.23 0.1 0.35 0.49 0.8 0.23 63 0.7%

Interpretación:

  • Ventas y utilidad son muy asimétricas a la derecha (asimetría ~2 y coeficiente de variación ~1): la media de ventas por registro (~$12.455) es bastante mayor que la mediana (~$7.800). Pocos registros muy grandes elevan el promedio, así que la mediana representa mejor una venta “típica”.
  • El precio y el margen son mucho más estables (CV de ~0,33 y ~0,23): la variabilidad del negocio viene sobre todo del volumen, no del precio.
  • Cerca del 8% de los registros de ventas y el 7% de los de utilidad son atípicos según el criterio del rango intercuartílico. No los eliminamos: son ventas de gran volumen (grandes puntos de venta y líneas fuertes), información legítima para el negocio y no errores.

3.3 Distribución de las ventas, la utilidad y el margen

d1 <- datos %>%
  select(ventas_total, utilidad_operativa) %>%
  pivot_longer(everything(), names_to = "variable", values_to = "valor") %>%
  mutate(variable = factor(variable, levels = c("ventas_total", "utilidad_operativa"),
                           labels = c("Ventas por registro (USD)", "Utilidad por registro (USD)")))

est <- d1 %>% group_by(variable) %>%
  summarise(Mediana = median(valor), Promedio = mean(valor), .groups = "drop") %>%
  pivot_longer(c(Mediana, Promedio), names_to = "medida", values_to = "v")

ggplot(d1, aes(x = valor)) +
  geom_histogram(bins = 40, fill = col_gris, color = "white") +
  geom_vline(data = est, aes(xintercept = v, color = medida), linewidth = 1.3) +
  facet_wrap(~ variable, scales = "free") +
  scale_color_manual(values = c("Mediana" = col_alto, "Promedio" = col_bajo)) +
  scale_x_continuous(labels = dollar) +
  labs(title = paste0("Una venta típica vale ", dollar(median(datos$ventas_total)),
                      ", pero el promedio es ", dollar(mean(datos$ventas_total))),
       subtitle = "Pocas ventas muy grandes elevan el promedio: por eso se usa la mediana como valor típico",
       x = NULL, y = "Número de registros") +
  theme_adidas()

Por qué este gráfico: el histograma muestra de un vistazo la forma de la distribución (la “cola” derecha de ventas grandes) y las dos líneas comparan la mediana con el promedio, que es la forma más simple de evidenciar la asimetría.
q_m <- quantile(datos$margen_operativo, c(0.25, 0.5, 0.75))

ggplot(datos, aes(x = margen_operativo)) +
  geom_histogram(binwidth = 0.025, fill = col_gris, color = "white") +
  geom_vline(xintercept = margen_glob, color = col_bajo, linewidth = 1.3) +
  geom_vline(xintercept = q_m[2], color = col_alto, linewidth = 1.3) +
  scale_x_continuous(labels = percent_format(accuracy = 1)) +
  labs(title = paste0("El margen típico es ", percent(q_m[2], accuracy = 1),
                      " y la mitad de los registros está entre ", percent(q_m[1], accuracy = 1),
                      " y ", percent(q_m[3], accuracy = 1)),
       subtitle = paste0("Línea azul: mediana (", percent(q_m[2], accuracy = 0.1),
                         "). Línea naranja: margen ponderado de la compañía (",
                         percent(margen_glob, accuracy = 0.1), ")"),
       x = "Margen operativo por registro", y = "Número de registros") +
  theme_adidas()

Por qué este gráfico: el margen es un porcentaje y su interés está en cuánto varía de un registro a otro; el histograma responde directamente la pregunta “¿cómo se distribuye el margen y qué tan variable es?”. A diferencia de las ventas, es una distribución casi simétrica y poco dispersa.
ggplot(datos, aes(x = fct_reorder(metodo_venta, margen_operativo, .fun = median), y = margen_operativo,
                  fill = metodo_venta)) +
  geom_boxplot(outlier.alpha = 0.25, outlier.size = 1, width = 0.6) +
  geom_hline(yintercept = margen_glob, linetype = "dashed", color = col_bajo, linewidth = 1) +
  coord_flip() +
  scale_fill_manual(values = pal_canal, guide = "none") +
  scale_y_continuous(labels = percent_format(accuracy = 1)) +
  labs(title = "Online tiene los márgenes más altos; In-store, los más bajos",
       subtitle = "La caja muestra el 50% central de los registros; la línea punteada es el margen promedio de la compañía",
       x = NULL, y = "Margen operativo por registro") +
  theme_adidas() +
  theme(panel.grid.major.y = element_blank())

Por qué este gráfico: el boxplot permite comparar la distribución completa del margen entre canales (mediana, dispersión y atípicos) en un solo vistazo, algo que un promedio por sí solo no muestra.

3.4 Desempeño por segmento: ¿dónde se vende y dónde se gana?

En estos gráficos, cada segmento tiene dos barras: qué porcentaje de las ventas totales representa (gris) y qué porcentaje de la utilidad total aporta. Si la barra de utilidad es azul, el segmento aporta más utilidad de lo que vende; si es naranja, aporta menos. Entre paréntesis está su margen ponderado.

Por producto

seg_prod <- resumen_seg(datos, producto)
graf_part(seg_prod, "producto", "Men's Street Footwear lidera tanto en ventas como en rentabilidad",
          paste0("Margen promedio de la compañía: ", percent(margen_glob, accuracy = 0.1)))

Por qué este gráfico: comparar el % de ventas con el % de utilidad de cada producto muestra directamente quién “rinde” más de lo que pesa, sin tener que interpretar escalas de dinero ni colores.
seg_prod %>%
  select(producto, registros, ventas, part_ventas, utilidad, part_utilidad, precio_prom, margen_pond) %>%
  formato_seg() %>%
  tabla(col.names = c("Producto", "Registros", "Ventas", "% ventas", "Utilidad", "% utilidad",
                      "Precio prom.", "Margen ponderado"))
Producto Registros Ventas % ventas Utilidad % utilidad Precio prom. Margen ponderado
Men’s Street Footwear 1,610 $27.7M 23.0% $11.6M 24.6% $44.24 42.0%
Women’s Apparel 1,608 $23.9M 19.9% $9.7M 20.5% $51.60 40.6%
Men’s Athletic Footwear 1,610 $20.6M 17.1% $7.4M 15.7% $43.78 36.1%
Women’s Street Footwear 1,608 $17.2M 14.3% $6.5M 13.8% $40.25 37.8%
Men’s Apparel 1,606 $16.5M 13.7% $6.4M 13.5% $50.32 38.6%
Women’s Athletic Footwear 1,606 $14.3M 11.9% $5.6M 11.9% $41.11 39.1%

Men’s Street Footwear aporta cerca del 23% de las ventas y el 25% de la utilidad, con el mejor margen (~42%). Women’s Apparel es el segundo en ventas (~20%) con un margen sólido (~41%). En el otro extremo, Men’s Athletic Footwear tiene el menor margen (~36%), seguido de Women’s Street Footwear (~38%): el calzado deportivo de hombre es el tercer producto en ventas (17%) pero deja proporcionalmente menos utilidad (15,8%).

Por región

seg_reg <- resumen_seg(datos, region)
graf_part(seg_reg, "region", "West vende más, pero aporta menos utilidad de lo que vende",
          "South, en cambio, aporta más utilidad de la que representa en ventas")

Por qué este gráfico: es el mismo formato que el de productos para que la comparación sea directa. La brecha entre las dos barras de cada región es, literalmente, la diferencia entre “vender” y “ganar”.
seg_reg %>%
  select(region, registros, ventas, part_ventas, utilidad, part_utilidad, precio_prom, margen_pond) %>%
  formato_seg() %>%
  tabla(col.names = c("Región", "Registros", "Ventas", "% ventas", "Utilidad", "% utilidad",
                      "Precio prom.", "Margen ponderado"))
Región Registros Ventas % ventas Utilidad % utilidad Precio prom. Margen ponderado
West 2,448 $36.4M 30.3% $13.0M 27.6% $49.94 35.7%
Northeast 2,376 $25.1M 20.9% $9.7M 20.6% $46.69 38.8%
Southeast 1,224 $21.4M 17.8% $8.4M 17.8% $50.18 39.3%
South 1,728 $20.6M 17.1% $9.2M 19.5% $38.24 44.8%
Midwest 1,872 $16.7M 13.9% $6.9M 14.5% $40.36 41.1%

Es uno de los hallazgos más relevantes: West aporta el 30% de las ventas pero solo el 27,6% de la utilidad, con el margen más bajo de la compañía (~35,7%). South aporta el 17% de las ventas y casi el 19,5% de la utilidad, con el margen más alto (~44,8%). La región más grande no es la más rentable, y esa brecha de ~9 puntos de margen entre South y West es una oportunidad clara.

Por distribuidor

seg_dist <- resumen_seg(datos, distribuidor)
graf_part(seg_dist, "distribuidor", "Sports Direct deja el mayor margen por cada dólar vendido",
          "West Gear y Foot Locker concentran más de la mitad de las ventas")

Por qué este gráfico: permite ver a la vez el tamaño de cada cliente (barra gris) y si ese tamaño se traduce en utilidad (barra de color), que es la información que necesita un gerente comercial para priorizar cuentas.

West Gear (27%) y Foot Locker (24%) concentran más de la mitad de las ventas. Sports Direct destaca por rentabilidad: con el 20,5% de las ventas logra el mayor margen (~43,2%). Walmart (~37,1%) y West Gear (~37,6%) tienen los márgenes más bajos; para West Gear esto pesa especialmente por su enorme volumen.

Por método de venta

seg_met <- resumen_seg(datos, metodo_venta)
graf_part(seg_met, "metodo_venta", "Online: el canal más grande y el más rentable",
          "In-store es el canal con menor margen")

Por qué este gráfico: con solo tres canales, el contraste entre volumen y utilidad se ve inmediatamente: Online es el único que aporta más utilidad de la que representa en ventas.

Online genera el 37,4% de las ventas, tiene el mejor margen (~43,5%) y aporta el 41,4% de la utilidad. In-store tiene el menor margen (~35,8%) y el precio promedio más alto ($48,8), lo que sugiere que el canal físico tiene costos o descuentos que le restan rentabilidad. Outlet queda en un punto intermedio (~37,7%).

Por ubicación (ciudad, estado)

seg_ubi <- resumen_seg(datos, ubicacion)

tab_ubi <- function(df) {
  df %>% select(ubicacion, ventas, part_ventas, margen_pond) %>%
    formato_seg() %>%
    tabla(col.names = c("Ubicación", "Ventas", "% ventas", "Margen ponderado"))
}

# Las 10 ubicaciones con más ventas
seg_ubi %>% slice_head(n = 10) %>% tab_ubi()
Ubicación Ventas % ventas Margen ponderado
New York, New York $5.7M 4.7% 37.3%
San Francisco, California $4.9M 4.1% 32.1%
Orlando, Florida $3.9M 3.3% 34.0%
Miami, Florida $3.9M 3.2% 40.8%
Los Angeles, California $3.7M 3.0% 37.7%
Houston, Texas $3.6M 3.0% 41.2%
Charleston, South Carolina $3.6M 3.0% 40.9%
New Orleans, Louisiana $3.4M 2.8% 42.2%
Seattle, Washington $3.2M 2.7% 28.8%
Richmond, Virginia $3.1M 2.6% 38.2%

Ubicaciones con ventas superiores a $1M y menor margen:

seg_ubi %>% filter(ventas >= 1e6) %>% arrange(margen_pond) %>% slice_head(n = 5) %>% tab_ubi()
Ubicación Ventas % ventas Margen ponderado
Honolulu, Hawaii $2.7M 2.3% 28.5%
Seattle, Washington $3.2M 2.7% 28.8%
San Francisco, California $4.9M 4.1% 32.1%
Anchorage, Alaska $1.8M 1.5% 32.7%
Boston, Massachusetts $1.6M 1.3% 32.8%

Ubicaciones con ventas superiores a $1M y mayor margen:

seg_ubi %>% filter(ventas >= 1e6) %>% arrange(desc(margen_pond)) %>% slice_head(n = 5) %>% tab_ubi()
Ubicación Ventas % ventas Margen ponderado
Birmingham, Alabama $2.5M 2.1% 54.4%
Knoxville, Tennessee $2.6M 2.1% 49.5%
Detroit, Michigan $2.3M 1.9% 45.9%
Dallas, Texas $3.0M 2.5% 44.8%
Boise, Idaho $2.7M 2.3% 44.6%

Ninguna ubicación supera el 5% de las ventas (la mayor, Nueva York, aporta ~4,7%), así que la compañía no depende de una sola ciudad. Sí hay diferencias de rentabilidad: Honolulu, Seattle y San Francisco tienen márgenes de 28-32%, todas del oeste, mientras que Birmingham (Alabama) y Knoxville (Tennessee), en el sur, llegan a ~54% y ~50%. Es coherente con el patrón regional: el oeste vende con precios altos y menor margen; el sur, con precios más bajos y mayor margen. Se usan tablas y no gráficos porque son 52 ubicaciones: un gráfico sería ilegible.

4. Análisis diagnóstico: ¿por qué pasan estas diferencias?

4.1 ¿Qué se asocia más con la utilidad?

etiquetas <- c("Precio", "Unidades", "Ventas", "Utilidad", "Margen")
mc <- datos %>%
  select(precio_unidad, unidades_vendidas, ventas_total, utilidad_operativa, margen_operativo) %>%
  cor()
dimnames(mc) <- list(etiquetas, etiquetas)

r_util <- data.frame(variable = c("Ventas totales", "Unidades vendidas", "Precio por unidad", "Margen operativo"),
                     r = mc["Utilidad", c("Ventas", "Unidades", "Precio", "Margen")])

ggplot(r_util, aes(x = fct_reorder(variable, r), y = r, fill = r > 0)) +
  geom_col(width = 0.65) +
  geom_text(aes(label = sprintf("%.2f", r), hjust = ifelse(r >= 0, -0.15, 1.15)), size = 5) +
  coord_flip() +
  scale_fill_manual(values = c("TRUE" = col_alto, "FALSE" = col_bajo), guide = "none") +
  scale_y_continuous(limits = c(-0.2, 1.1)) +
  labs(title = "La utilidad se explica sobre todo por cuánto se vende",
       subtitle = "Correlación de Pearson (r) de cada variable con la utilidad operativa",
       x = NULL, y = "Correlación con la utilidad") +
  theme_adidas() +
  theme(panel.grid.major.y = element_blank())

Por qué este gráfico: la pregunta de la guía es “¿qué variables se asocian más con la utilidad?”. Un gráfico de barras con una sola columna de correlaciones la responde directo; la matriz completa está en la tabla de abajo por si se necesita el detalle.
kable(round(mc, 2)) %>%
  kable_styling(bootstrap_options = c("striped", "condensed"), full_width = FALSE)
Precio Unidades Ventas Utilidad Margen
Precio 1.00 0.27 0.54 0.50 -0.14
Unidades 0.27 1.00 0.92 0.87 -0.31
Ventas 0.54 0.92 1.00 0.94 -0.30
Utilidad 0.50 0.87 0.94 1.00 -0.05
Margen -0.14 -0.31 -0.30 -0.05 1.00
  • Ventas y utilidad: r ≈ 0,94. La utilidad se explica casi por completo por cuánto se vende; las unidades vendidas también tienen una asociación fuerte (0,87).
  • El precio se asocia de forma moderada con la utilidad (0,50) y solo débilmente con las unidades (+0,27).
  • El margen casi no se relaciona con la utilidad total (-0,05) y se relaciona negativamente con el volumen (-0,30 con unidades y con ventas): la utilidad depende del volumen, no de qué tan alto sea el margen porcentual del registro.

4.2 Relación entre ventas y utilidad

mod <- lm(utilidad_operativa ~ ventas_total, data = datos)
r2  <- summary(mod)$r.squared

ggplot(datos, aes(x = ventas_total, y = utilidad_operativa)) +
  geom_point(alpha = 0.12, color = col_negro, size = 1.3) +
  geom_smooth(method = "lm", color = col_alto, se = FALSE, linewidth = 1.6) +
  scale_x_continuous(labels = dollar) + scale_y_continuous(labels = dollar) +
  labs(title = paste0("A más ventas, más utilidad: casi en línea recta (r = ",
                      round(cor(datos$ventas_total, datos$utilidad_operativa), 2), ")"),
       subtitle = "Cada punto es un registro de venta; la línea azul es la tendencia promedio",
       x = "Ventas totales (USD)", y = "Utilidad operativa (USD)") +
  theme_adidas()

Por qué este gráfico: el diagrama de dispersión es la herramienta estándar para mostrar la relación entre dos variables numéricas; la línea de tendencia resume esa relación y los puntos alejados de ella son los registros más (o menos) rentables de lo normal.

El modelo lineal indica que cada dólar adicional de venta aporta ~0.36 dólares de utilidad, y que las ventas explican cerca del 87% de la variabilidad de la utilidad. La dispersión alrededor de la línea es donde está la oportunidad: a igual nivel de ventas, hay registros que ganan mucho más que otros, y eso se explica por el margen (segmento, canal, región).

4.3 Precio, volumen y rentabilidad

Las preguntas de la guía son si precios más altos implican menor volumen y si el precio influye en la rentabilidad. Agrupamos los registros por banda de precio para responderlas de forma simple:

datos <- datos %>%
  mutate(banda_precio = cut(precio_unidad, breaks = c(0, 30, 40, 50, 60, Inf),
                            labels = c("≤ $30", "$31-40", "$41-50", "$51-60", "> $60")))

bandas <- datos %>% group_by(banda_precio) %>%
  summarise(registros = n(), unidades_prom = mean(unidades_vendidas),
            ventas = sum(ventas_total), utilidad = sum(utilidad_operativa),
            margen_pond = sum(utilidad_operativa) / sum(ventas_total), .groups = "drop")

b_long <- bandas %>%
  transmute(banda_precio,
            `Unidades vendidas por registro (promedio)` = unidades_prom,
            `Margen operativo ponderado` = margen_pond) %>%
  pivot_longer(-banda_precio, names_to = "indicador", values_to = "valor") %>%
  mutate(etiqueta = ifelse(grepl("Margen", indicador), percent(valor, accuracy = 0.1), comma(valor, accuracy = 1)))

ggplot(b_long, aes(x = banda_precio, y = valor)) +
  geom_col(fill = col_gris, width = 0.7) +
  geom_col(data = b_long %>% filter(banda_precio == "> $60"), fill = col_bajo, width = 0.7) +
  geom_text(aes(label = etiqueta), vjust = -0.4, size = 4.2) +
  facet_wrap(~ indicador, scales = "free_y") +
  scale_y_continuous(expand = expansion(mult = c(0, 0.18)), labels = NULL) +
  labs(title = "Los precios altos venden más unidades, pero con menos margen",
       subtitle = "Banda de precio > $60 en naranja: mayor volumen por registro y el menor margen",
       x = "Precio por unidad", y = NULL) +
  theme_adidas() +
  theme(panel.grid = element_blank(), strip.text = element_text(face = "bold"))

Por qué este gráfico: en lugar de una nube de 9.648 puntos entre precio y unidades (difícil de leer), agrupar por banda de precio muestra la misma relación con solo cinco barras y permite ver a la vez el efecto sobre el volumen y sobre el margen.
bandas %>%
  mutate(unidades_prom = round(unidades_prom, 1),
         ventas = dollar(ventas / 1e6, accuracy = 0.1, suffix = "M"),
         utilidad = dollar(utilidad / 1e6, accuracy = 0.1, suffix = "M"),
         margen_pond = percent(margen_pond, accuracy = 0.1)) %>%
  tabla(col.names = c("Banda de precio", "Registros", "Unidades prom.", "Ventas", "Utilidad", "Margen ponderado"))
Banda de precio Registros Unidades prom. Ventas Utilidad Margen ponderado
≤ $30 1,445 188.4 $6.5M $2.7M 41.9%
$31-40 2,391 225.8 $19.6M $7.9M 40.6%
$41-50 2,656 249.6 $30.9M $12.4M 40.2%
$51-60 1,796 280.0 $28.1M $11.3M 40.1%
> $60 1,360 368.3 $35.1M $12.9M 36.7%

¿Precios más altos implican menor volumen? No: los datos muestran lo contrario (r = +0,27 entre precio y unidades). Pero esto no significa que subir precios aumente las ventas. Es una correlación entre registros distintos, no un experimento; lo más probable es que refleje el mix de productos y puntos de venta (los registros de precio alto son de puntos de venta de mayor tráfico o posicionamiento). Para verificar que no es un efecto de mezclar productos o canales, revisamos la relación dentro de cada uno:

cor_prod <- datos %>% group_by(Segmento = as.character(producto)) %>%
  summarise(`r precio-unidades` = cor(precio_unidad, unidades_vendidas),
            `r precio-margen` = cor(precio_unidad, margen_operativo), .groups = "drop")
cor_met <- datos %>% group_by(Segmento = as.character(metodo_venta)) %>%
  summarise(`r precio-unidades` = cor(precio_unidad, unidades_vendidas),
            `r precio-margen` = cor(precio_unidad, margen_operativo), .groups = "drop")

bind_rows(cor_prod, cor_met) %>%
  kable(digits = 2) %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed"), full_width = FALSE) %>%
  pack_rows("Por producto", 1, 6) %>%
  pack_rows("Por método de venta", 7, 9)
Segmento r precio-unidades r precio-margen
Por producto
Men’s Apparel 0.31 -0.08
Men’s Athletic Footwear 0.33 -0.22
Men’s Street Footwear 0.25 -0.03
Women’s Apparel 0.27 -0.28
Women’s Athletic Footwear 0.34 -0.18
Women’s Street Footwear 0.30 -0.11
Por método de venta
In-store 0.36 -0.10
Online 0.15 -0.09
Outlet 0.39 -0.29

La relación positiva se repite en todos los productos y canales (entre +0,15 y +0,39). Con esta base no es recomendable usar el precio como palanca de volumen; habría que probarlo con experimentos controlados.

¿El precio influye en la rentabilidad? Sí, pero en sentido contrario al que podría esperarse: la banda más cara (> $60) tiene el menor margen (~36,7%) frente a ~41,9% de la más barata (≤ $30), y la correlación entre precio y margen es negativa (r = -0,14). Esa banda vende bastante más unidades por registro (~368 frente a ~188), lo que sugiere que en los precios altos se está “comprando” volumen con margen (posibles descuentos, promociones o costos más altos). Aquí se ve el patrón general del negocio: vender más no implica ganar mejor (el margen se correlaciona negativamente con el volumen, r = -0,30).

4.4 ¿Las diferencias de margen son estadísticamente relevantes?

Como apoyo al diagnóstico, comparamos la distribución del margen entre grupos con la prueba no paramétrica de Kruskal-Wallis (el margen no es normal ni simétrico).

kw <- lapply(c("metodo_venta", "region", "producto", "distribuidor"), function(v) {
  t <- kruskal.test(datos$margen_operativo ~ datos[[v]])
  data.frame(Factor = v, Chi2 = unname(t$statistic), gl = unname(t$parameter), p_valor = t$p.value)
}) %>% bind_rows() %>%
  mutate(Factor = recode(Factor, metodo_venta = "Método de venta", region = "Región",
                         producto = "Producto", distribuidor = "Distribuidor"),
         p_valor = ifelse(p_valor < 0.001, "< 0.001", as.character(round(p_valor, 3))))

kable(kw, digits = 1) %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed"), full_width = FALSE)
Factor Chi2 gl p_valor
Método de venta 2112.0 2 < 0.001
Región 520.0 4 < 0.001
Producto 288.6 5 < 0.001
Distribuidor 90.9 5 < 0.001

En los cuatro casos el valor-p es menor a 0,001: las diferencias de margen entre métodos de venta, regiones, productos y distribuidores no son producto del azar; la más marcada es la del método de venta.

4.5 ¿Por qué West tiene menor margen? Diagnóstico por canal

reg_met <- resumen_seg(datos, region, metodo_venta) %>%
  mutate(metodo_venta = factor(metodo_venta, levels = c("Online", "Outlet", "In-store")),
         region = factor(region, levels = c("Northeast", "Midwest", "Southeast", "South", "West")))

ggplot(reg_met, aes(x = region, y = margen_pond, fill = metodo_venta)) +
  geom_col(position = position_dodge(width = 0.85), width = 0.8) +
  geom_text(aes(label = percent(margen_pond, accuracy = 1)),
            position = position_dodge(width = 0.85), vjust = -0.4, size = 3.8) +
  geom_hline(yintercept = margen_glob, linetype = "dashed", color = col_bajo, linewidth = 1) +
  scale_fill_manual(values = pal_canal) +
  scale_y_continuous(labels = percent_format(accuracy = 1), expand = expansion(mult = c(0, 0.12))) +
  labs(title = "En West, Outlet e In-store rinden poco; su canal Online sí rinde",
       subtitle = paste0("Margen ponderado por región y canal. Línea punteada: promedio de la compañía (",
                         percent(margen_glob, accuracy = 0.1), ")"),
       x = NULL, y = "Margen ponderado") +
  theme_adidas() +
  theme(panel.grid.major.x = element_blank())

Por qué este gráfico: las barras agrupadas permiten comparar, dentro de cada región, qué canal rinde más, y a la vez comparar el mismo canal entre regiones. Es más fácil de leer que un mapa de calor de 15 celdas.
reg_met %>%
  group_by(region) %>% mutate(part_region = ventas / sum(ventas)) %>% ungroup() %>%
  arrange(region, metodo_venta) %>%
  select(region, metodo_venta, ventas, part_region, margen_pond) %>%
  mutate(ventas = dollar(ventas / 1e6, accuracy = 0.1, suffix = "M"),
         part_region = percent(part_region, accuracy = 0.1),
         margen_pond = percent(margen_pond, accuracy = 0.1)) %>%
  tabla(col.names = c("Región", "Método", "Ventas", "% de las ventas de la región", "Margen ponderado"))
Región Método Ventas % de las ventas de la región Margen ponderado
Northeast Online $4.6M 18.4% 48.6%
Northeast Outlet $8.9M 35.3% 36.5%
Northeast In-store $11.6M 46.2% 36.7%
Midwest Online $7.1M 42.7% 44.0%
Midwest Outlet $3.6M 21.6% 39.2%
Midwest In-store $6.0M 35.7% 38.9%
Southeast Online $12.1M 56.5% 42.1%
Southeast Outlet $2.1M 9.7% 36.4%
Southeast In-store $7.2M 33.9% 35.4%
South Online $9.2M 44.7% 45.1%
South Outlet $11.1M 53.7% 44.6%
South In-store $0.3M 1.6% 39.7%
West Online $12.0M 32.8% 41.4%
West Outlet $13.9M 38.3% 32.8%
West In-store $10.5M 28.9% 33.2%

Hipótesis que surgen:

  • West: su canal Online rinde bien (~41%), pero Outlet (~32,8%) e In-store (~33,2%) están entre los menos rentables de toda la compañía, y pesan ~67% de las ventas de la región. El problema no es “West” en general sino cómo se vende en tienda y en outlet en West. Además, el outlet de West es la celda de mayor venta del cruce región × canal ($13,9M).
  • Northeast: su mejor canal es Online (~48,6%, el margen más alto de todo el cruce), pero Online es solo ~18% de sus ventas, mientras In-store (~46%) rinde ~36,7%. Es una oportunidad de mix.
  • South: rinde bien en casi todos los canales (44-45% en Outlet y Online) y In-store es casi inexistente (< 2% de sus ventas).

5. Combinaciones estratégicas

Producto x región

celdas <- resumen_seg(datos, producto, region) %>%
  mutate(celda = paste(producto, region, sep = " - "))

top10 <- celdas %>%
  slice_max(ventas, n = 10) %>%
  mutate(dif_pp = (margen_pond - margen_glob) * 100,
         estado = ifelse(margen_pond >= margen_glob, "Por encima del promedio", "Por debajo del promedio"),
         etiqueta = paste0(celda, "  (", dollar(ventas / 1e6, accuracy = 0.1, suffix = "M"), ")"))
top10$etiqueta <- factor(top10$etiqueta, levels = rev(top10$etiqueta))
n_bajo <- sum(top10$margen_pond < margen_glob)

ggplot(top10, aes(x = etiqueta, y = dif_pp, fill = estado)) +
  geom_col(width = 0.7) +
  geom_hline(yintercept = 0, color = col_negro) +
  geom_text(aes(label = percent(margen_pond, accuracy = 0.1),
                hjust = ifelse(dif_pp >= 0, -0.15, 1.15)), size = 4.2) +
  coord_flip() +
  scale_fill_manual(values = c("Por encima del promedio" = col_alto, "Por debajo del promedio" = col_bajo)) +
  scale_y_continuous(limits = c(-13, 9)) +
  labs(title = paste0("De las 10 combinaciones que más venden, ", n_bajo, " rinden por debajo del promedio"),
       subtitle = paste0("Barras: puntos porcentuales frente al margen promedio (", percent(margen_glob, accuracy = 0.1),
                         "). Entre paréntesis: ventas de la combinación"),
       x = NULL, y = "Diferencia de margen frente al promedio de la compañía (puntos porcentuales)") +
  theme_adidas() +
  theme(panel.grid.major.y = element_blank())

Por qué este gráfico: las 30 combinaciones producto-región son demasiadas para un gráfico legible; nos concentramos en las 10 que más venden (las que más mueven el resultado) y mostramos solo si están por encima o por debajo del promedio, que es la decisión que le importa a la gerencia.

Lectura estratégica:

  • A proteger: Men’s Street Footwear en West es la combinación más grande (~$7,4M) con un margen en el promedio (~39,3%); en Northeast rinde ~44%. Women’s Apparel en South (~$4,2M) tiene el margen más alto entre las combinaciones relevantes (~52%).
  • A revisar primero: Women’s Apparel en West es la segunda combinación más grande de la compañía (~$7,0M) y rinde solo ~29,8%; Men’s Athletic Footwear en West (~$6,8M) rinde ~31,9%. Son dos celdas grandes con márgenes muy por debajo del promedio, y ambas están en West.

Producto x método de venta

prod_met <- resumen_seg(datos, producto, metodo_venta) %>%
  mutate(metodo_venta = factor(metodo_venta, levels = c("Online", "Outlet", "In-store")))

ggplot(prod_met, aes(x = margen_pond, y = fct_reorder(producto, ventas, .fun = sum))) +
  geom_line(aes(group = producto), color = "grey75", linewidth = 1.6) +
  geom_vline(xintercept = margen_glob, linetype = "dashed", color = col_bajo, linewidth = 1) +
  geom_point(aes(color = metodo_venta), size = 6) +
  scale_color_manual(values = pal_canal) +
  scale_x_continuous(labels = percent_format(accuracy = 1)) +
  labs(title = "En los seis productos, Online es el canal más rentable",
       subtitle = paste0("Cada punto es el margen ponderado del producto en un canal. Línea punteada: promedio (",
                         percent(margen_glob, accuracy = 0.1), ")"),
       x = "Margen ponderado", y = NULL) +
  theme_adidas() +
  theme(panel.grid.major.y = element_blank())

Por qué este gráfico: el gráfico de puntos conectados (dumbbell) hace visible la “distancia” de margen entre el mejor y el peor canal de cada producto, que es justamente lo que se quiere comparar.

En los seis productos, Online es el canal más rentable, y In-store es el menos rentable en cinco de ellos (en Men’s Athletic Footwear, Outlet e In-store quedan empatados en ~33%). Los mejores casos son Women’s Apparel y Men’s Street Footwear en Online (~45-46% de margen y entre $9M y $10,4M de ventas). Los peores son el calzado en tienda física: Women’s Street Footwear In-store (~32,5%), Men’s Athletic (~33%) y Women’s Athletic (~33,5%). El canal importa tanto como el producto.

Distribuidor x método de venta (las 6 combinaciones con mayores ventas)

resumen_seg(datos, distribuidor, metodo_venta) %>%
  slice_head(n = 6) %>%
  select(distribuidor, metodo_venta, ventas, part_ventas, margen_pond) %>%
  formato_seg() %>%
  tabla(col.names = c("Distribuidor", "Método", "Ventas", "% ventas", "Margen ponderado"))
Distribuidor Método Ventas % ventas Margen ponderado
West Gear In-store $15.7M 13.0% 35.1%
Foot Locker Online $12.2M 10.2% 42.4%
Sports Direct Online $10.0M 8.3% 45.1%
West Gear Online $9.5M 7.9% 44.5%
Foot Locker Outlet $9.1M 7.6% 36.4%
Sports Direct Outlet $9.1M 7.6% 44.6%

La combinación más grande es West Gear In-store (~$15,7M, 13% de las ventas totales) con solo ~35,1% de margen. En contraste, Sports Direct Online rinde ~45,1% y West Gear Online ~44,5%. Mover parte del volumen de West Gear de tienda física a online sería la palanca de rentabilidad más grande a nivel de un solo cliente.

6. Principales hallazgos

  1. Escala y rentabilidad: ventas de $120.2M, utilidad de $47.2M y margen ponderado de 39.3%. La utilidad depende del volumen (r = 0,94 con ventas), no del margen del registro.
  2. Distribución sesgada: el negocio se apoya en pocas transacciones muy grandes (media > mediana, ~8% de atípicos legítimos). Se deben usar mediana y margen ponderado, no promedios simples.
  3. El producto líder también es el más rentable: Men’s Street Footwear (23% de ventas, ~42% de margen). Men’s Athletic Footwear tiene el margen más bajo (~36%).
  4. La región más grande no es la más rentable: West (30% de ventas, 35,7% de margen) frente a South (17% de ventas, 44,8% de margen).
  5. Online es el mejor canal: 37% de las ventas, ~43,5% de margen y 41% de la utilidad. In-store es el más débil (~35,8%). Las diferencias son estadísticamente significativas.
  6. El problema de West es principalmente de canal: su Outlet e In-store rinden ~33% mientras su Online rinde ~41%.
  7. Precio y volumen: la relación entre precio y unidades es positiva (no negativa) en todos los segmentos; refleja el mix y no permite concluir que subir precios aumente ventas. Los precios altos (> $60) tienen el menor margen (~36,7%).
  8. Celdas críticas: Women’s Apparel en West (~$7,0M, ~29,8% de margen) y Men’s Athletic Footwear en West (~$6,8M, ~31,9%) son grandes y poco rentables; Women’s Apparel en South (~52%) es la más rentable.
  9. Oportunidad de mix en Northeast: su canal Online tiene el mayor margen del cruce región-canal (~48,6%) y solo pesa ~18% de sus ventas.

Lectura financiera para la gerencia

w <- datos %>% filter(region == "West")
resto <- datos %>% filter(region != "West")
m_west  <- sum(w$utilidad_operativa) / sum(w$ventas_total)
m_resto <- sum(resto$utilidad_operativa) / sum(resto$ventas_total)
brecha_west <- sum(w$ventas_total) * (m_resto - m_west)

onl <- seg_met %>% filter(metodo_venta == "Online")
  • Cada dólar vendido deja $0.39 de utilidad operativa, y esa cifra esconde diferencias grandes: de 35.7% en la región menos rentable a 44.8% en la más rentable.
  • West vende $36.4M con un margen de 35.7%; el resto de regiones rinde 40.9%. Si West rindiera lo mismo que el resto, la utilidad sería $1.9M mayor (4.0% de la utilidad actual) sin vender un dólar más.
  • Online genera el 37.4% de las ventas pero el 41.4% de la utilidad: cada punto de mix que se traslada hacia Online mejora el resultado sin necesidad de crecer en volumen.

7. Recomendaciones (analítica prescriptiva)

Las recomendaciones se basan en la evidencia anterior. Como la base no incluye costos, descuentos ni fechas, cada una debe verse como una hipótesis a validar con información interna de Adidas antes de ejecutarse.

cierre <- 0.5

esc <- function(seg, ref, cierre = 0.5) {
  m_seg <- sum(seg$utilidad_operativa) / sum(seg$ventas_total)
  m_ref <- sum(ref$utilidad_operativa) / sum(ref$ventas_total)
  list(ventas = sum(seg$ventas_total), m_seg = m_seg, m_ref = m_ref,
       ganancia = sum(seg$ventas_total) * (m_ref - m_seg) * cierre)
}

# A: West - Outlet cierra la mitad de su brecha frente al Outlet del resto del país
A <- esc(datos %>% filter(region == "West", metodo_venta == "Outlet"),
         datos %>% filter(region != "West", metodo_venta == "Outlet"), cierre)

# B: Women's Apparel en West cierra la mitad de su brecha frente al resto de regiones
B <- esc(datos %>% filter(region == "West", producto == "Women's Apparel"),
         datos %>% filter(region != "West", producto == "Women's Apparel"), cierre)

# C: West Gear traslada el 10% de sus ventas In-store al canal Online
wg_ins <- datos %>% filter(distribuidor == "West Gear", metodo_venta == "In-store")
wg_onl <- datos %>% filter(distribuidor == "West Gear", metodo_venta == "Online")
traslado <- 0.10
C <- list(ventas = sum(wg_ins$ventas_total),
          m_seg = sum(wg_ins$utilidad_operativa) / sum(wg_ins$ventas_total),
          m_ref = sum(wg_onl$utilidad_operativa) / sum(wg_onl$ventas_total))
C$ganancia <- C$ventas * traslado * (C$m_ref - C$m_seg)

escenarios <- data.frame(
  Escenario = c("A. West - Outlet: cierra 50% de la brecha frente al Outlet del resto del país",
                "B. Women's Apparel en West: cierra 50% de la brecha frente al resto de regiones",
                "C. West Gear: traslada 10% de su venta In-store a Online"),
  `Ventas del segmento` = dollar(c(A$ventas, B$ventas, C$ventas) / 1e6, accuracy = 0.1, suffix = "M"),
  `Margen actual` = percent(c(A$m_seg, B$m_seg, C$m_seg), accuracy = 0.1),
  `Margen de referencia` = percent(c(A$m_ref, B$m_ref, C$m_ref), accuracy = 0.1),
  `Utilidad adicional` = dollar(c(A$ganancia, B$ganancia, C$ganancia) / 1e6, accuracy = 0.01, suffix = "M"),
  check.names = FALSE
)
total_esc <- A$ganancia + B$ganancia + C$ganancia
# Recomendación Evidencia Indicador de seguimiento
1 Revisar precios, descuentos y costos en los canales Outlet e In-store de West, empezando por Women’s Apparel y Men’s Athletic Footwear. West: 30% de ventas y solo ~35,7% de margen; Outlet ~32,8%, In-store ~33,2%; Women’s Apparel West ~29,8% Margen ponderado West Outlet e In-store
2 Impulsar el canal Online en Northeast y en las cuentas con mayor peso en tienda física (West Gear, Foot Locker). Online es el canal más rentable en los 6 productos; Northeast Online ~48,6% de margen con solo ~18% del mix % de ventas online por región y margen del canal
3 Replicar en otras regiones las prácticas de South (mix, precios y estructura de canal). South: margen ~44,8% con el precio promedio más bajo ($38) Margen ponderado por región
4 Priorizar la relación comercial con Sports Direct y renegociar condiciones con los clientes de menor rentabilidad (Walmart, West Gear en tienda). Sports Direct ~43,2% de margen; Walmart ~37,1%; West Gear In-store ~35,1% con $15,7M de ventas Margen por distribuidor y por distribuidor x canal
5 Proteger Men’s Street Footwear (la de mayor venta y margen) y revisar la estructura de costos y precios de Men’s Athletic Footwear. Men’s Street 23% de ventas y ~42% de margen; Men’s Athletic ~36% (el menor) Margen por producto
6 No usar el precio como palanca de volumen sin una prueba controlada. Diseñar experimentos por tienda o canal antes de mover precios. Correlación positiva precio-unidades en todos los segmentos, que no permite inferir causalidad Resultado del piloto (unidades y margen)
7 Mejorar la base de datos: incorporar fecha, costos, descuentos e inventario. La base actual no permite medir crecimiento ni identificar causas Existencia y calidad de las nuevas variables

Impacto financiero ilustrativo. Para dimensionar el potencial de las recomendaciones 1, 2 y 4, calculamos cuánta utilidad adicional se generaría en tres escenarios conservadores, sin vender una sola unidad adicional: dos segmentos de West que cierran solo la mitad de su brecha de margen frente al resto de la compañía, y un cambio de mix en West Gear (el mayor cliente en tienda física) hacia el canal online.

esc_df <- data.frame(
  escenario = c("A. West Outlet: mejora de margen", "B. Women's Apparel West: mejora de margen",
                "C. West Gear: 10% de In-store a Online"),
  ganancia = c(A$ganancia, B$ganancia, C$ganancia) / 1e6)

ggplot(esc_df, aes(x = fct_reorder(escenario, ganancia), y = ganancia)) +
  geom_col(fill = col_alto, width = 0.6) +
  geom_text(aes(label = dollar(ganancia, accuracy = 0.01, suffix = "M")), hjust = -0.15, size = 5) +
  coord_flip() +
  scale_y_continuous(expand = expansion(mult = c(0, 0.25))) +
  labs(title = paste0("Tres ajustes conservadores sumarían ~", dollar(total_esc / 1e6, accuracy = 0.1, suffix = "M"),
                      " de utilidad"),
       subtitle = "Utilidad operativa adicional por escenario, sin vender una unidad más (millones de USD)",
       x = NULL, y = NULL) +
  theme_adidas() +
  theme(panel.grid.major.y = element_blank(), axis.text.x = element_blank(), panel.grid.major.x = element_blank())

tabla(escenarios)
Escenario Ventas del segmento Margen actual Margen de referencia Utilidad adicional
A. West - Outlet: cierra 50% de la brecha frente al Outlet del resto del país $13.9M 32.8% 40.4% $0.53M
B. Women’s Apparel en West: cierra 50% de la brecha frente al resto de regiones $7.0M 29.8% 45.1% $0.54M
C. West Gear: traslada 10% de su venta In-store a Online $15.7M 35.1% 44.5% $0.15M

Sumando los tres escenarios, la utilidad operativa aumentaría en aproximadamente $1.2M, cerca del 2.6% de la utilidad actual. (Los escenarios se solapan parcialmente porque comparten registros de West, por lo que la suma es un orden de magnitud y no una proyección exacta.) El resultado también deja una lección: mover el mix de canal es una palanca real pero gradual (cada 10% de traslado aporta cifras modestas), mientras que corregir el margen de las celdas grandes de West es la palanca de mayor impacto.

8. Limitaciones

  • Sin fecha: no se pueden calcular tasas de crecimiento, estacionalidad ni tendencias; el análisis es una “foto” del desempeño.
  • Sin costos ni descuentos: las razones por las que un segmento rinde menos (precios promocionales, costos logísticos, costos de arriendo en tienda) son hipótesis; solo se observa la utilidad operativa resultante.
  • Duplicados exactos: no fue posible confirmar si los 262 registros repetidos son errores de captura; se mostró que no cambian las conclusiones.
  • Correlación no es causalidad: la relación positiva entre precio y unidades, en particular, no debe interpretarse como que subir el precio aumente las ventas.
  • Escenarios ilustrativos: el impacto financiero supone que un segmento puede acercarse al margen del resto de la compañía, lo cual depende de factores que la base no permite evaluar.
  • Moneda no especificada: los valores se presentan en dólares como supuesto.

9. Conclusiones

El análisis muestra que el desempeño de Adidas se explica por cómo y dónde se vende, más que por cuánto se vende. Las ventas y la utilidad se mueven casi en línea (r = 0,94), pero el margen por dólar vendido cambia mucho según la región, el canal, el producto y el distribuidor. Algunos de los segmentos que más venden (West, los canales físicos y Men’s Athletic Footwear) son los que menos rentabilidad dejan, mientras que Online, South, Sports Direct y Men’s Street Footwear combinan volumen y rentabilidad.

Para el equipo directivo, el mensaje es claro: la oportunidad no está en vender más en todas partes, sino en corregir el margen de las pocas combinaciones grandes que rinden por debajo del promedio (sobre todo en West) y en mover el mix hacia los canales y clientes más rentables. Con evidencia adicional (fechas, costos y descuentos) se podrá pasar de las hipótesis planteadas aquí a un análisis predictivo y prescriptivo más robusto.

10. Referencias

  • Provost, F. y Fawcett, T. (2013). Data Science for Business. O’Reilly Media.
  • Wickham, H. y Grolemund, G. (2017). R for Data Science. O’Reilly Media.
  • Xie, Y., Allaire, J. J. y Grolemund, G. (2018). R Markdown: The Definitive Guide. Chapman & Hall/CRC.
  • Wickham, H. (2016). ggplot2: Elegant Graphics for Data Analysis. Springer.
  • Base de datos DatosCaso1.xlsx (Data Sales Adidas), suministrada por la profesora Julieth Stefens Cerón para el Caso 1 de Analítica de Datos para la Toma de Decisiones, Pontificia Universidad Javeriana Cali (2026).