Simulacion de la cola en un Banco

Para resolver este problema se desarrollaron varias funciones:

  1. Funciones de la forma MMk_queue.R. Estas funciones reciben como parametro el dia de la semana, y en base a la distribucion de llegadas para los 7 dias de la semana, generan un dataframe por dia (8 hrs = 480 minutos). Se desarrollaron 7 funciones, una para tipo de cola: MM1_queue.R , MM2_queue.R, MM3_queue.R, MM4_queue.R , MM5_queue.R, MM6_queue.R y MM7_queue.R.

  2. Luego se desarrollo script que barre por los 7 dias de la semana y hace esto por 52 semanas (1 año). Es decir se genera un dataframe de un año por cada una de las 7 configuraciones de cola.

  3. La funcion queue_performance.R, recibe el dataframe correspondiente a un año para cada cola (MMk_queue.R) y calcula los parametros de rendimiento de la cola.

Funciones MMk_queue.R

Estas funciones reciben como parametro el dia de la semana, que va de 1 a 7 (1 = Lunes, 2 = Martes,…, 7 = Domingo) y devuelven un dataframe de duracion 480 minutos y que toma en cuenta el numero de servidores: 1,2,3,4,5,6 o 7.

Su funcionamiento es el siguiente:

  1. Se generan los tiempos de llegada de acuerdo al dia. El limite maximo de arribos es de hasta 480 minutos ya que el banco trabaja 8 hrs. (10:00 a 18:00 hrs).

  2. Los primeros k clientes entran directo al servicio, es decir no hacen cola ya que hay k servidores disponibles.

  3. A partir del cliente k+1 hay que revisar que servidor esta disponible. Si el tiempo de llegada del siguiente cliente es mayor que el tiempo de liberacion de cualquiera de los k servidores, el usuario entra directo a servicio.

  4. Si el tiempo de llegada del siguiente cliente es menor que el tiempo de desocupacion de cualquiera de los k servidores, el cliente espera hasta que cualquier servidor se desocupe. El primer servidor desocupado es el que da el servicio. Esto se verifica con la funcion min().

Un ejemplo de esta funcion para k = 3 (3 servidores) se muestra a continuacion:

MM3_queue <- function(dia=1) {
  
  #  Synopsis:  Funcion que simula una cola de k servidores.  Se recibe como parametro el dia
  #  de la semana y en base a esto se calcula la distribucion de llegada.  La funcion devuelve 
  #  un dataframe de 480 minutos (8 hrs.)
  
  
  #  Initialize
  
  if (dia==1) p <- c(0.1,0.15,0.1,0.35,0.25,0.05,0)
  if (dia==2) p <- c(0.1,0.1,0.15,0.2,0.35,0.1,0)
  if (dia==3) p <- c(0,0.1,0.1,0.2,0.1,0.25,0.25)
  if (dia==4) p <- c(0,0.15,0.2,0.2,0.15,0.15,0.15) 
  if (dia==5) p <- c(0.15,0.15,0.2,0.2,0.1,0.1,0.1)
  if (dia==6) p <- c(0.2,0.15,0.1,0.5,0.05,0,0)
  if (dia==7) p <- c(0.35,0.25,0.2,0.1,0.1,0,0)
  
  inter_times <- c(0,1,2,3,4,5,6)  
  
  arrival_times <- 0
  interarrival_times <- 0
  k <- 3
  
  
  # Interarrival times.  Se calcula el numero N de clientes que llegan a la cola
  #  de acuerdo a la probabilidad de llegada.
  
  arrival_times[1] <- sample(inter_times,1,replace = T,prob = p)
  N <- 1
  
  while (arrival_times[N] < 480) {
    
    N <- N + 1   
    interarrival_times[N] <- sample(inter_times,1,replace = T,prob = p)
    arrival_times[N] <- arrival_times[N-1] + interarrival_times[N]
  }
  
  # Service times
  
  service_times <- ceiling(abs(rnorm(N,mean=8,sd=5)))
  
  # vectors to track service time and departure
  
  enter_service_times <- rep(0,N)
  completion_times <- rep(0,N)
  idle_time_server <- rep(0,N)
  server_time <- rep(0,k)
  
  # first k customers.  Para k=3 , los primeros tres clientes no hacen cola.
  
  for (j in 1:k) {
    
    enter_service_times[j] <- arrival_times[j]
    completion_times[j] <- enter_service_times[j]+service_times[j]
    server_time[j] <- completion_times[j]
    
  }
  
  # Loop through the remaining customers.  Esta parte calcula la cola. Basicamente se revisa
  # el servidor que este disponible con la funcion min(x,y) y ese se asigna para el siguiente 
  # cliente en cola
  
  for (i in seq(from=(k+1), to=N, by=1)) {
     
    # En esta parte se revisa si cuando el siguiente cliente llega hay algun servidor 
    # disponible
    
    if (arrival_times[i] >= server_time[1]) {
      
      enter_service_times[i] <- arrival_times[i]
      completion_times[i] <- enter_service_times[i]+service_times[i]  
      server_time[1] <- completion_times[i]
      
      } else if (arrival_times[i] >= server_time[2]) {
        
        enter_service_times[i] <- arrival_times[i]
        completion_times[i] <- enter_service_times[i]+service_times[i]  
        server_time[2] <- completion_times[i]
      
        } else if (arrival_times[i] >= server_time[3]) {
          
          enter_service_times[i] <- arrival_times[i]
          completion_times[i] <- enter_service_times[i]+service_times[i]  
          server_time[3] <- completion_times[i]
    
    # Si el siguiente cliente en cola, encuentra los servidores ocupados, esta parte 
    # revisa cual de los tres servidores esta libre antes. Esto se revisa via la funcion
    #  min(x,y,z)
      
          } else  if (server_time[1] == min(server_time)) {
            
            enter_service_times[i] <- server_time[1]
            completion_times[i] <- enter_service_times[i]+service_times[i] 
            server_time[1] <- completion_times[i]
      
            } else if (server_time[2] == min(server_time)) {
              
              enter_service_times[i] <- server_time[2]
              completion_times[i] <- enter_service_times[i]+service_times[i] 
              server_time[2] <- completion_times[i]
    
              } else if (server_time[3] == min(server_time)) {
              
              enter_service_times[i] <- server_time[3]
              completion_times[i] <- enter_service_times[i]+service_times[i] 
              server_time[3] <- completion_times[i]
            }
    
}
  
  
  waiting_time_q <- enter_service_times - arrival_times
  total_time <- completion_times - arrival_times
  
  df <- data.frame(entre_llegadas=interarrival_times,llegadas=arrival_times,tiempo_servicio=service_times,inicio_servicio=enter_service_times,finalizacion=completion_times)
  return(df)
  
}

El resultado de la funcion es:

head(MM3_queue(),10)
##    entre_llegadas llegadas tiempo_servicio inicio_servicio finalizacion
## 1               0        4              13               4           17
## 2               3        7               2               7            9
## 3               2        9              15               9           24
## 4               4       13               2              13           15
## 5               4       17              11              17           28
## 6               4       21               7              21           28
## 7               3       24               7              24           31
## 8               0       24               6              28           34
## 9               5       29               2              29           31
## 10              1       30               2              31           33

Pregunta 1: ¿Cual es el tamaño promedio de la cola para cada uno de los servidores?

El tamaño promedio puede ser por hora, por dia o por semana. Debido a que los 7 dias tienen distribuciones distintas vamos a calcular el tamaño promedio de la cola para 1 semana (7 dias), para cada uno de las 7 colas. Para esto vamos a generar un dataframe de los 7 dias, para cada una de las colas, desde 1 servidor a 7, por 52 semanas (1 año). Esto es equivalente a simular cada semana durante un año:

y2 <- 0
for (k in 1:52) {
    x <- 0
    for (i in 1:7) {
      x <- MM2_queue(i)
      y2 <- rbind(y2,x)
    }
}

y3 <- 0
for (k in 1:52) {
    x <- 0
    for (i in 1:7){
      x <- MM3_queue(i)
      y3 <- rbind(y3,x)
    }
} 

y4 <- 0
for (k in 1:52) {
    x <- 0
    for (i in 1:7) {
      x <- MM4_queue(i)
      y4 <- rbind(y4,x)
    }
}


y5 <- 0
for (k in 1:52) {
    x <- 0
    for (i in 1:7) {
      x <- MM5_queue(i)
      y5 <- rbind(y5,x)
    }
}

y6 <- 0
for (k in 1:52) {
    x <- 0
    for (i in 1:7) {
      x <- MM6_queue(i)
      y6 <- rbind(y6,x)
    }
}

y7 <- 0
for (k in 1:52) {
    x <- 0
    for (i in 1:7) {
      x <- MM7_queue(i)
      y7 <- rbind(y7,x)
    }
}

Y ahora con la funcion queue_performance.R, calculamos los parametros de cada cola:

queue_performance(y2)
##   promedio_espera prob_cola promedio_servicio promedio_en_sis
## 1        247.7809 0.9793744          8.720529        256.5014
##   promedio_llegada clientes_en_cola
## 1         2.428703            70228
queue_performance(y3)
##   promedio_espera prob_cola promedio_servicio promedio_en_sis
## 1        98.17752 0.8342312          8.702596        106.8801
##   promedio_llegada clientes_en_cola
## 1         2.425851            59927
queue_performance(y4)
##   promedio_espera prob_cola promedio_servicio promedio_en_sis
## 1        41.77052 0.5637223          8.735122        50.50564
##   promedio_llegada clientes_en_cola
## 1         2.436613            40296
queue_performance(y5)
##   promedio_espera prob_cola promedio_servicio promedio_en_sis
## 1        20.24168  0.374932          8.766396        29.00808
##   promedio_llegada clientes_en_cola
## 1         2.429887            26874
queue_performance(y6)
##   promedio_espera prob_cola promedio_servicio promedio_en_sis
## 1        7.590505 0.2839698          8.717028        16.30753
##   promedio_llegada clientes_en_cola
## 1         2.415205            20487
queue_performance(y7)
##   promedio_espera prob_cola promedio_servicio promedio_en_sis
## 1        1.308965 0.1800293          8.724897        10.03386
##   promedio_llegada clientes_en_cola
## 1         2.433974            12882

El parametro prob_cola mide la probabilidad de hacer cola y el parametro clientes_en_cola mide el numero de clientes en promedio que hacen cola:

Por ejemplo, si el banco tiene 3 cajeros, el 83% de sus clientes hacen cola o el equivalente a 165 clientes por dia.º

Pregunta 2: ¿ Si no se quiere que un cliente este mas de 15 minutos en cola, cuantos agentes tiene que tener el banco?

Nuevamente vemos los parametros de rendimiento de cada cola. Debido a que las colas de 2,3 y 4 servidores tienen tiempos promedio de espera grandes, volvemos a calcular solo para colas de 5,6 y 7 servidores:

queue_performance(y5)
##   promedio_espera prob_cola promedio_servicio promedio_en_sis
## 1        20.24168  0.374932          8.766396        29.00808
##   promedio_llegada clientes_en_cola
## 1         2.429887            26874
queue_performance(y6)
##   promedio_espera prob_cola promedio_servicio promedio_en_sis
## 1        7.590505 0.2839698          8.717028        16.30753
##   promedio_llegada clientes_en_cola
## 1         2.415205            20487
queue_performance(y7)
##   promedio_espera prob_cola promedio_servicio promedio_en_sis
## 1        1.308965 0.1800293          8.724897        10.03386
##   promedio_llegada clientes_en_cola
## 1         2.433974            12882

Vemos que con 5 agentes o cajeros, el tiempo promedio de espera esta arriba de los 15 mins. Por lo tanto si el banco no quiere que un cliente este mas de 15 mins, debe tener al menos 6 agentes.

Pregunta 3: Como una restricción extra el banco no puede tener en cola mas de 10 personas.¿Cuántas personas no son aceptadas en promedio por día al banco?

Aqui nos piden calcular el tamaño de la cola. Es decir, en un momento en particular ¿cuantos clientes estan esperando entrar a servicio?. Si este numero supera 10, el resto son rechazados. Para resolver esto la logica es la siguiente:

  1. A partir de un dataframe, se genera otro dataframe con el listado de clientes que hicieron cola. Esto se hace para cada cola: MM2, MM3,…,MM7.

  2. Debido a que el tamaño de la cola se mide en base a la diferencia entre el inicio de servicio (cuando un cliente pasa con cajero) y la llegada del cliente, se cuenta el numero de clientes que esperan en cola antes de que el primero que hizo cola inicie el servicio.

  3. Se genera un vector con los tamaños de la cola, antes que el primer cliente reciba servicio.

La funcion queue_mean_length.R , calcula el tamaño promedio de la cola que excede 10, es decir devuelve el promedio de clientes que fueron rechazados ya que el banco solo permite, en un momento dado tener 10.

La funcion es la siguiente:

queue_mean_length <- function(d=MM2_queue()) {

  count <- rep(0,1000)
  
  for (k in 1:1000) {
    
        # d <- MM2_queue()
        z <- which(d$inicio_servicio -d$llegadas !=0)
        d <- d[z,]  # Dataframe solo de los que hicieron cola
        
        a <- rep(1000000,5)
        d <- rbind(d,a)
        
        i <- 1
        j <- 0
        c <- rep(0,50)
        
          
        while (i < (length(d$llegadas)-5)) {
          
              j <- j + 1
              flag <- 0
              minimo <- d$inicio_servicio[i]
        
                while (flag == 0) {
                  
                      if (d$llegadas[i+1] < minimo) {
                        
                        c[j] <- c[j] + 1
                        i <- i + 1
                        flag <- 0
                      }
                        
                      if (d$llegadas[i+1] >= minimo) { 
                         
                          c[j] <- c[j] + 1
                          i <- i +1
                          flag <- 1
                          
                      }
                }
        }
        
        c <- c[-which(c==0)]
        c <- c[which(c-10>0)]
        
        count[k] <- sum(c)
        
  }
  
  return(mean(count))
  
}

Para las diferentes configuraciones de servidores tenemos:

queue_mean_length(MM2_queue())
## [1] 159
queue_mean_length(MM3_queue())
## [1] 152
queue_mean_length(MM4_queue())
## [1] 0
queue_mean_length(MM5_queue())
## [1] 0
queue_mean_length(MM6_queue())
## [1] 0
queue_mean_length(MM7_queue())
## [1] 0

Esto representa el promedio de clientes rechazados, cuando la cola en el banco ya esta en 10. Para las colas de 6 y 7 podemos ver que no hay clientes rechazados cuando se supera 10, debido a que muy seguramente la cola nunca llega a 10.

Apendicé: La funcion **queue_performance.R*

La funcion queue_performance.R se muestra acontinuacion. Esta funcion calcula, para un dataframe de una cola en particular, todos los paramentros de rendimiento de la cola.

queue_performance <- function(x=MM2_queue()) {

# Synopsis:  Recibe un dataframe de una cola de k servidores y calcula los parametros de rendimiento
#  de la cola.
  
# Initialize
    
c <- 0
      
#  Queue for N clients: Cola de N clientes
      
      N <- length(x$llegadas)
      idle_time_server <- rep(0,N)  # Vector de tiempo desocupado
      
      waiting_time_q <- x$inicio_servicio-x$llegadas # tiempo de espera en la cola
      total_time <- x$finalizacion-x$llegadas # tiempo total en el sistema       
      service_times <- x$finalizacion-x$inicio_servicio # tiempo de servicio
      interarrival_times <- x$entre_llegadas # tiempo entre llegadas de clientes
      arrival_times <- x$llegadas # llegadas de los clientes
      completion_times <- x$finalizacion # Finalizacion del servicio
      enter_service_times <- x$inicio_servicio # Inicio del servicio
      
      
#  Performance Calculations
      
      w_bar <- mean(waiting_time_q)  # tiempo promedio de espera en la cola
      t_bar <- mean (total_time) # tiempo promedio en el sistema
      s_bar <- mean(service_times) # tiempro promedio de servicio
      i_bar <- mean(interarrival_times) # tiempo promedio de llegada
      
# Calculo de las personas que hacen cola.
      
      for (k in 1:N) {
            if (arrival_times[k] == enter_service_times[k]) {c <- c + 1}
      }
      
      prob_queue <- 1- (c/N)
      P_queue <- round(N*prob_queue, digits = 0) # Promedio de personas que hacen cola


df2 <- data.frame(promedio_espera=w_bar,prob_cola=prob_queue,promedio_servicio=s_bar,promedio_en_sis=t_bar,promedio_llegada=i_bar,clientes_en_cola=P_queue)
return(df2)

}