Adidas es una empresa global reconocida por su participación en la industria de artículos deportivos y de estilo de vida, fundada en el año 1949 en Alemania, con un portafolio que incluye principalmente calzado, ropa y accesorios dirigidos tanto al rendimiento deportivo como al consumo cotidiano. La marca tiene un valor de 6.800 millones de dólares, lo que la convierte en una de las marcas más valiosas entre las corporaciones deportivas.
Como equipo de analistas de datos de Adidas tenemos como objetivo evaluar el desempeño comercial y financiero de distintas líneas de productos en el mercado de Estados Unidos, con el fin de comprender cómo se están desempeñando los diferentes productos, regiones y canales comerciales, y de qué manera esto afecta la rentabilidad de la compañía.
Aplicaremos técnicas de estadística descriptiva, diagnóstica y visualización de datos para detectar patrones, valores atípicos y relaciones entre variables, con el fin de facilitar la interpretación del desempeño comercial y financiero de la compañía y de proponer recomendaciones basadas en evidencia.
La base de datos utilizada contiene 9.651 registros con las siguientes variables: distribuidor, región, estado, ciudad, producto, precio por unidad, unidades vendidas, ventas totales, utilidad operativa, margen operativo y método de venta.
# Cargar librerías necesarias
library(readxl)
library(dplyr)
library(ggplot2)
library(plotly)
library(knitr)
library(kableExtra)
library(tidyr)
library(tidyverse)
library(scales)
Cargar la base de datos
Nota importante: para que el documento compile en cualquier
computador (incluido el de la profesora), el archivo
DatosCaso1.xlsx debe estar guardado en la misma
carpeta que este archivo .Rmd, y se carga con una
ruta relativa en lugar de una ruta absoluta del computador personal.
# Cargar datos desde el archivo Excel (ruta relativa: mismo folder que el .Rmd)
datos_col <- read_excel("DatosCaso1.xlsx",
col_types = c("text", "text", "text",
"text", "text", "numeric", "numeric",
"numeric", "numeric", "numeric",
"text"))
# Ver las primeras filas de los datos
class(datos_col)
## [1] "tbl_df" "tbl" "data.frame"
colnames(datos_col)
## [1] "distribuidor" "region" "estado"
## [4] "ciudad" "producto" "precio_unidad"
## [7] "unidades_vendidas" "ventas_total" "utilidad_operativa"
## [10] "margen_operativo" "metodo_venta"
head(datos_col)
| 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 |
Limpieza de datos
Se revisan valores faltantes por columna:
colSums(is.na(datos_col)) %>%
kable(col.names = "Valores faltantes", caption = "Valores faltantes por columna") %>%
kable_styling(full_width = FALSE, bootstrap_options = c("striped", "hover"))
| Valores faltantes | |
|---|---|
| distribuidor | 0 |
| region | 0 |
| estado | 0 |
| ciudad | 0 |
| producto | 0 |
| precio_unidad | 0 |
| unidades_vendidas | 0 |
| ventas_total | 0 |
| utilidad_operativa | 0 |
| margen_operativo | 0 |
| metodo_venta | 0 |
filas_antes <- nrow(datos_col)
datos_col <- datos_col %>%
filter(if_all(everything(), ~ !is.na(.)))
filas_despues <- nrow(datos_col)
cat("Filas antes de la limpieza:", filas_antes,
"\nFilas después de la limpieza:", filas_despues,
"\nFilas eliminadas (registros incompletos):", filas_antes - filas_despues)
## Filas antes de la limpieza: 9648
## Filas después de la limpieza: 9648
## Filas eliminadas (registros incompletos): 0
Se eliminan los registros con datos incompletos, ya que corresponden
a filas sin información aprovechable y no representan una categoría de
negocio real. De aquí en adelante todo el análisis se realiza sobre el
conjunto de datos ya depurado (datos_col).
# Resumen estadístico de las variables financieras
resumen <- datos_col %>%
select(ventas_total, utilidad_operativa, margen_operativo) %>%
summary()
resumen
## ventas_total utilidad_operativa margen_operativo
## Min. : 0 Min. : 0 Min. :0.100
## 1st Qu.: 4065 1st Qu.: 1753 1st Qu.:0.350
## Median : 7804 Median : 3263 Median :0.410
## Mean :12455 Mean : 4895 Mean :0.423
## 3rd Qu.:15864 3rd Qu.: 6192 3rd Qu.:0.490
## Max. :82500 Max. :39000 Max. :0.800
Para complementar el resumen anterior, se calculan de forma explícita las medidas de tendencia central y de variabilidad (incluyendo el coeficiente de variación, que permite comparar la dispersión relativa entre variables con escalas distintas):
resumen_variabilidad <- datos_col %>%
summarise(across(
c(precio_unidad, unidades_vendidas, ventas_total, utilidad_operativa, margen_operativo),
list(
Media = ~mean(., na.rm = TRUE),
Mediana = ~median(., na.rm = TRUE),
Desv_estandar = ~sd(., na.rm = TRUE),
Coef_variacion = ~sd(., na.rm = TRUE) / mean(., na.rm = TRUE)
),
.names = "{.col}__{.fn}"
)) %>%
pivot_longer(everything(), names_to = c("Variable", "Medida"), names_sep = "__") %>%
pivot_wider(names_from = Medida, values_from = value) %>%
mutate(across(where(is.numeric), ~round(., 2)))
kable(resumen_variabilidad, caption = "Medidas de tendencia central y variabilidad") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"), full_width = TRUE) %>%
row_spec(0, bold = TRUE, color = "white", background = "#1F4E78")
| Variable | Media | Mediana | Desv_estandar | Coef_variacion |
|---|---|---|---|---|
| precio_unidad | 45.22 | 45.00 | 14.71 | 0.33 |
| unidades_vendidas | 256.93 | 176.00 | 214.25 | 0.83 |
| ventas_total | 12455.08 | 7803.50 | 12716.39 | 1.02 |
| utilidad_operativa | 4894.79 | 3262.98 | 4866.46 | 0.99 |
| margen_operativo | 0.42 | 0.41 | 0.10 | 0.23 |
Interpretación: las ventas totales muestran una
media claramente superior a la mediana, lo que indica una distribución
sesgada a la derecha: existen registros de ventas muy
altas que elevan el promedio por encima del valor típico. El coeficiente
de variación de ventas_total y
utilidad_operativa es superior a 1, lo que refleja una
alta dispersión relativa en el desempeño comercial
entre transacciones. En contraste, el margen_operativo es
la variable más estable (coeficiente de variación más bajo), moviéndose
de forma más homogénea alrededor de su media.
# Crear indicadores generales
tabla_general <- datos_col %>%
summarise(
ventas_total = sum(ventas_total, na.rm = TRUE),
unidades_vendidas = sum(unidades_vendidas, na.rm = TRUE),
utilidad_operativa = sum(utilidad_operativa, na.rm = TRUE),
margen_operativo_promedio = mean(
utilidad_operativa / ventas_total * 100,
na.rm = TRUE
),
precio_promedio = ventas_total / unidades_vendidas
) %>%
mutate(
ventas_total = dollar(
ventas_total,
prefix = "$",
big.mark = ".",
decimal.mark = ",",
accuracy = 1
),
unidades_vendidas = format(
unidades_vendidas,
big.mark = ".",
decimal.mark = ",",
scientific = FALSE
),
utilidad_operativa = dollar(
utilidad_operativa,
prefix = "$",
big.mark = ".",
decimal.mark = ",",
accuracy = 1
),
margen_operativo_promedio = paste0(
format(
round(margen_operativo_promedio, 2),
decimal.mark = ",",
nsmall = 2
),
"%"
),
precio_promedio = dollar(
precio_promedio,
prefix = "$",
big.mark = ".",
decimal.mark = ",",
accuracy = 1
)
) %>%
# Convertir la tabla a formato vertical
pivot_longer(
cols = everything(),
names_to = "indicador",
values_to = "valor"
) %>%
mutate(
indicador = recode(
indicador,
ventas_total = "Ventas totales",
unidades_vendidas = "Unidades vendidas",
utilidad_operativa = "Utilidad operacional",
margen_operativo_promedio = "Margen operativo promedio",
precio_promedio = "Precio promedio"
)
)
# Mostrar tabla vertical
kable(
tabla_general,
format = "html",
escape = FALSE,
align = c("l", "r"),
col.names = c("Indicador", "Resultado"),
caption = "Resumen general de indicadores comerciales y operativos"
) %>%
kable_styling(
bootstrap_options = c(
"striped",
"hover",
"condensed",
"responsive"
),
full_width = FALSE,
position = "center",
font_size = 14
) %>%
row_spec(
0,
bold = TRUE,
color = "white",
background = "#1F4E78",
align = "center"
) %>%
column_spec(
1,
bold = TRUE,
color = "#1F4E78",
width = "7cm"
) %>%
column_spec(
2,
bold = TRUE,
color = "#333333",
width = "6cm"
)
| Indicador | Resultado |
|---|---|
| Ventas totales | $120.166.650 |
| Unidades vendidas | 2.478.861 |
| Utilidad operacional | $47.224.968 |
| Margen operativo promedio | 39,30% |
| Precio promedio | $48 |
# Resumen de ventas y utilidad operativa por región
resumen_region <- datos_col %>%
group_by(region) %>%
summarise(
ventas_total = sum(ventas_total, na.rm = TRUE),
utilidad_operativa = sum(utilidad_operativa, na.rm = TRUE),
.groups = "drop"
) %>%
pivot_longer(
cols = c(ventas_total, utilidad_operativa),
names_to = "indicador",
values_to = "valor"
) %>%
mutate(
indicador = recode(
indicador,
ventas_total = "Ventas totales",
utilidad_operativa = "Utilidad operativa"
),
valor_millones = valor / 1000000
)
# Gráfico vertical de barras agrupadas
ggplot(
resumen_region,
aes(
x = region,
y = valor_millones,
fill = indicador
)
) +
geom_col(
position = position_dodge(width = 0.75),
width = 0.55
) +
scale_fill_manual(
values = c(
"Ventas totales" = "#1F4E78",
"Utilidad operativa" = "#5B9DB5"
)
) +
scale_y_continuous(
labels = function(x) {
paste0(
"$",
format(
x,
decimal.mark = ",",
big.mark = ".",
nsmall = 1
),
" M"
)
},
expand = expansion(mult = c(0, 0.10))
) +
labs(
title = "Figura 1. Ventas y utilidad operativa por región",
subtitle = "Valores acumulados expresados en millones de USD",
x = "Región",
y = "Valor financiero",
fill = "Indicador"
) +
theme_minimal() +
theme(
panel.grid = element_blank(),
plot.title = element_text(
size = 16,
face = "bold",
color = "black"
),
plot.subtitle = element_text(
size = 11,
color = "#4B5563"
),
axis.title = element_text(
size = 11,
face = "bold",
color = "#1F2937"
),
axis.text = element_text(
size = 10,
color = "#374151"
),
axis.text.x = element_text(
angle = 30,
hjust = 1
),
legend.position = "top",
legend.title = element_text(
face = "bold",
color = "#1F2937"
),
legend.text = element_text(
color = "#374151"
)
)
Figura 1
Interpretación: la región West concentra el mayor volumen de ventas y de utilidad operativa, seguida de Northeast, mientras que Midwest es sistemáticamente la región con menor desempeño comercial. Sin embargo, como se verá más adelante, un mayor volumen de ventas no siempre implica un mayor margen relativo: South, pese a no ser la región líder en ventas, presenta el margen operativo promedio más alto del país.
# Resumen de ventas y utilidad por método de venta
resumen_metodo <- datos_col %>%
group_by(metodo_venta) %>%
summarise(
ventas_total = sum(ventas_total, na.rm = TRUE),
utilidad_operativa = sum(utilidad_operativa, na.rm = TRUE),
.groups = "drop"
) %>%
mutate(
ventas_total = ventas_total / 1000000,
utilidad_operativa = utilidad_operativa / 1000000
) %>%
pivot_longer(
cols = c(ventas_total, utilidad_operativa),
names_to = "indicador",
values_to = "valor"
) %>%
mutate(
indicador = recode(
indicador,
ventas_total = "Ventas totales",
utilidad_operativa = "Utilidad operativa"
)
)
# Gráfico de barras agrupadas
ggplot(
resumen_metodo,
aes(
x = metodo_venta,
y = valor,
fill = indicador
)
) +
geom_col(
position = position_dodge(width = 0.75),
width = 0.65
) +
geom_text(
aes(
label = paste0(
"$",
format(
round(valor, 2),
decimal.mark = ",",
big.mark = ".",
nsmall = 2
),
" M"
)
),
position = position_dodge(width = 0.75),
vjust = -0.35,
size = 3.8,
color = "#263238"
) +
scale_fill_manual(
values = c(
"Ventas totales" = "#164E70",
"Utilidad operativa" = "#8FA9B5"
)
) +
scale_y_continuous(
labels = function(x) {
paste0("$", format(x, decimal.mark = ",", nsmall = 0), " M")
},
expand = expansion(mult = c(0, 0.15))
) +
labs(
title = "Figura 2. Ventas y utilidad operativa por método de venta",
subtitle = "Valores acumulados expresados en millones de USD",
x = "Método de venta",
y = "Valor financiero",
fill = "Indicador"
) +
theme_minimal() +
theme(
panel.grid = element_blank(),
plot.title = element_text(
size = 16,
face = "bold",
color = "black"
),
plot.subtitle = element_text(
size = 11,
color = "#5B6770"
),
axis.title = element_text(
size = 11,
face = "bold",
color = "#263238"
),
axis.text = element_text(
size = 10,
color = "#374151"
),
legend.position = "top",
legend.title = element_text(face = "bold"),
legend.text = element_text(size = 10)
)
Figura 2
Interpretación: el canal Online genera el mayor volumen de ventas y de utilidad operativa, seguido de Outlet y de In-store. Este resultado es relevante porque, como se confirma en la sección de rentabilidad, el canal Online no solo vende más: también es el canal con mejor margen operativo promedio, es decir, combina volumen y rentabilidad.
# Resumen de ventas y utilidad operativa por distribuidor
resumen_distribuidor <- datos_col %>%
group_by(distribuidor) %>%
summarise(
ventas_total = sum(ventas_total, na.rm = TRUE),
utilidad_operativa = sum(utilidad_operativa, na.rm = TRUE),
.groups = "drop"
) %>%
pivot_longer(
cols = c(ventas_total, utilidad_operativa),
names_to = "indicador",
values_to = "valor"
) %>%
mutate(
indicador = recode(
indicador,
ventas_total = "Ventas totales",
utilidad_operativa = "Utilidad operativa"
),
valor_millones = valor / 1000000
)
# Gráfico vertical de barras agrupadas
ggplot(
resumen_distribuidor,
aes(
x = distribuidor,
y = valor_millones,
fill = indicador
)
) +
geom_col(
position = position_dodge(width = 0.75),
width = 0.55
) +
scale_fill_manual(
values = c(
"Ventas totales" = "#1F4E78",
"Utilidad operativa" = "#5B9DB5"
)
) +
scale_y_continuous(
labels = function(x) {
paste0(
"$",
format(
x,
decimal.mark = ",",
big.mark = ".",
nsmall = 1
),
" M"
)
},
expand = expansion(mult = c(0, 0.10))
) +
labs(
title = "Figura 3. Ventas y utilidad operativa por distribuidor",
subtitle = "Valores acumulados expresados en millones de USD",
x = "Distribuidor",
y = "Valor financiero",
fill = "Indicador"
) +
theme_minimal() +
theme(
panel.grid = element_blank(),
plot.title = element_text(
size = 16,
face = "bold",
color = "black"
),
plot.subtitle = element_text(
size = 11,
color = "#4B5563"
),
axis.title = element_text(
size = 11,
face = "bold",
color = "#1F2937"
),
axis.text = element_text(
size = 10,
color = "#374151"
),
axis.text.x = element_text(
angle = 35,
hjust = 1
),
legend.position = "top",
legend.title = element_text(
face = "bold",
color = "#1F2937"
),
legend.text = element_text(
color = "#374151"
)
)
Figura 3
Interpretación: West Gear y Foot Locker son los distribuidores con mayor volumen de ventas y utilidad, mientras que Amazon y Walmart presentan la menor participación dentro de este conjunto de datos. Esto sugiere que la relación comercial con distribuidores especializados de calzado/deporte (West Gear, Foot Locker, Sports Direct) es, hasta ahora, más fuerte que con los grandes marketplaces generalistas.
# Resumir unidades vendidas por producto
unidades_producto <- datos_col %>%
group_by(producto) %>%
summarise(
total_unidades = sum(unidades_vendidas, na.rm = TRUE),
ventas_totales = sum(ventas_total, na.rm = TRUE),
.groups = "drop"
) %>%
mutate(participacion_ventas = ventas_totales / sum(ventas_totales) * 100) %>%
arrange(desc(total_unidades))
# Paleta en escala de grises y azules
colores_grises_azules <- c(
"#0B2D45", # Azul marino
"#164E70", # Azul petróleo
"#287A9F", # Azul medio
"#5B9DB5", # Azul grisáceo
"#8FA9B5", # Gris azulado
"#B8C2C8", # Gris claro
"#6B7280", # Gris medio
"#374151" # Gris oscuro
)
# Repetir colores si hay más productos que colores definidos
colores_grises_azules <- rep(
colores_grises_azules,
length.out = nrow(unidades_producto)
)
# Gráfico de torta
plot_ly(
unidades_producto,
labels = ~producto, # Nombres completos en la leyenda
values = ~total_unidades,
type = "pie",
textinfo = "percent", # Solo porcentajes dentro de la torta
textposition = "inside",
insidetextorientation = "radial",
hovertemplate = paste(
"<b>%{label}</b><br>",
"Unidades vendidas: %{value:,}<br>",
"Participación: %{percent}<extra></extra>"
),
marker = list(
colors = colores_grises_azules,
line = list(
color = "#FFFFFF",
width = 2
)
)
) %>%
layout(
title = list(
text = "Figura 4. Participación de unidades vendidas por producto",
font = list(
color = "#000000",
size = 18,
family = "Arial"
)
),
showlegend = TRUE,
legend = list(
title = list(
text = "Productos"
),
orientation = "v",
x = 1,
y = 0.5,
font = list(
size = 11,
color = "#263238"
)
),
margin = list(
l = 10,
r = 220,
t = 75,
b = 10
),
paper_bgcolor = "#FFFFFF",
plot_bgcolor = "#FFFFFF"
)
Figura 4
unidades_producto %>%
mutate(
total_unidades = comma(total_unidades),
ventas_totales = dollar(ventas_totales, big.mark = ".", decimal.mark = ",", accuracy = 1),
participacion_ventas = paste0(round(participacion_ventas, 1), "%")
) %>%
kable(col.names = c("Producto", "Unidades vendidas", "Ventas totales", "Participación en ventas"),
caption = "Participación de cada línea de producto en unidades y ventas totales") %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = TRUE)
| Producto | Unidades vendidas | Ventas totales | Participación en ventas |
|---|---|---|---|
| Men’s Street Footwear | 593,320 | $27.680.769 | 23% |
| Men’s Athletic Footwear | 435,526 | $20.577.180 | 17.1% |
| Women’s Apparel | 433,827 | $23.870.985 | 19.9% |
| Women’s Street Footwear | 392,269 | $17.201.563 | 14.3% |
| Women’s Athletic Footwear | 317,236 | $14.315.521 | 11.9% |
| Men’s Apparel | 306,683 | $16.520.632 | 13.7% |
Interpretación: el portafolio de Adidas está razonablemente diversificado: ninguna línea de producto concentra más del 23% de las ventas totales. Men’s Street Footwear lidera tanto en unidades vendidas como en participación de ventas (23,0%), seguido de Women’s Apparel (19,9%). Esta diversificación reduce el riesgo de depender de una sola categoría de producto.
# Crear y mostrar el boxplot interactivo
grafico <- ggplot(datos_col,
aes(x = metodo_venta,
y = ventas_total,
fill = metodo_venta,
text = paste(
"Método:", metodo_venta,
"<br>Ventas totales:", ventas_total,
"<br>Producto:", producto,
"<br>Ciudad:", ciudad,
"<br>Distribuidor:", distribuidor
))) +
geom_boxplot() +
labs(
title = "Figura 5. Distribución de ventas totales por método de venta",
x = "Método de venta",
y = "Ventas total (USD)"
) +
theme_minimal() +
theme(
legend.position = "none",
plot.title = element_text(hjust = 0.5)
)
ggplotly(grafico, tooltip = "text")
Figura 5
q_out <- quantile(datos_col$ventas_total, c(0.25, 0.75))
iqr_out <- q_out[2] - q_out[1]
lim_sup_out <- q_out[2] + 1.5 * iqr_out
n_outliers <- sum(datos_col$ventas_total > lim_sup_out)
pct_outliers <- n_outliers / nrow(datos_col) * 100
Interpretación: en los tres métodos de venta la
distribución de ventas_total está sesgada a la derecha y
presenta numerosos valores atípicos (los puntos por encima de las
cajas), lo cual es consistente con lo observado en la sección de
indicadores generales. Usando el criterio estadístico de 1,5 veces el
rango intercuartílico (IQR), se identifican 799 registros
atípicos en el total de la base (8.3% de las observaciones):
transacciones puntuales de muy alto valor que conviene monitorear y
gestionar de forma diferenciada, ya que concentran una parte importante
de los ingresos totales.
grafico_margen_producto <- ggplot(
datos_col,
aes(x = reorder(producto, margen_operativo, FUN = median), y = margen_operativo, fill = producto,
text = paste("Producto:", producto, "<br>Margen operativo:", scales::percent(margen_operativo, accuracy = 0.1)))
) +
geom_boxplot(show.legend = FALSE) +
scale_fill_manual(values = colores_grises_azules) +
scale_y_continuous(labels = percent) +
coord_flip() +
labs(
title = "Figura 6. Distribución del margen operativo por línea de producto",
x = NULL, y = "Margen operativo"
) +
theme_minimal() +
theme(plot.title = element_text(hjust = 0.5, size = 13, face = "bold"))
ggplotly(grafico_margen_producto, tooltip = "text")
Figura 6
grafico_margen_metodo <- ggplot(
datos_col,
aes(x = reorder(metodo_venta, margen_operativo, FUN = median), y = margen_operativo, fill = metodo_venta,
text = paste("Método:", metodo_venta, "<br>Margen operativo:", scales::percent(margen_operativo, accuracy = 0.1)))
) +
geom_boxplot(show.legend = FALSE) +
scale_fill_manual(values = c("#1F4E78", "#5B9DB5", "#8FA9B5")) +
scale_y_continuous(labels = percent) +
coord_flip() +
labs(
title = "Figura 7. Distribución del margen operativo por método de venta",
x = NULL, y = "Margen operativo"
) +
theme_minimal() +
theme(plot.title = element_text(hjust = 0.5, size = 13, face = "bold"))
ggplotly(grafico_margen_metodo, tooltip = "text")
Figura 7
margen_region <- datos_col %>%
group_by(region) %>%
summarise(margen_promedio = mean(margen_operativo, na.rm = TRUE), .groups = "drop") %>%
arrange(desc(margen_promedio))
margen_region %>%
mutate(margen_promedio = paste0(round(margen_promedio * 100, 1), "%")) %>%
kable(col.names = c("Región", "Margen operativo promedio"),
caption = "Margen operativo promedio por región") %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
| Región | Margen operativo promedio |
|---|---|
| South | 46.7% |
| Midwest | 43.5% |
| Southeast | 41.9% |
| Northeast | 41% |
| West | 39.7% |
Interpretación: Men’s Street Footwear y Women’s Apparel son las líneas de producto con mayor margen operativo promedio, mientras que Men’s Athletic Footwear es la de menor margen relativo (Figura 6). Por método de venta (Figura 7), el canal Online presenta el margen más alto y menos disperso, mientras que In-store es el menos rentable en términos relativos, probablemente por mayores costos de operación física y descuentos más frecuentes. A nivel geográfico, la región South tiene el mejor margen operativo promedio del país, aun sin ser la de mayores ventas (ver tabla anterior), lo que confirma que volumen de ventas y rentabilidad relativa no siempre van de la mano.
Correlación-Dispersión
# Crear gráfico interactivo con correlación
cor_precio_unidades <- round(cor(datos_col$precio_unidad, datos_col$unidades_vendidas, use = "complete.obs"), 2)
ggplotly(
ggplot(datos_col, aes(x = precio_unidad, y = unidades_vendidas)) +
geom_point(color = "lightblue", alpha = 0.9, size = 2) +
geom_smooth(method = "lm", color = "grey", se = TRUE) +
labs(
title = paste("Figura 8. Relación entre Precio por Unidad y Unidades Vendidas \nCoef. de correlación:",
cor_precio_unidades),
x = "Precio unidad (USD)",
y = "Unidades vendidas",
caption = "Fuente: Base de datos Caso 1 - Ventas Adidas"
) +
theme_minimal() +
theme(
plot.title = element_text(size = 14, face = "bold", hjust = 0.5),
axis.title = element_text(size = 12),
axis.text = element_text(size = 10)
)
)
Figura 8
Interpretación: la correlación entre precio por unidad y unidades vendidas es positiva pero débil (r = 0.27). Esto no confirma la hipótesis de que precios más altos reducen el volumen de ventas; de hecho, la relación es ligeramente positiva, lo que sugiere que el precio está capturando en parte diferencias de categoría de producto (p. ej. calzado vs. ropa) más que un efecto de elasticidad-precio dentro de un mismo producto.
# Crear gráfico interactivo con correlación
cor_ventas_utilidad <- round(cor(datos_col$ventas_total, datos_col$utilidad_operativa, use = "complete.obs"), 2)
ggplotly(
ggplot(datos_col, aes(x = ventas_total, y = utilidad_operativa)) +
geom_point(color = "lightblue", alpha = 0.9, size = 2) +
geom_smooth(method = "lm", color = "grey", se = TRUE) +
labs(
title = paste("Figura 9. Relación entre Ventas Totales y Utilidad Operativa \nCoef. de correlación:",
cor_ventas_utilidad),
x = "Ventas totales (USD)",
y = "Utilidad operativa (USD)",
caption = "Fuente: Base de datos Caso 1 - Ventas Adidas"
) +
theme_minimal() +
theme(
plot.title = element_text(size = 14, face = "bold", hjust = 0.5),
axis.title = element_text(size = 12),
axis.text = element_text(size = 10)
)
)
Figura 9
En la Figura 9 se observa una fuerte correlación positiva entre las ventas totales y la utilidad operativa, con un coeficiente de correlación de 0.94. Esto indica que, a medida que las ventas aumentan, la utilidad operativa también crece de forma casi proporcional. Esta relación es esperable: a mayor volumen vendido, mayor utilidad en términos absolutos. Sin embargo, esto no implica que un mayor volumen de ventas garantice también un mayor margen (rentabilidad relativa), como se explora a continuación.
cor_precio_margen <- round(cor(datos_col$precio_unidad, datos_col$margen_operativo, use = "complete.obs"), 2)
ggplotly(
ggplot(datos_col, aes(x = precio_unidad, y = margen_operativo)) +
geom_point(color = "#8B5CF6", alpha = 0.7, size = 2) +
geom_smooth(method = "lm", color = "grey", se = TRUE) +
scale_y_continuous(labels = percent) +
labs(
title = paste("Figura 10. Relación entre Precio por Unidad y Margen Operativo \nCoef. de correlación:",
cor_precio_margen),
x = "Precio unidad (USD)",
y = "Margen operativo",
caption = "Fuente: Base de datos Caso 1 - Ventas Adidas"
) +
theme_minimal() +
theme(
plot.title = element_text(size = 14, face = "bold", hjust = 0.5),
axis.title = element_text(size = 12),
axis.text = element_text(size = 10)
)
)
Figura 10
Interpretación: la correlación entre precio por unidad y margen operativo es negativa y débil (r = -0.14), por lo que el precio, de forma aislada, no explica de manera importante la rentabilidad. Esto refuerza la conclusión de que el margen depende más del canal de venta y del distribuidor (secciones anteriores) que del nivel de precio en sí mismo.
# Resumir las ventas por producto y región
heatmap_producto_region <- datos_col %>%
group_by(producto, region) %>%
summarise(
ventas_total = sum(ventas_total, na.rm = TRUE),
.groups = "drop"
) %>%
pivot_wider(
names_from = region,
values_from = ventas_total,
values_fill = 0
)
# Conservar los nombres de los productos
productos <- heatmap_producto_region$producto
# Convertir los valores a una matriz numérica
matriz_heatmap <- heatmap_producto_region %>%
select(-producto) %>%
as.matrix()
# Heatmap con escala de colores fríos a cálidos
grafico_heatmap <- plot_ly(
x = colnames(matriz_heatmap),
y = productos,
z = matriz_heatmap,
type = "heatmap",
colorscale = list(
list(0.00, "#2166AC"),
list(0.25, "#67A9CF"),
list(0.50, "#FFFFBF"),
list(0.75, "#F4A582"),
list(1.00, "#B2182B")
),
colorbar = list(
title = "Ventas",
tickprefix = "$",
tickformat = ",.0f"
),
hovertemplate = paste(
"<b>Producto:</b> %{y}<br>",
"<b>Región:</b> %{x}<br>",
"<b>Ventas:</b> $%{z:,.0f}<extra></extra>"
)
) %>%
layout(
title = list(
text = "Figura 11. Mapa de calor de ventas por producto y región",
font = list(
color = "#000000",
size = 18,
family = "Arial"
),
x = 0.05
),
xaxis = list(
title = "Región",
tickfont = list(color = "#374151", size = 11),
showgrid = FALSE
),
yaxis = list(
title = "Producto",
tickfont = list(color = "#374151", size = 11),
showgrid = FALSE
),
paper_bgcolor = "#FFFFFF",
plot_bgcolor = "#FFFFFF",
margin = list(l = 160, r = 100, t = 90, b = 80)
)
# Mostrar el heatmap
grafico_heatmap
Figura 11
# Resumir el margen operativo promedio por producto y método de venta
heatmap_producto_metodo <- datos_col %>%
group_by(producto, metodo_venta) %>%
summarise(
margen_promedio = mean(margen_operativo, na.rm = TRUE),
.groups = "drop"
) %>%
pivot_wider(
names_from = metodo_venta,
values_from = margen_promedio,
values_fill = 0
)
productos_m <- heatmap_producto_metodo$producto
matriz_heatmap_m <- heatmap_producto_metodo %>%
select(-producto) %>%
as.matrix()
plot_ly(
x = colnames(matriz_heatmap_m),
y = productos_m,
z = matriz_heatmap_m,
type = "heatmap",
colorscale = list(
list(0.00, "#F7FBFF"),
list(0.50, "#6BAED6"),
list(1.00, "#08306B")
),
colorbar = list(title = "Margen", tickformat = ".0%"),
hovertemplate = paste(
"<b>Producto:</b> %{y}<br>",
"<b>Método de venta:</b> %{x}<br>",
"<b>Margen operativo promedio:</b> %{z:.1%}<extra></extra>"
)
) %>%
layout(
title = list(
text = "Figura 12. Margen operativo promedio por producto y método de venta",
font = list(color = "#000000", size = 18, family = "Arial"),
x = 0.05
),
xaxis = list(title = "Método de venta", tickfont = list(color = "#374151", size = 11), showgrid = FALSE),
yaxis = list(title = "Producto", tickfont = list(color = "#374151", size = 11), showgrid = FALSE),
paper_bgcolor = "#FFFFFF",
plot_bgcolor = "#FFFFFF",
margin = list(l = 160, r = 60, t = 90, b = 80)
)
Figura 12
Interpretación: en la Figura 11, la combinación de mayor volumen de ventas es Men’s Street Footwear en la región West, lo que la convierte en la combinación producto-región más relevante en términos comerciales. En la Figura 12, el patrón es muy claro: para todas las líneas de producto, el canal Online es el que ofrece el mayor margen operativo promedio, mientras que In-store es sistemáticamente el de menor margen. Esto sugiere una oportunidad estratégica clara: reforzar la venta online de las líneas de mayor participación (Men’s Street Footwear, Women’s Apparel) para capturar simultáneamente volumen y rentabilidad.
cor_margen_utilidad <- round(cor(datos_col$margen_operativo, datos_col$utilidad_operativa, use = "complete.obs"), 2)
ggplotly(
ggplot(datos_col, aes(x = margen_operativo, y = utilidad_operativa)) +
geom_point(color = "purple", alpha = 0.8, size = 2) +
geom_smooth(method = "loess", color = "grey", se = TRUE) +
scale_x_continuous(labels = percent) +
labs(
title = paste("Figura 13. Relación entre Margen Operativo y Utilidad Operativa \nCoef. de correlación:",
cor_margen_utilidad),
x = "Margen Operativo",
y = "Utilidad Operativa (USD)",
caption = "Fuente: Base de datos Caso 1 - Ventas Adidas"
) +
theme_minimal() +
theme(
plot.title = element_text(size = 14, face = "bold", hjust = 0.5),
axis.title = element_text(size = 12),
axis.text = element_text(size = 10)
)
)
Figura 13
Interpretación: el margen operativo y la utilidad operativa en dólares están prácticamente descorrelacionados (r = -0.05). Esto ocurre porque la utilidad en dólares depende principalmente del volumen de ventas (Figura 9), mientras que el margen depende de la eficiencia relativa de cada transacción; una transacción puede generar mucha utilidad en dólares con un margen moderado (alto volumen), o poca utilidad con un margen alto (bajo volumen). Ambas métricas son complementarias y deben monitorearse por separado.
vars_numericas <- datos_col %>%
select(precio_unidad, unidades_vendidas, ventas_total, utilidad_operativa, margen_operativo)
mat_cor <- round(cor(vars_numericas, use = "complete.obs"), 2)
mat_cor_long <- as.data.frame(mat_cor) %>%
mutate(var1 = rownames(mat_cor)) %>%
pivot_longer(-var1, names_to = "var2", values_to = "correlacion")
plot_ly(
x = colnames(mat_cor),
y = rownames(mat_cor),
z = mat_cor,
type = "heatmap",
colorscale = list(
list(0.00, "#B2182B"),
list(0.50, "#FFFFFF"),
list(1.00, "#2166AC")
),
zmin = -1, zmax = 1,
colorbar = list(title = "r"),
hovertemplate = "<b>%{y} vs %{x}</b><br>r = %{z}<extra></extra>"
) %>%
layout(
title = list(text = "Figura 14. Matriz de correlación entre variables numéricas",
font = list(color = "#000000", size = 18, family = "Arial"), x = 0.05),
xaxis = list(title = "", tickfont = list(size = 10)),
yaxis = list(title = "", tickfont = list(size = 10)),
paper_bgcolor = "#FFFFFF",
plot_bgcolor = "#FFFFFF",
margin = list(l = 140, r = 60, t = 90, b = 100)
)
Figura 14
Interpretación: la matriz de correlación resume los
hallazgos anteriores: unidades_vendidas y
ventas_total están muy fuertemente correlacionadas (r =
0.92), al igual que ventas_total y
utilidad_operativa (r = 0.94). En contraste,
margen_operativo tiene correlaciones negativas y débiles
con unidades_vendidas (r = -0.31) y con
ventas_total (r = -0.3), lo que confirma que los
productos o transacciones de mayor volumen tienden a operar, en
promedio, con un margen ligeramente menor — un clásico
trade-off entre volumen y rentabilidad relativa.
unidades_vendidas (r = 0.27) y con
margen_operativo (r = -0.14) son débiles.El análisis descriptivo y diagnóstico muestra una compañía con un portafolio de producto diversificado y un desempeño de ventas fuertemente influenciado por la región y, sobre todo, por el canal de venta. La rentabilidad (margen operativo) no está determinada principalmente por el precio, sino por cómo y dónde se vende el producto. A partir de estos hallazgos se proponen las siguientes recomendaciones de negocio (analítica prescriptiva):
Estas recomendaciones deberían complementarse, en una siguiente fase, con información adicional no disponible en este dataset (por ejemplo, costos de marketing por canal o datos con marca temporal que permitan calcular tasas de crecimiento en el tiempo), pero constituyen un punto de partida sólido y basado en evidencia para la toma de decisiones comerciales de Adidas.