Venta de Refrigeradoras

Considere una compañía que se dedica a la venta de refrigeradoras. La demanda diaria de refrigeradoras se puede observar en la siguiente tabla.

Demanda Probabilidad
0 0.10
1 0.25
2 0.35
3 0.21
4 0.09

Cuando se hace un pedido a la compañía que les vende la refrigeradoras esta se tarda un tiempo determinado el cual es estocástico y se pueden ver las probabilidades en la siguiente tabla. (Tiempo de Abastecimiento)

Dias abastecimiento Probabilidad
1 0.6
2 0.3
3 0.1

Las órdenes se hacen al final del día y las órdenes se reciben al inicia del dia. Si no hay refrigeradoras en la tienda entonces no se le pueden vender al cliente.

El objetivo es determinar en qué nivel de inventario se debe de hacer el pedido para minimizar la cantidad de clientes a los que no se les puede vender una refrigeradora también el tamaño de la orden.

El maximo numero en bodega es de 10

Generacion de dataframe

Para generar el dataframe de 30 dias, para un valor inicial de inventario y abastecimientos varios iniciamos creando un dataframe , parametrizable, con inventario de inicio N. Este dataframe finaliza cuando el inventario se agoto (M=0) o es negativo.

La funcion se llama inv() y es la siguiente:

inv <- function(N=10,M=0){
  
# Inicializacion de variables
  
i <- 1
inv_inicial <- N
inv_final <- M+1

# Inicializacion de vectores de demanda

pv_d <- c(0.1,0.25,0.35,0.21,0.09)
d <- c(0,1,2,3,4)
demanda <- 0

# Finalizar hasta que el inventario llege a cero o negativo

while (inv_final[i] > M) {
  
  demanda[i] <- sample(d,1,replace = T,pv_d)
  
  if (inv_inicial[i]-demanda[i] > M) {
    inv_final[i] <- inv_inicial[i] - demanda[i]
    inv_inicial[i+1] <- inv_final[i]
    inv_final[i+1] <- inv_final[i]
    
  } else {
    inv_final[i] <- inv_inicial[i]-demanda[i]
    inv_final[i+1] <- inv_final[i]
  }
  i <- i + 1
}

df <- data.frame(x=inv_inicial,y=inv_final[-length(inv_final)],demanda)
return(df)
}

El valor default es N=10:

inv()
##    x  y demanda
## 1 10  8       2
## 2  8  6       2
## 3  6  6       0
## 4  6  6       0
## 5  6  4       2
## 6  4  2       2
## 7  2  1       1
## 8  1 -2       3

Donde “x” es el inventario inicial, “y” es el final y “demanda”" es la demanda estocastica dada al inicio.

Para generar un dataframe de 30 dias procedemos de la siguiente forma:

Generamos varios dataframes a partir de la funcion inv(). Como lo que se busca es reabastacer para tres niveles de inventario: 0, 1 y 2, buscamos en la variable inventario final (y) el indice donde el inventario llega a este nivel. Una vez encontramos este indice, “concatenamos” un segundo dataframe al inicial, luego volvemos a revisar el indice donde el inventario final llega a 0,1 o 2 y ahi volvemos a pegar otro dataframe. Este proceso sigue hasta que se genera un dataframe de 30 indices o dias.

Como el reabastecimiento puede ocurrir en 1,2 o 3 dias, tenemos especial cuidado de pegar el siguiente dataframe en los dias que corresponde.

La funcion que logra esto se llama stochastic_inv:

stochastic_inv <- function(N=10) {

pv_t <- c(0.6,0.3,0.1)
t <- c(1,2,3)

pv_d <- c(0.1,0.25,0.35,0.21,0.09)
d <- c(0,1,2,3,4)

t_r <- 0
r1 <- c(0,0,0)
f <- 0
f1 <- 0
j <- 0
z <- rep(NA,30)


# generacion de dataframe inicial

f <- inv(N)  

# indice para iniciar reabastecimiento

index <- min(which(f$y <= 0 | f$y==1 | f$y ==2,arr.ind = F)) 

# Condicion para generar 30 dias (o indices)

while (length(f$y) <= 30) {

      j <- (j+1)  
      t_r[j] <- sample(t,1,replace = T,pv_t)
      f1 <- inv(N)
      index2 <- min(which(f1$y <= 0 | f1$y==1 | f1$y ==2,arr.ind = F))
      z[index] <- t_r[j]
    
      if (t_r[j] == 1) {
        f <- rbind(f[1:index,],f1)   
        }
      if (t_r[j] == 2) { 
        r1[3] <- sample(d,1,replace = T,pv_d)
        f <- rbind(f,r1)
        f <- rbind(f[1:(index+1),],f1)
        index <- index + 1
        }
      if (t_r[j] == 3) {
        r1[3] <- sample(d,1,replace = T,pv_d)
        f <- rbind(f,r1,r1)
        f <- rbind(f[1:(index+2),],f1)
        index <- index + 2
      }
      
    index <- index + index2
  
}

demanda_ins <- f$x-f$demanda

for (i in 1:length(demanda_ins)) {

  if (demanda_ins[i] >= 0) {demanda_ins[i] <- 0}
  if (demanda_ins[i] < 0 ) {demanda_ins[i] <- f$demanda[i] - f$x[i]}

}

f <- cbind(f,demanda_ins)
f <- f[1:30,]
f <- cbind(f,z)
f <- rename(f,c("x"="inicial","y"="final","z" = "reabastecimiento"))

return(f) 

}

Un mes o 30 dias para un nivel de inventario N=10 y un nivel de reabastecimiento M=2 es:

stochastic_inv(10)
##    inicial final demanda demanda_ins reabastecimiento
## 1       10     8       2           0               NA
## 2        8     8       0           0               NA
## 3        8     7       1           0               NA
## 4        7     3       4           0               NA
## 5        3     1       2           0                3
## 6        1    -1       2           1               NA
## 7        0     0       3           3               NA
## 8       10     7       3           0               NA
## 9        7     6       1           0               NA
## 10       6     6       0           0               NA
## 11       6     2       4           0                1
## 12      10     9       1           0               NA
## 13       9     6       3           0               NA
## 14       6     4       2           0               NA
## 15       4     3       1           0               NA
## 16       3     1       2           0                1
## 17      10     7       3           0               NA
## 18       7     5       2           0               NA
## 19       5     3       2           0               NA
## 20       3     1       2           0                1
## 21      10     8       2           0               NA
## 22       8     4       4           0               NA
## 23       4     3       1           0               NA
## 24       3     1       2           0                1
## 25      10     9       1           0               NA
## 26       9     6       3           0               NA
## 27       6     3       3           0               NA
## 28       3     1       2           0                1
## 29      10     9       1           0               NA
## 30       9     8       1           0               NA

Simulacion de escenarios.

Lo que nos interesa en este problema es la combinacion de N y M que produce la menor demanda insatisfecha (4a columna del dataframe). Debido a que todos los dias hay demanda, en un periodo de 30 dias, hay dias en que la demanda insatisfecha es mayor o menor. La figura de merito que buscamos es entonces el numero de refrigeradores que se dejan de vender. Para esto vamos a calcular la suma de refrigeradoras que se dejan de vender, para varios escenarios de M y N y veremos cual es el optimo.

Reabastecimiento de inventario en M=2

Probamos 3 escenarios para un nivel de reabastecimiento M=2:

x1 <- rep(0,1000)
x2 <- rep(0,1000)
x3 <- rep(0,1000)

for (i in 1:1000) {
  
  d <- stochastic_inv()
  x1[i] <- sum(d$demanda_ins)
  
  e <- stochastic_inv(8)
  x2[i] <- sum(e$demanda_ins)
  
  f <- stochastic_inv(6)
  x3[i] <- sum(f$demanda_ins)
}
x <- c(mean(x1),mean(x2),mean(x3))
x
## [1] 3.348 4.196 5.686

En este caso el mejor escenario es N=10 y M=2.

Reabastecimiento de inventario en M=1

Para este escenario modificamos la funcion stochastic_inv() para buscar niveles de inventario final de 0 o 1:

stochastic_inv2 <- function(N=10) {
  
  pv_t <- c(0.6,0.3,0.1)
  t <- c(1,2,3)
  
  pv_d <- c(0.1,0.25,0.35,0.21,0.09)
  d <- c(0,1,2,3,4)
  
  t_r <- 0
  r1 <- c(0,0,0)
  f <- 0
  f1 <- 0
  j <- 0
  z <- rep(NA,30)
  
  
  # generacion de dataframe inicial
  
  f <- inv(N)  
  
  # indice para iniciar reabastecimiento
  
  index <- min(which(f$y <= 0 | f$y==1,arr.ind = F)) 
  
  # Condicion para generar 30 dias (o indices)
  
  while (length(f$y) <= 30) {
    
    j <- (j+1)  
    t_r[j] <- sample(t,1,replace = T,pv_t)
    f1 <- inv(N)
    index2 <- min(which(f1$y <= 0 | f1$y==1,arr.ind = F))
    z[index] <- t_r[j]
    
    if (t_r[j] == 1) {
      f <- rbind(f[1:index,],f1)   
    }
    if (t_r[j] == 2) { 
      r1[3] <- sample(d,1,replace = T,pv_d)
      f <- rbind(f,r1)
      f <- rbind(f[1:(index+1),],f1)
      index <- index + 1
    }
    if (t_r[j] == 3) {
      r1[3] <- sample(d,1,replace = T,pv_d)
      f <- rbind(f,r1,r1)
      f <- rbind(f[1:(index+2),],f1)
      index <- index + 2
    }
    
    index <- index + index2
    
  }
  
  demanda_ins <- f$x-f$demanda
  
  for (i in 1:length(demanda_ins)) {
    
    if (demanda_ins[i] >= 0) {demanda_ins[i] <- 0}
    if (demanda_ins[i] < 0 ) {demanda_ins[i] <- f$demanda[i] - f$x[i]}
    
  }
  
  f <- cbind(f,demanda_ins)
  f <- f[1:30,]
  f <- cbind(f,z)
  f <- rename(f,c("x"="inicial","y"="final","z" = "reabastecimiento"))
  
  return(f) 
  
}

A partir de esta funcion ya podemos simular tres escenarios: N=10/M=1 , N=8/M=1 y N=6/M=1

x1 <- rep(0,1000)
x2 <- rep(0,1000)
x3 <- rep(0,1000)

for (i in 1:1000) {
  
  d <- stochastic_inv2()
  x1[i] <- sum(d$demanda_ins)
  
  e <- stochastic_inv2(8)
  x2[i] <- sum(e$demanda_ins)
  
  f <- stochastic_inv2(6)
  x3[i] <- sum(f$demanda_ins)
}

y <- c(mean(x1),mean(x2),mean(x3))
y
## [1] 5.278 6.474 8.425

Vemos que la demanda insatisfecha es aun mayor que en el caso de M=2.

Conclusiones

De los valores promedio de demanda insatisfecha vemos que el escenario de inventario N=10 y reabastecimiento M=2 es el optimo. Las razones son las siguientes: