# 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
)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")
)
# 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
## 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, …
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)| 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).
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)| 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()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()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()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()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()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()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)| 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()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()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()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()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:
## 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")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))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()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")| 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 |
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.
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.
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))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