AD3003B Analítica Prescriptiva
Módulo 1 – Analítica Espacial de Datos
Febrero – Junio 2025
Instrucciones:
A partir de la base de datos “regional_price_dataset.csv” calcular los
diferentes precios elasticidad e ingresos óptimos para las zonas norte,
centro y sur.
library(ggplot2)
library(dplyr)
library(readr)
library(lubridate)
library(tidyverse)
df <- read.csv("C:\\Users\\Diego Pérez\\Downloads\\regional_price_dataset.csv")
df$fecha <- as.Date(df$fecha)
# Columna ingreso
df <- df %>% mutate(ingreso = precio * cantidad)
# Ver registros
head(df)
## fecha zona precio cantidad ingreso
## 1 2018-01-01 Centro 13.7 195 2671.5
## 2 2018-01-01 Norte 13.7 149 2041.3
## 3 2018-01-01 Sur 13.7 168 2301.6
## 4 2018-01-02 Centro 13.7 221 3027.7
## 5 2018-01-02 Norte 13.7 179 2452.3
## 6 2018-01-02 Sur 13.7 183 2507.1
# Agregar columna de semana
df <- df %>%
mutate(semana = floor_date(fecha, unit = "week"))
# Agrupar por semana y zona
df_semanal <- df %>%
group_by(zona, semana) %>%
summarise(cantidad = sum(cantidad), .groups = "drop")
# Gráfico de series
ggplot(df_semanal, aes(x = semana, y = cantidad, color = zona)) +
geom_line(size = 1) +
labs(
title = "Serie de Tiempo de Cantidad por Región (Datos Semanales)",
x = "Fecha (Inicio de la Semana)",
y = "Cantidad"
) +
theme_minimal()
# Convertir fecha y extraer día de la semana
df <- df %>%
mutate(
fecha = as.Date(fecha),
dia_semana = wday(fecha, label = TRUE, abbr = FALSE, week_start = 1)
)
# Gráfico tipo boxplot
ggplot(df, aes(x = dia_semana, y = cantidad, fill = zona)) +
geom_boxplot(outlier.shape = 1) +
labs(
title = "Distribución de cantidad por día de la semana y zona",
x = "Día de la semana",
y = "Cantidad"
) +
theme_minimal()
# Asegurar que la fecha es tipo Date
df <- df %>%
mutate(fecha = as.Date(fecha))
# Visualizar el precio por zona a lo largo del tiempo
ggplot(df, aes(x = fecha, y = precio, color = zona)) +
geom_line() +
labs(
title = "Evolución del Precio por Zona",
x = "Fecha", y = "Precio"
) +
theme_minimal()
# Visualizar la cantidad por zona a lo largo del tiempo
ggplot(df, aes(x = fecha, y = cantidad, color = zona)) +
geom_line() +
labs(
title = "Evolución de la Cantidad Vendida por Zona",
x = "Fecha", y = "Cantidad Vendida"
) +
theme_minimal()
# Agrupar y calcular la cantidad promedio vendida por día de la semana (todas las zonas)
df_dia <- df %>%
group_by(dia_semana) %>%
summarise(cantidad_promedio = mean(cantidad))
# Visualizador: barras por día de la semana
ggplot(df_dia, aes(x = dia_semana, y = cantidad_promedio)) +
geom_col(fill = "steelblue") +
labs(
title = "Promedio de ventas por día de la semana (todas las zonas)",
x = "Día de la semana",
y = "Cantidad promedio vendida"
) +
theme_minimal()
# Calcular cantidad promedio por día y zona
df_dia_zona <- df %>%
group_by(zona, dia_semana) %>%
summarise(cantidad_promedio = mean(cantidad), .groups = "drop")
# Visualizador: barras por día y zona
ggplot(df_dia_zona, aes(x = dia_semana, y = cantidad_promedio, fill = zona)) +
geom_col(position = "dodge") +
labs(
title = "Promedio de ventas por día de la semana por zona",
x = "Día de la semana",
y = "Cantidad promedio vendida"
) +
theme_minimal()
# Agrupar por semana y zona
df_semanal <- df %>%
group_by(zona, semana) %>%
summarise(
cantidad_total = sum(cantidad),
precio_promedio = mean(precio),
.groups = "drop"
)
# Visualizador: evolución de cantidad semanal por zona
ggplot(df_semanal, aes(x = semana, y = cantidad_total, color = zona)) +
geom_line(size = 1) +
labs(
title = "Evolución semanal de cantidad vendida por zona",
x = "Semana",
y = "Cantidad total vendida"
) +
theme_minimal()
# Gráfico de dispersión con tendencia
ggplot(df, aes(x = precio, y = cantidad, color = zona)) +
geom_point(alpha = 0.6) +
geom_smooth(method = "lm", se = FALSE) +
labs(
title = "Relación entre precio y cantidad vendida",
x = "Precio",
y = "Cantidad vendida"
) +
theme_minimal()
# Modelo lineal por zona
ggplot(df, aes(x = precio, y = cantidad, color = zona)) +
geom_point(alpha = 0.5) +
geom_smooth(method = "lm", se = FALSE) +
facet_wrap(~ zona) +
labs(
title = "Modelos de demanda por zona (regresión lineal)",
x = "Precio",
y = "Cantidad vendida"
) +
theme_minimal()
modelos <- df %>%
group_by(zona) %>%
group_map(~ lm(cantidad ~ precio, data = .x), .keep = TRUE)
summary(modelos[[1]])
##
## Call:
## lm(formula = cantidad ~ precio, data = .x)
##
## Residuals:
## Min 1Q Median 3Q Max
## -77.403 -22.115 -5.413 15.883 120.316
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 299.6711 5.7533 52.09 <2e-16 ***
## precio -7.1412 0.4809 -14.85 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 33.32 on 495 degrees of freedom
## Multiple R-squared: 0.3082, Adjusted R-squared: 0.3068
## F-statistic: 220.5 on 1 and 495 DF, p-value: < 2.2e-16
# Calcular elasticidad por zona
elasticidades <- df %>%
group_by(zona) %>%
summarise(
modelo = list(lm(cantidad ~ precio, data = cur_data())),
precio_prom = mean(precio),
cantidad_prom = mean(cantidad)
) %>%
mutate(
pendiente = map_dbl(modelo, ~ coef(.x)[["precio"]]),
elasticidad = pendiente * (precio_prom / cantidad_prom)
) %>%
select(zona, pendiente, precio_prom, cantidad_prom, elasticidad)
print(elasticidades)
## # A tibble: 3 × 5
## zona pendiente precio_prom cantidad_prom elasticidad
## <chr> <dbl> <dbl> <dbl> <dbl>
## 1 Centro -7.14 11.6 217. -0.380
## 2 Norte -13.8 11.6 201. -0.792
## 3 Sur -6.08 11.6 167. -0.420
# Visualizar como gráfico de barras
ggplot(elasticidades, aes(x = zona, y = elasticidad, fill = zona)) +
geom_col() +
geom_text(aes(label = round(elasticidad, 2)), vjust = -0.5) +
labs(
title = "Elasticidad precio de la demanda por zona",
x = "Zona",
y = "Elasticidad estimada"
) +
theme_minimal()
get_precio_optimo <- function(modelo, zona) {
coef <- coef(modelo)
a <- coef[1]
b <- coef[2]
precio_optimo <- -a / (2 * b)
cat("Zona:", zona, "\n")
cat("Modelo: cantidad =", round(a, 2), "+", round(b, 2), "* precio\n")
cat("Precio óptimo:", round(precio_optimo, 2), "\n\n")
return(precio_optimo)
}
# Obtener zonas
zonas <- unique(df$zona)
# Calcular precio óptimo por zona
precios_optimos <- mapply(get_precio_optimo, modelos, zonas)
## Zona: Centro
## Modelo: cantidad = 299.67 + -7.14 * precio
## Precio óptimo: 20.98
##
## Zona: Norte
## Modelo: cantidad = 360.88 + -13.81 * precio
## Precio óptimo: 13.06
##
## Zona: Sur
## Modelo: cantidad = 237.18 + -6.08 * precio
## Precio óptimo: 19.52
# Crear una secuencia de precios simulados
precios_simulados <- seq(1, 25, length.out = 200)
# Calcular ingresos estimados por zona usando el modelo lineal
simular_ingresos <- function(modelo, zona) {
coefs <- coef(modelo)
a <- coefs[1]
b <- coefs[2]
cantidad_estimada <- a + b * precios_simulados
ingreso_estimado <- precios_simulados * cantidad_estimada
data.frame(
zona = zona,
precio = precios_simulados,
ingreso = ingreso_estimado, # <- CORREGIDO
precio_optimo = -a / (2 * b)
)
}
# Aplicar a cada zona
df_ingresos_simulados <- purrr::map2_dfr(modelos, zonas, simular_ingresos)
# Graficar
ggplot(df_ingresos_simulados, aes(x = precio, y = ingreso)) +
geom_line(aes(color = zona), size = 1.2) +
geom_vline(aes(xintercept = precio_optimo, color = zona), linetype = "dashed") +
labs(
title = "Ingreso estimado vs Precio por zona",
subtitle = "Línea punteada indica el precio óptimo",
x = "Precio",
y = "Ingreso estimado"
) +
theme_minimal() +
expand_limits(x = c(0, 25))
La obtención del “precio ideal” que permita maximizar los ingresos. Buscando obtener un equilibrio entre la mayor cantidad de unidades vendidas y la obtención de ganancias.
La relación nos ayuda a determinar que tanto cambia la cantidad vendida al modificar el precio del producto.
La adaptación del precio a las caracteristicas de elasticidad de cada región.