1 Preparación del Entorno

1.1 Instalación y carga de librerías

# Instala pacman si no está disponible
if (!requireNamespace("pacman", quietly = TRUE)) install.packages("pacman")

pacman::p_load(
  readxl,      # Leer archivos .xlsx
  dplyr,       # Manipulación de datos
  tidyr,       # Datos ordenados
  ggplot2,     # Visualizaciones
  ggcorrplot,  # Matriz de correlación
  scales,      # Formateo de ejes
  forcats,     # Manejo de factores
  stringr,     # Manejo de texto
  moments,     # Asimetría y curtosis
  knitr,       # Tablas
  kableExtra   # Estilo de tablas
)

1.2 Paleta corporativa y tema visual

AZUL   <- "#1C3A6E"
ROJO   <- "#C8102E"
DORADO <- "#F5A623"
VERDE  <- "#2ECC71"
MORADO <- "#9B59B6"
TEAL   <- "#1ABC9C"
GRIS   <- "#6D6E71"
PAL    <- c(AZUL, ROJO, DORADO, VERDE, MORADO, TEAL)

tema_adidas <- function() {
  theme_minimal(base_size = 12) +
    theme(
      plot.title       = element_text(face = "bold", size = 14, color = AZUL),
      plot.subtitle    = element_text(size = 10, color = GRIS),
      plot.caption     = element_text(size = 8, color = GRIS),
      axis.title       = element_text(face = "bold", color = GRIS),
      axis.text        = element_text(color = GRIS),
      panel.grid.major = element_line(color = "#D9D9D9", linewidth = 0.4),
      panel.grid.minor = element_blank(),
      legend.position  = "bottom",
      legend.title     = element_text(face = "bold"),
      strip.text       = element_text(face = "bold", color = AZUL),
      plot.background  = element_rect(fill = "white", color = NA)
    )
}

# IMPORTANTE: ajusta esta ruta a la ubicación de tu archivo .xlsx
df <- read_excel("CASOADIDASESTE.xlsx", 
  col_types = c("text", "text", "text", "text", "text", "text", "text", 
                "numeric", "numeric", "numeric", "numeric", "numeric", "text")
)

2 Carga y Limpieza de Datos

# IMPORTANTE: ajusta esta ruta a la ubicación de tu archivo .xlsx
df <- read_excel("CASOADIDASESTE.xlsx", 
  col_types = c("text", "text", "text", "text", "text", "text", "text", 
                "numeric", "numeric", "numeric", "numeric", "numeric", "text")
)
# Renombrar solo las columnas que cambian
df <- df %>%
  rename(
    retailer      = distribuidor,
    genero        = Genero,
    tipo_producto = TipoProducto1,
    unidades      = unidades_vendidas,
    ventas        = ventas_total,
    utilidad_op   = utilidad_operativa,
    margen_op     = margen_operativo
  ) %>%
  mutate(
    tipo_producto = str_trim(tipo_producto),
    margen_pct    = margen_op * 100,
    genero        = factor(genero),
    region        = factor(region),
    retailer      = factor(retailer),
    metodo_venta  = factor(metodo_venta),
    producto      = factor(producto)
  )

cat("Filas:", nrow(df), "| Columnas:", ncol(df))
## Filas: 9648 | Columnas: 14

2.1 Vista previa de los datos

head(df, 10)

2.2 Estructura del dataset

glimpse(df)
## Rows: 9,648
## Columns: 14
## $ retailer      <fct> Foot Locker, Foot Locker, Foot Locker, Foot Locker, Foot…
## $ region        <fct> Northeast, Northeast, Northeast, Northeast, Northeast, N…
## $ estado        <chr> "New York", "New York", "New York", "New York", "New Yor…
## $ ciudad        <chr> "New York", "New York", "New York", "New York", "New Yor…
## $ producto      <fct> Men's Street Footwear, Men's Athletic Footwear, Women's …
## $ genero        <fct> Men, Men, Women, Women, Men, Women, Men, Men, Women, Wom…
## $ tipo_producto <chr> "treet Footwear", "Athletic Footwear", "treet Footwear",…
## $ precio_unidad <dbl> 50, 50, 40, 45, 60, 50, 50, 50, 40, 45, 60, 50, 50, 50, …
## $ unidades      <dbl> 1200, 1000, 1000, 850, 900, 1000, 1250, 900, 950, 825, 9…
## $ ventas        <dbl> 60000, 50000, 40000, 38250, 54000, 50000, 62500, 45000, …
## $ utilidad_op   <dbl> 30000.00, 15000.00, 14000.00, 13387.50, 16200.00, 12500.…
## $ margen_op     <dbl> 0.50, 0.30, 0.35, 0.35, 0.30, 0.25, 0.50, 0.30, 0.35, 0.…
## $ metodo_venta  <fct> In-store, In-store, In-store, In-store, In-store, In-sto…
## $ margen_pct    <dbl> 50, 30, 35, 35, 30, 25, 50, 30, 35, 35, 30, 25, 50, 30, …

3 Estadísticas Descriptivas

3.1 Medidas de tendencia central y variabilidad

vars_num <- c("precio_unidad", "unidades", "ventas", "utilidad_op", "margen_pct")
etiquetas <- c("Precio/Unidad ($)", "Unidades Vendidas",
               "Ventas Totales ($)", "Utilidad Operativa ($)", "Margen Operativo (%)")

tabla_desc <- df %>%
  select(all_of(vars_num)) %>%
  pivot_longer(everything(), names_to = "Variable", values_to = "Valor") %>%
  group_by(Variable) %>%
  summarise(
    N         = n(),
    Media     = mean(Valor),
    Mediana   = median(Valor),
    Desv_Std  = sd(Valor),
    CV_pct    = round((sd(Valor) / mean(Valor)) * 100, 1),
    Q1        = quantile(Valor, 0.25),
    Q3        = quantile(Valor, 0.75),
    IQR       = IQR(Valor),
    Asimetria = round(skewness(Valor), 3),
    Curtosis  = round(kurtosis(Valor), 3),
    Min       = min(Valor),
    Max       = max(Valor)
  ) %>%
  mutate(Variable = etiquetas)

tabla_desc %>%
  kbl(digits = 2, caption = "Estadísticas Descriptivas — Variables Financieras Clave") %>%
  kable_styling(bootstrap_options = c("striped","hover","condensed"), full_width = TRUE) %>%
  row_spec(0, background = AZUL, color = "white", bold = TRUE)
Estadísticas Descriptivas — Variables Financieras Clave
Variable N Media Mediana Desv_Std CV_pct Q1 Q3 IQR Asimetria Curtosis Min Max
Precio/Unidad (\() </td> <td style="text-align:right;"> 9648 </td> <td style="text-align:right;"> 42.30 </td> <td style="text-align:right;"> 41.00 </td> <td style="text-align:right;"> 9.72 </td> <td style="text-align:right;"> 23.0 </td> <td style="text-align:right;"> 35.00 </td> <td style="text-align:right;"> 49.00 </td> <td style="text-align:right;"> 14.00 </td> <td style="text-align:right;"> 0.23 </td> <td style="text-align:right;"> 3.17 </td> <td style="text-align:right;"> 10 </td> <td style="text-align:right;"> 80 </td> </tr> <tr> <td style="text-align:left;"> Unidades Vendidas </td> <td style="text-align:right;"> 9648 </td> <td style="text-align:right;"> 45.22 </td> <td style="text-align:right;"> 45.00 </td> <td style="text-align:right;"> 14.71 </td> <td style="text-align:right;"> 32.5 </td> <td style="text-align:right;"> 35.00 </td> <td style="text-align:right;"> 55.00 </td> <td style="text-align:right;"> 20.00 </td> <td style="text-align:right;"> 0.36 </td> <td style="text-align:right;"> 3.43 </td> <td style="text-align:right;"> 7 </td> <td style="text-align:right;"> 110 </td> </tr> <tr> <td style="text-align:left;"> Ventas Totales (\)) 9648 256.93 176.00 214.25 83.4 106.00 350.00 244.00 1.46 4.70 0 1275
Utilidad Operativa ($) 9648 4894.79 3262.98 4866.46 99.4 1753.44 6192.36 4438.92 2.33 10.18 0 39000
Margen Operativo (%) 9648 12455.08 7803.50 12716.39 102.1 4065.25 15864.50 11799.25 1.96 7.12 0 82500

Interpretación: Un CV > 100% indica alta variabilidad relativa. Asimetría positiva significa cola derecha (valores extremos altos poco frecuentes).


4 Análisis de Ventas

4.1 Ventas totales por región

ventas_region <- df %>%
  group_by(region) %>%
  summarise(
    ventas_total   = sum(ventas),
    utilidad_total = sum(utilidad_op),
    margen_prom    = mean(margen_pct),
    n_registros    = n()
  ) %>%
  arrange(desc(ventas_total))

ventas_region %>%
  mutate(
    ventas_total   = dollar(ventas_total),
    utilidad_total = dollar(utilidad_total),
    margen_prom    = paste0(round(margen_prom, 1), "%")
  ) %>%
  kbl(caption = "Ventas y Rentabilidad por Región",
      col.names = c("Región","Ventas Totales","Utilidad Total","Margen Promedio","Registros")) %>%
  kable_styling(bootstrap_options = c("striped","hover"), full_width = FALSE) %>%
  row_spec(0, background = AZUL, color = "white", bold = TRUE) %>%
  row_spec(1, background = "#EEF2FA", bold = TRUE)
Ventas y Rentabilidad por Región
Región Ventas Totales Utilidad Total Margen Promedio Registros
West $36,436,157 $13,017,584 39.7% 2448
Northeast $25,078,267 $9,732,774 41% 2376
Southeast $21,374,436 $8,393,059 41.9% 1224
South $20,603,356 $9,221,605 46.7% 1728
Midwest $16,674,434 $6,859,945 43.5% 1872
ggplot(ventas_region,
       aes(x = fct_reorder(region, ventas_total), y = ventas_total / 1e6)) +
  geom_col(fill = AZUL, width = 0.6) +
  geom_text(aes(label = paste0("$", round(ventas_total / 1e6, 1), "M")),
            hjust = -0.1, fontface = "bold", size = 3.8) +
  coord_flip() +
  scale_y_continuous(labels = dollar_format(suffix = "M"),
                     expand = expansion(mult = c(0, 0.2))) +
  labs(
    title    = "Ventas Totales por Región",
    subtitle = "Millones de USD | Todas las categorías",
    x = NULL, y = "Ventas (Millones USD)",
    caption  = "Fuente: Base de datos Adidas"
  ) +
  tema_adidas()

4.2 Ventas por retailer

ventas_retailer <- df %>%
  group_by(retailer) %>%
  summarise(
    ventas_total   = sum(ventas),
    utilidad_total = sum(utilidad_op),
    margen_prom    = mean(margen_pct)
  ) %>%
  arrange(desc(ventas_total))

ggplot(ventas_retailer,
       aes(x = fct_reorder(retailer, ventas_total), y = ventas_total / 1e6, fill = retailer)) +
  geom_col(width = 0.65, show.legend = FALSE) +
  geom_text(aes(label = paste0("$", round(ventas_total / 1e6, 1), "M")),
            hjust = -0.1, fontface = "bold", size = 3.5) +
  scale_fill_manual(values = PAL) +
  coord_flip() +
  scale_y_continuous(labels = dollar_format(suffix = "M"),
                     expand = expansion(mult = c(0, 0.22))) +
  labs(
    title    = "Ventas Totales por Retailer",
    subtitle = "Comparación entre distribuidores",
    x = NULL, y = "Ventas (Millones USD)",
    caption  = "Fuente: Base de datos Adidas"
  ) +
  tema_adidas()

4.3 Participación por producto

ventas_prod <- df %>%
  group_by(producto) %>%
  summarise(ventas_total = sum(ventas)) %>%
  mutate(pct = ventas_total / sum(ventas_total) * 100) %>%
  arrange(desc(ventas_total))

# Gráfico de torta
ggplot(ventas_prod, aes(x = "", y = pct, fill = producto)) +
  geom_col(width = 1, color = "white", linewidth = 0.6) +
  coord_polar("y", start = 0) +
  geom_text(aes(label = paste0(round(pct, 1), "%")),
            position = position_stack(vjust = 0.5),
            size = 3.5, color = "white", fontface = "bold") +
  scale_fill_manual(values = PAL, name = "Producto") +
  labs(
    title    = "Participación en Ventas por Producto",
    subtitle = "Distribución porcentual del total",
    caption  = "Fuente: Base de datos Adidas"
  ) +
  tema_adidas() +
  theme(
    axis.text  = element_blank(),
    axis.title = element_blank(),
    panel.grid = element_blank()
  )

ggplot(ventas_prod,
       aes(x = fct_reorder(str_wrap(producto, 20), ventas_total),
           y = ventas_total / 1e6)) +
  geom_col(fill = AZUL, width = 0.6) +
  geom_text(aes(label = paste0("$", round(ventas_total / 1e6, 1), "M\n(",
                                round(pct, 1), "%)")),
            hjust = -0.1, size = 3.2, fontface = "bold") +
  coord_flip() +
  scale_y_continuous(labels = dollar_format(suffix = "M"),
                     expand = expansion(mult = c(0, 0.3))) +
  labs(
    title    = "Ventas Absolutas y Participación por Producto",
    subtitle = "Millones USD",
    x = NULL, y = "Ventas (Millones USD)",
    caption  = "Fuente: Base de datos Adidas"
  ) +
  tema_adidas()

4.4 Valores atípicos en ventas — Boxplot

ggplot(df, aes(x = fct_reorder(region, ventas, median), y = ventas / 1e3, fill = region)) +
  geom_boxplot(outlier.color = ROJO, outlier.size = 1.5,
               alpha = 0.75, show.legend = FALSE) +
  scale_fill_manual(values = PAL) +
  scale_y_continuous(labels = dollar_format(suffix = "K")) +
  labs(
    title    = "Distribución de Ventas por Región",
    subtitle = "Detección de variabilidad y valores atípicos",
    x = NULL, y = "Ventas (Miles USD)",
    caption  = "Fuente: Base de datos Adidas"
  ) +
  tema_adidas()


5 Análisis de Rentabilidad

5.1 Distribución del margen operativo

ggplot(df, aes(x = margen_pct)) +
  geom_histogram(binwidth = 2, fill = AZUL, color = "white", alpha = 0.85) +
  geom_vline(aes(xintercept = mean(margen_pct), color = "Media"),
             linewidth = 1.2, linetype = "dashed") +
  geom_vline(aes(xintercept = median(margen_pct), color = "Mediana"),
             linewidth = 1.2, linetype = "dotted") +
  scale_color_manual(values = c("Media" = ROJO, "Mediana" = DORADO), name = NULL) +
  scale_x_continuous(labels = function(x) paste0(x, "%")) +
  labs(
    title    = "Distribución del Margen Operativo",
    subtitle = paste0("Media: ", round(mean(df$margen_pct), 1),
                      "% | Mediana: ", round(median(df$margen_pct), 1), "%"),
    x = "Margen Operativo (%)", y = "Frecuencia",
    caption  = "Fuente: Base de datos Adidas"
  ) +
  tema_adidas()

5.2 Margen operativo por región — Boxplot

ggplot(df, aes(x = fct_reorder(region, margen_pct, median),
               y = margen_pct, fill = region)) +
  geom_boxplot(outlier.color = ROJO, outlier.size = 1.5,
               alpha = 0.75, show.legend = FALSE) +
  scale_fill_manual(values = PAL) +
  scale_y_continuous(labels = function(x) paste0(x, "%")) +
  labs(
    title    = "Distribución del Margen Operativo por Región",
    subtitle = "Identificación de variabilidad y atípicos",
    x = NULL, y = "Margen Operativo (%)",
    caption  = "Fuente: Base de datos Adidas"
  ) +
  tema_adidas()

5.3 Rentabilidad por método de venta

util_metodo <- df %>%
  group_by(metodo_venta) %>%
  summarise(
    ventas_total   = sum(ventas),
    utilidad_total = sum(utilidad_op),
    margen_prom    = mean(margen_pct)
  ) %>%
  arrange(desc(utilidad_total))

util_metodo %>%
  mutate(
    ventas_total   = dollar(ventas_total),
    utilidad_total = dollar(utilidad_total),
    margen_prom    = paste0(round(margen_prom, 1), "%")
  ) %>%
  kbl(caption = "Rentabilidad por Método de Venta",
      col.names = c("Método","Ventas Totales","Utilidad Total","Margen Promedio")) %>%
  kable_styling(bootstrap_options = c("striped","hover"), full_width = FALSE) %>%
  row_spec(0, background = AZUL, color = "white", bold = TRUE)
Rentabilidad por Método de Venta
Método Ventas Totales Utilidad Total Margen Promedio
Online $44,965,657 $19,552,538 46.4%
Outlet $39,536,618 $14,913,301 39.5%
In-store $35,664,375 $12,759,129 35.6%
ggplot(util_metodo,
       aes(x = fct_reorder(metodo_venta, utilidad_total),
           y = utilidad_total / 1e6, fill = metodo_venta)) +
  geom_col(width = 0.55, show.legend = FALSE) +
  geom_text(aes(label = paste0("$", round(utilidad_total / 1e6, 1), "M\n(",
                                round(margen_prom, 1), "%)")),
            hjust = -0.1, fontface = "bold", size = 3.8) +
  scale_fill_manual(values = c(AZUL, ROJO, DORADO)) +
  coord_flip() +
  scale_y_continuous(labels = dollar_format(suffix = "M"),
                     expand = expansion(mult = c(0, 0.3))) +
  labs(
    title    = "Utilidad Operativa por Método de Venta",
    subtitle = "Total en millones USD y margen promedio (%)",
    x = NULL, y = "Utilidad Operativa (Millones USD)",
    caption  = "Fuente: Base de datos Adidas"
  ) +
  tema_adidas()

5.4 Rentabilidad por producto

rent_prod <- df %>%
  group_by(producto, metodo_venta) %>%
  summarise(utilidad = sum(utilidad_op) / 1e6, .groups = "drop")

ggplot(rent_prod,
       aes(x = fct_reorder(str_wrap(producto, 20), utilidad, sum),
           y = utilidad, fill = metodo_venta)) +
  geom_col(width = 0.65) +
  coord_flip() +
  scale_fill_manual(values = c(AZUL, ROJO, DORADO), name = "Método de Venta") +
  scale_y_continuous(labels = dollar_format(suffix = "M")) +
  labs(
    title    = "Utilidad Operativa por Producto y Método de Venta",
    subtitle = "Millones USD — Análisis de rentabilidad combinada",
    x = NULL, y = "Utilidad Operativa (Millones USD)",
    caption  = "Fuente: Base de datos Adidas"
  ) +
  tema_adidas()


6 Relación entre Variables Clave

6.1 Correlación: Ventas vs Utilidad Operativa

r_vu <- cor(df$ventas, df$utilidad_op, method = "pearson")
cat(sprintf("Correlación de Pearson (Ventas - Utilidad): r = %.4f\n", r_vu))
## Correlación de Pearson (Ventas - Utilidad): r = 0.9354
set.seed(42)
df_muestra <- df %>% sample_n(min(2500, nrow(df)))

ggplot(df_muestra, aes(x = ventas / 1e3, y = utilidad_op / 1e3, color = region)) +
  geom_point(alpha = 0.4, size = 1.8) +
  geom_smooth(method = "lm", se = TRUE, aes(group = 1),
              color = "black", linewidth = 1) +
  scale_color_manual(values = PAL, name = "Región") +
  scale_x_continuous(labels = dollar_format(suffix = "K")) +
  scale_y_continuous(labels = dollar_format(suffix = "K")) +
  annotate("label", x = Inf, y = -Inf,
           label = paste0("r = ", round(r_vu, 3)),
           hjust = 1.1, vjust = -0.5, size = 4.5,
           fontface = "bold", color = ROJO,
           fill = "white", label.size = 0.5) +
  labs(
    title    = "Relación entre Ventas Totales y Utilidad Operativa",
    subtitle = paste0("r = ", round(r_vu, 3), " — Correlación de Pearson (muestra aleatoria)"),
    x = "Ventas Totales (Miles USD)",
    y = "Utilidad Operativa (Miles USD)",
    caption  = "Fuente: Base de datos Adidas"
  ) +
  tema_adidas()

6.2 Correlación: Precio por unidad vs Unidades vendidas

r_pu <- cor(df$precio_unidad, df$unidades, method = "pearson")
cat(sprintf("Correlación de Pearson (Precio - Unidades): r = %.4f\n", r_pu))
## Correlación de Pearson (Precio - Unidades): r = 0.2659
ggplot(df_muestra, aes(x = precio_unidad, y = unidades, color = tipo_producto)) +
  geom_point(alpha = 0.35, size = 1.8) +
  geom_smooth(method = "lm", se = TRUE, aes(group = 1),
              color = "black", linewidth = 1) +
  scale_color_manual(values = PAL, name = "Tipo de Producto") +
  scale_x_continuous(labels = dollar_format()) +
  annotate("label", x = Inf, y = Inf,
           label = paste0("r = ", round(r_pu, 3)),
           hjust = 1.1, vjust = 1.5, size = 4.5,
           fontface = "bold", color = ROJO,
           fill = "white", label.size = 0.5) +
  labs(
    title    = "Precio por Unidad vs Unidades Vendidas",
    subtitle = paste0("r = ", round(r_pu, 3), " | ¿El precio penaliza el volumen?"),
    x = "Precio por Unidad (USD)",
    y = "Unidades Vendidas",
    caption  = "Fuente: Base de datos Adidas"
  ) +
  tema_adidas()

6.3 Matriz de correlación completa

vars_cor <- df %>%
  select(precio_unidad, unidades, ventas, utilidad_op, margen_pct)

colnames(vars_cor) <- c("Precio/Unidad", "Unidades", "Ventas", "Utilidad Op.", "Margen (%)")

mat_cor <- cor(vars_cor, method = "pearson")

cat("Matriz de Correlación de Pearson:\n")
## Matriz de Correlación de Pearson:
round(mat_cor, 3)
##               Precio/Unidad Unidades Ventas Utilidad Op. Margen (%)
## Precio/Unidad         1.000    0.266  0.540        0.504     -0.137
## Unidades              0.266    1.000  0.919        0.872     -0.305
## Ventas                0.540    0.919  1.000        0.935     -0.302
## Utilidad Op.          0.504    0.872  0.935        1.000     -0.047
## Margen (%)           -0.137   -0.305 -0.302       -0.047      1.000
ggcorrplot(mat_cor,
           method   = "circle",
           type     = "lower",
           lab      = TRUE,
           lab_size = 3.5,
           colors   = c(ROJO, "white", AZUL),
           title    = "Matriz de Correlación — Variables Financieras",
           ggtheme  = tema_adidas()) +
  labs(caption = "Correlación de Pearson | Fuente: Base de datos Adidas")


7 Análisis Estratégico

7.1 Mapa de calor: Ventas por Producto × Región

heat_data <- df %>%
  group_by(producto, region) %>%
  summarise(ventas_total = sum(ventas) / 1e6, .groups = "drop") %>%
  mutate(producto = str_replace_all(producto, "Men's ", "M. ") %>%
                    str_replace_all("Women's ", "W. "))

ggplot(heat_data, aes(x = region, y = producto, fill = ventas_total)) +
  geom_tile(color = "white", linewidth = 0.8) +
  geom_text(aes(label = paste0("$", round(ventas_total, 1), "M")),
            size = 3, fontface = "bold",
            color = ifelse(heat_data$ventas_total > max(heat_data$ventas_total) * 0.6,
                           "white", AZUL)) +
  scale_fill_gradient(low = "#D4E6F1", high = AZUL,
                      name = "Ventas (M USD)") +
  labs(
    title    = "Mapa de Calor: Ventas por Producto y Región",
    subtitle = "Millones de USD — Identificación de combinaciones estratégicas",
    x = "Región", y = NULL,
    caption  = "Fuente: Base de datos Adidas"
  ) +
  tema_adidas() +
  theme(axis.text.x = element_text(angle = 25, hjust = 1))

7.2 Ventas por género

ventas_genero <- df %>%
  group_by(genero) %>%
  summarise(
    ventas_total   = sum(ventas),
    utilidad_total = sum(utilidad_op),
    margen_prom    = mean(margen_pct)
  )

ggplot(ventas_genero, aes(x = genero, y = ventas_total / 1e6, fill = genero)) +
  geom_col(width = 0.45, show.legend = FALSE) +
  geom_text(aes(label = paste0("$", round(ventas_total / 1e6, 1), "M")),
            vjust = -0.5, fontface = "bold", size = 4.5) +
  scale_fill_manual(values = c(AZUL, ROJO)) +
  scale_y_continuous(labels = dollar_format(suffix = "M"),
                     expand = expansion(mult = c(0, 0.18))) +
  labs(
    title    = "Ventas Totales por Género",
    subtitle = "Comparación Men vs Women",
    x = NULL, y = "Ventas (Millones USD)",
    caption  = "Fuente: Base de datos Adidas"
  ) +
  tema_adidas()


8 Resumen Ejecutivo

top_region   <- df %>% group_by(region) %>%
                summarise(v = sum(ventas)) %>% slice_max(v, n=1) %>% pull(region)
top_retailer <- df %>% group_by(retailer) %>%
                summarise(v = sum(ventas)) %>% slice_max(v, n=1) %>% pull(retailer)
top_producto <- df %>% group_by(producto) %>%
                summarise(v = sum(ventas)) %>% slice_max(v, n=1) %>% pull(producto)
top_metodo   <- df %>% group_by(metodo_venta) %>%
                summarise(u = sum(utilidad_op)) %>% slice_max(u, n=1) %>% pull(metodo_venta)

resumen <- data.frame(
  Indicador = c(
    "Registros analizados",
    "Ventas totales",
    "Utilidad operativa total",
    "Margen operativo promedio",
    "Región líder en ventas",
    "Retailer principal",
    "Producto más vendido",
    "Método más rentable",
    "Correlación Ventas–Utilidad (r)",
    "Correlación Precio–Unidades (r)"
  ),
  Valor = c(
    format(nrow(df), big.mark = ","),
    dollar(sum(df$ventas)),
    dollar(sum(df$utilidad_op)),
    paste0(round(mean(df$margen_pct), 1), "%"),
    as.character(top_region),
    as.character(top_retailer),
    as.character(top_producto),
    as.character(top_metodo),
    round(r_vu, 3),
    round(r_pu, 3)
  ),
  Interpretacion = c(
    "Base completa de análisis",
    "Ingresos brutos acumulados",
    "Ganancia neta de operaciones",
    paste0("DE: ", round(sd(df$margen_pct), 1), "% — baja variabilidad"),
    "Mayor concentración de ventas",
    "Canal de distribución dominante",
    "Categoría de mayor participación",
    "Canal con mayor retorno",
    "Relación positiva muy fuerte",
    "Precio no penaliza fuertemente el volumen"
  )
)

resumen %>%
  kbl(caption = "Resumen Ejecutivo — Hallazgos Clave para la Junta Directiva") %>%
  kable_styling(bootstrap_options = c("striped","hover","condensed"),
                full_width = TRUE) %>%
  row_spec(0, background = AZUL, color = "white", bold = TRUE) %>%
  row_spec(c(1,3,5,7,9), background = "#EEF2FA")
Resumen Ejecutivo — Hallazgos Clave para la Junta Directiva
Indicador Valor Interpretacion
Registros analizados 9,648 Base completa de análisis
Ventas totales $120,166,650 Ingresos brutos acumulados
Utilidad operativa total $47,224,968 Ganancia neta de operaciones
Margen operativo promedio 42.3% DE: 9.7% — baja variabilidad
Región líder en ventas West Mayor concentración de ventas
Retailer principal West Gear Canal de distribución dominante
Producto más vendido Men’s Street Footwear Categoría de mayor participación
Método más rentable Online Canal con mayor retorno
Correlación Ventas–Utilidad (r) 0.935 Relación positiva muy fuerte
Correlación Precio–Unidades (r) 0.266 Precio no penaliza fuertemente el volumen

9 Analisis Complementarios

9.1 Perfil Precio-Margen por Region (Grafico de Lineas)

Este grafico de lineas muestra, para cada region, como evoluciona el margen operativo promedio a medida que sube el precio promedio por unidad del producto. Cada linea es una region, y cada punto es una categoria de producto ordenada de menor a mayor precio. Permite identificar si precios mas altos se traducen en mejores margenes, y si ese patron es consistente entre regiones.

perfil <- df %>%
  group_by(region, producto) %>%
  summarise(
    precio_prom = mean(precio_unidad),
    margen_prom = mean(margen_op) * 100,
    .groups = "drop"
  ) %>%
  arrange(precio_prom)

orden_prod <- perfil %>%
  group_by(producto) %>%
  summarise(precio_global = mean(precio_prom)) %>%
  arrange(precio_global) %>%
  pull(producto)

perfil$producto_ord <- factor(perfil$producto, levels = orden_prod)
etiq <- c("M.Str.Foot","M.Ath.Foot","W.Str.Foot","W.Ath.Foot","M.App","W.App")
levels(perfil$producto_ord) <- etiq

ggplot(perfil, aes(x = producto_ord, y = margen_prom,
                   color = region, group = region)) +
  geom_line(linewidth = 1.1) +
  geom_point(size = 3.2, shape = 21, fill = "white", stroke = 1.5) +
  geom_text(aes(label = paste0(round(margen_prom, 1), "%")),
            vjust = -1.1, size = 2.8, fontface = "bold", show.legend = FALSE) +
  scale_color_manual(values = PAL, name = "Region") +
  scale_y_continuous(labels = function(x) paste0(x, "%"),
                     limits = c(30, 60),
                     expand = expansion(mult = c(0.05, 0.12))) +
  labs(
    title    = "Perfil Precio-Margen por Region",
    subtitle = "Cada linea es una region | Productos ordenados de menor a mayor precio promedio",
    x        = "Producto (orden ascendente de precio)",
    y        = "Margen Operativo Promedio (%)",
    caption  = "Fuente: Base de datos Adidas"
  ) +
  tema_adidas() +
  theme(axis.text.x = element_text(angle = 20, hjust = 1))

Interpretacion: Si las lineas son relativamente planas, el precio no determina el margen. Si suben hacia la derecha, los productos mas caros son mas rentables. Cruces entre lineas revelan que la estrategia de precio-margen difiere por region.


9.2 Margen Operativo por Retailer segun Metodo de Venta (Grafico de Lineas)

Cada linea representa un retailer. El eje X muestra los tres metodos de venta (In-store, Online, Outlet) y el eje Y el margen promedio. Permite comparar como cambia la rentabilidad de cada distribuidor segun el canal.

margen_ret <- df %>%
  group_by(retailer, metodo_venta) %>%
  summarise(margen_prom = mean(margen_op) * 100, .groups = "drop") %>%
  mutate(metodo_venta = factor(metodo_venta,
                               levels = c("In-store", "Outlet", "Online")))

ggplot(margen_ret, aes(x = metodo_venta, y = margen_prom,
                       color = retailer, group = retailer)) +
  geom_line(linewidth = 1.2) +
  geom_point(size = 4, shape = 21, fill = "white", stroke = 1.8) +
  geom_text(aes(label = paste0(round(margen_prom, 1), "%")),
            vjust = -1.1, size = 3, fontface = "bold", show.legend = FALSE) +
  scale_color_manual(values = PAL, name = "Retailer") +
  scale_y_continuous(labels = function(x) paste0(x, "%"),
                     limits = c(25, 55),
                     expand = expansion(mult = c(0.05, 0.15))) +
  labs(
    title    = "Margen Operativo por Retailer segun Metodo de Venta",
    subtitle = "Cada linea es un distribuidor | Se evidencia el impacto del canal en la rentabilidad",
    x        = "Metodo de Venta",
    y        = "Margen Operativo Promedio (%)",
    caption  = "Fuente: Base de datos Adidas"
  ) +
  tema_adidas()

Interpretacion: Si todas las lineas suben hacia Online, el canal digital es sistematicamente mas rentable para todos los retailers. Lineas que se cruzan indican que algunos distribuidores aprovechan mejor ciertos canales que otros.


9.3 Ventas por Producto segun Retailer (Grafico de Lineas)

Cada linea es un retailer. El eje X recorre los 6 productos ordenados por volumen global. Permite detectar en que categorias cada distribuidor tiene fortaleza o debilidad relativa.

orden_p <- df %>%
  group_by(producto) %>%
  summarise(v = sum(ventas)) %>%
  arrange(v) %>%
  pull(producto)

etiq_p <- c("W.Ath.Foot","M.App","W.App","W.Str.Foot","M.Ath.Foot","M.Str.Foot")

ventas_ret_prod <- df %>%
  group_by(retailer, producto) %>%
  summarise(ventas_M = sum(ventas) / 1e6, .groups = "drop") %>%
  mutate(producto_ord = factor(producto, levels = orden_p))

levels(ventas_ret_prod$producto_ord) <- etiq_p

ggplot(ventas_ret_prod, aes(x = producto_ord, y = ventas_M,
                             color = retailer, group = retailer)) +
  geom_line(linewidth = 1.1) +
  geom_point(size = 3.5, shape = 21, fill = "white", stroke = 1.6) +
  geom_text(aes(label = paste0("$", round(ventas_M, 1), "M")),
            vjust = -1.1, size = 2.6, fontface = "bold", show.legend = FALSE) +
  scale_color_manual(values = PAL, name = "Retailer") +
  scale_y_continuous(labels = dollar_format(suffix = "M"),
                     expand = expansion(mult = c(0.05, 0.2))) +
  labs(
    title    = "Ventas por Producto segun Retailer",
    subtitle = "Productos ordenados de menor a mayor volumen global | Millones USD",
    x        = "Producto",
    y        = "Ventas (Millones USD)",
    caption  = "Fuente: Base de datos Adidas"
  ) +
  tema_adidas() +
  theme(axis.text.x = element_text(angle = 20, hjust = 1))


9.4 Curva de Pareto — Ciudades por Ventas

Muestra cuantas ciudades concentran el 80% de las ventas totales. Es un analisis de concentracion geografica que no habia sido incluido.

pareto <- df %>%
  group_by(ciudad) %>%
  summarise(ventas_total = sum(ventas)) %>%
  arrange(desc(ventas_total)) %>%
  mutate(
    rank   = row_number(),
    acum   = cumsum(ventas_total) / sum(ventas_total) * 100
  )

top20 <- head(pareto, 20)

corte_80 <- min(pareto$rank[pareto$acum >= 80])
cat(sprintf("El 80%% de las ventas se concentra en las primeras %d ciudades de %d totales.\n",
            corte_80, nrow(pareto)))
## El 80% de las ventas se concentra en las primeras 32 ciudades de 52 totales.
ggplot(top20, aes(x = rank)) +
  geom_col(aes(y = ventas_total / 1e3), fill = AZUL, alpha = 0.8, width = 0.7) +
  geom_line(aes(y = acum * max(top20$ventas_total / 1e3) / 100),
            color = ROJO, linewidth = 1.4, group = 1) +
  geom_point(aes(y = acum * max(top20$ventas_total / 1e3) / 100),
             color = ROJO, size = 3, shape = 21, fill = "white", stroke = 1.5) +
  geom_hline(yintercept = 80 * max(top20$ventas_total / 1e3) / 100,
             linetype = "dashed", color = DORADO, linewidth = 0.9) +
  annotate("text", x = 15, y = 80 * max(top20$ventas_total / 1e3) / 100,
           label = "Linea 80%", vjust = -0.6, color = DORADO,
           fontface = "bold", size = 3.5) +
  scale_x_continuous(breaks = 1:20,
                     labels = top20$ciudad) +
  scale_y_continuous(
    name     = "Ventas (Miles USD)",
    labels   = dollar_format(suffix = "K"),
    sec.axis = sec_axis(~ . * 100 / max(top20$ventas_total / 1e3),
                        name   = "Acumulado (%)",
                        labels = function(x) paste0(x, "%"))
  ) +
  labs(
    title    = "Curva de Pareto — Top 20 Ciudades por Ventas",
    subtitle = paste0("Las primeras ", corte_80,
                      " ciudades concentran el 80% de las ventas totales"),
    x        = "Ciudad (ranking)",
    caption  = "Fuente: Base de datos Adidas | Barras = ventas | Linea roja = % acumulado"
  ) +
  tema_adidas() +
  theme(axis.text.x  = element_text(angle = 45, hjust = 1),
        axis.title.y.right = element_text(color = ROJO, face = "bold"),
        axis.text.y.right  = element_text(color = ROJO))

Interpretacion: La regla de Pareto (80/20) aplicada geograficamente revela cuales ciudades son estrategicamente criticas. Concentrar esfuerzos de marketing y distribucion en estas ciudades maximiza el retorno.


Documento generado con R Markdown | Analisis Corporativo Adidas