El objetivo es estimar el inventario ideal para cada producto utilizando la demanda histórica mensual y un nivel de servicio del 95%.
El modelo utilizado será:
\[ Inventario\ Ideal = \mu + Z\sigma \]
Donde:
library(readxl)
library(dplyr)
library(tidyr)
library(ggplot2)
inventario <- read_excel(
"C:/Users/isaac/Searches/Downloads/Ejercicio Análisis de Inventario y Nivel de Servicio (1) (1) (1) (1).xlsx"
)
head(inventario)
## # A tibble: 6 × 14
## Producto Enero Febrero Marzo Abril Mayo Junio Julio Agosto Septiembre Octubre
## <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 DAC0023… 0 0 0 0 0 0 0 0 0 0
## 2 DAC0023… 0 0 0 0 0 0 0 0 0 0
## 3 DAC0023… 0 0 0 0 0 0 0 0 0 0
## 4 DAX0041… 0 0 0 0 0 0 0 0 0 0
## 5 DAX0041… 0 0 0 0 0 0 0 0 0 0
## 6 DAX0041… 0 0 0 0 0 0 0 0 0 0
## # ℹ 3 more variables: Noviembre <dbl>, Diciembre <dbl>, `Costo unitario` <dbl>
La base original se encuentra en formato ancho. Se transforma a formato largo para facilitar el análisis.
inventario_long <- inventario %>%
pivot_longer(
cols = -c(Producto, `Costo unitario`),
names_to = "Mes",
values_to = "Cantidad"
) %>%
mutate(
`Costo unitario` = as.numeric(`Costo unitario`),
Cantidad = as.integer(Cantidad)
)
head(inventario_long)
## # A tibble: 6 × 4
## Producto `Costo unitario` Mes Cantidad
## <chr> <dbl> <chr> <int>
## 1 DAC00238020 1 Enero 0
## 2 DAC00238020 1 Febrero 0
## 3 DAC00238020 1 Marzo 0
## 4 DAC00238020 1 Abril 0
## 5 DAC00238020 1 Mayo 0
## 6 DAC00238020 1 Junio 0
n_distinct(inventario_long$Producto)
## [1] 4770
inventario_long %>%
group_by(Producto) %>%
summarise(n = n()) %>%
count(n)
## # A tibble: 1 × 2
## n nn
## <int> <int>
## 1 12 4770
Interpretación:
Cada producto tiene exactamente 12 observaciones correspondientes a los meses de enero a diciembre.
Se clasifican las referencias según si presentan o no movimiento.
clasif <- inventario_long %>%
group_by(Producto) %>%
summarise(
Total_Demanda = sum(Cantidad)
) %>%
mutate(
Estado = ifelse(
Total_Demanda > 0,
"Activo",
"Sin movimiento"
)
)
head(clasif)
## # A tibble: 6 × 3
## Producto Total_Demanda Estado
## <chr> <int> <chr>
## 1 4135061001 0 Sin movimiento
## 2 523560 0 Sin movimiento
## 3 525015 0 Sin movimiento
## 4 AC000001222 0 Sin movimiento
## 5 AC000002222 0 Sin movimiento
## 6 AC000005020 2 Activo
clasificacion_resumen <- inventario_long %>%
group_by(Producto) %>%
summarise(
Total = sum(Cantidad)
) %>%
summarise(
Productos_con_demanda = sum(Total > 0),
Productos_sin_demanda = sum(Total == 0)
)
clasificacion_resumen
## # A tibble: 1 × 2
## Productos_con_demanda Productos_sin_demanda
## <int> <int>
## 1 2449 2320
Interpretación:
La base contiene productos activos y productos sin movimiento. Los productos sin demanda representan oportunidades potenciales de optimización del inventario.
Para el análisis del inventario ideal se consideran únicamente las referencias con movimiento.
productos_activos <- inventario_long %>%
group_by(Producto) %>%
filter(sum(Cantidad) > 0)
head(productos_activos)
## # A tibble: 6 × 4
## # Groups: Producto [1]
## Producto `Costo unitario` Mes Cantidad
## <chr> <dbl> <chr> <int>
## 1 DAB28248025 105484. Enero 0
## 2 DAB28248025 105484. Febrero 0
## 3 DAB28248025 105484. Marzo 0
## 4 DAB28248025 105484. Abril 0
## 5 DAB28248025 105484. Mayo 0
## 6 DAB28248025 105484. Junio 0
Supuestos:
#Calculo Inventario Ideal
resumen <- productos_activos %>%
group_by(Producto) %>%
summarise(
Demanda_Promedio = mean(Cantidad),
Desv_Demanda = sd(Cantidad),
Costo_Unitario = first(`Costo unitario`)
) %>%
mutate(
Inventario_Seguridad =
1.645 * Desv_Demanda,
Inventario_Ideal =
Demanda_Promedio +
Inventario_Seguridad,
Nivel_Servicio = "95%"
)
head(resumen)
## # A tibble: 6 × 7
## Producto Demanda_Promedio Desv_Demanda Costo_Unitario Inventario_Seguridad
## <chr> <dbl> <dbl> <dbl> <dbl>
## 1 AC000005020 0.167 0.577 1250 0.950
## 2 AGBGRASA030 96.3 152. 26.8 249.
## 3 AHB0AW68116 0.0833 0.289 317625. 0.475
## 4 AHB80W90050 0.25 0.452 460139. 0.744
## 5 AHB85W14050 0.0833 0.289 469317. 0.475
## 6 AHBNTO68030 3.42 2.07 342304. 3.40
## # ℹ 2 more variables: Inventario_Ideal <dbl>, Nivel_Servicio <chr>
df_estado <- data.frame(
Estado = c("Con demanda", "Sin demanda"),
Cantidad = c(2449, 2320)
)
ggplot(
df_estado,
aes(
x = Estado,
y = Cantidad,
fill = Estado
)
) +
geom_col() +
labs(
title = "Clasificación de productos según demanda",
x = "",
y = "Número de productos"
) +
theme_minimal()
Interpretación:
La distribución muestra que una proporción importante de las referencias no presenta movimiento durante el período analizado.
#Visualización 2: Distribución de la demanda promedio
ggplot(
resumen,
aes(x = Demanda_Promedio)
) +
geom_histogram(
bins = 30,
fill = "steelblue"
) +
labs(
title = "Distribución de la demanda promedio",
x = "Demanda promedio",
y = "Frecuencia"
) +
theme_minimal()
Interpretación:
La mayoría de los productos presenta una demanda promedio baja, mientras que un grupo reducido concentra gran parte del consumo.
#Visualización 3: Inventario ideal vs demanda promedio
ggplot(
resumen,
aes(
x = Demanda_Promedio,
y = Inventario_Ideal
)
) +
geom_point(alpha = 0.5) +
labs(
title = "Inventario ideal vs demanda promedio",
x = "Demanda promedio",
y = "Inventario ideal"
) +
theme_minimal()
Interpretación:
Existe una relación positiva entre demanda promedio e inventario ideal. Los productos con mayor demanda requieren mayores niveles de inventario y stock de seguridad.
El modelo utiliza:
Z = 1.645 pnorm(1.645) Interpretación:
El valor corresponde aproximadamente a un nivel de servicio del 95%.
Se analizaron las referencias con movimiento durante el período. Se utilizó un modelo probabilístico basado en demanda promedio y desviación estándar. El inventario ideal se calculó como:
Inventario Ideal = \(\mu\) + 1.645\(\sigma\)
El nivel de servicio teórico alcanzado es del 95%. Los productos con mayor variabilidad requieren un mayor inventario de seguridad.