Introduction:

In this report, we simulate a sequential, two-stage queuing system in a bank setting, with a single reception desk and a single bank employee. Customers must visit the reception first, followed by the bank employee for further assistance. By assessing performance metrics, we aim to validate the system’s functionality and effectiveness when dealing with single-stage services. This simulation offers valuable insights for similar real-world scenarios in the service industry.

Probability distributions and why we chose them:

  • Arrival Time: The Poisson distribution is used to model the arrival of customers, as it represents the number of independent events occurring at a constant average rate (λ) during the specified time frame (open to close times).

  • Reception Service Time (ST): We chose the Exponential distribution because it’s commonly used to model service times when the length of service is random and independent of other factors. Its parameter of 1/5 ensures values between 1 and 6, simulating the varying time customers might spend at the reception.

  • Bank Employee Service Time (ST2): The Normal distribution is suitable for modeling service times when the values cluster around a central mean value (in this case, 10 minutes), with a standard deviation of 2, accounting for variations in service time. Values between 5 and 20 minutes reflect the time range customers might spend with a bank employee.

Overall,these distributions help simulate a realistic bank scenario by capturing the randomness in customer arrivals and service times while considering the varying levels of support customers require.

Implementing the Systems in R:

set.seed(111)
openTime <- 7 * 60 
closeTime <- 18 * 60 
peakTime <- 13 * 60 
numCustomers <- 20 

# function for AT using poison dist with lambda = peakTime
AT=Filter(function(x) x >= openTime & x <= closeTime, round(rpois(numCustomers, lambda = peakTime)))

TSB = c()
TCW= c()
TSE=c()

# function for ST reception using exponential dist with rate = 1/5, values btw 1 and 6 mins
generate_ST <- function(numCustomers) {
  ST <- round(rexp(numCustomers, rate = 1/5))
  ST <- ST[ST >= 1 & ST <= 6]
  while (length(ST) < numCustomers) {
    additional <- round(rexp(numCustomers - length(ST), rate = 1/5))
    ST <- c(ST, additional[additional >= 1 & additional <= 6])
  }
  return(head(ST, numCustomers))
}

ST <- generate_ST(numCustomers)

for (i in 1:length(AT)) {
   
  TSB[i]= max(AT[i],TSE[i-1])
  TSE[i]= TSB[i]+ST[i]
  TCW[i]= abs(TSB[i]-AT[i])
  
}

AT2 = TSE
TCB2 = c()
TCW2=c()
TSE2=c()
ST2=c()
TSS=c()

# function for ST reception using normal dist with mean=10, values btw 5 and 20 mins
ST2= Filter(function(x) x >= 5 & x <= 20, round(rnorm(numCustomers, mean = 10, sd = 2)))
for (i in 1:length(AT2)) {
  TCB2[i]= max(TSE2[i-1],AT2[i])
  TCW2[i]= TCB2[i]-AT2[i]
  TSE2[i]= TCB2[i]+ST2[i]
  TSS[i]= TSE2[i]-AT[i]
  
}
data.frame(AT,ST,TSB,TCW,TSE,TCB2,TCW2,ST2,TSE2,TSS)
##     AT ST TSB TCW TSE TCB2 TCW2 ST2 TSE2 TSS
## 1  786  1 786   0 787  787    0   9  796  10
## 2  770  5 787  17 792  796    4  14  810  40
## 3  774  3 792  18 795  810   15  11  821  47
## 4  775  4 795  20 799  821   22  13  834  59
## 5  786  5 799  13 804  834   30  11  845  59
## 6  733  4 804  71 808  845   37  12  857 124
## 7  753  2 808  55 810  857   47  11  868 115
## 8  788  4 810  22 814  868   54  11  879  91
## 9  764  6 814  50 820  879   59  11  890 126
## 10 831  2 831   0 833  890   57  10  900  69
## 11 791  2 833  42 835  900   65  14  914 123
## 12 802  3 835  33 838  914   76   8  922 120
## 13 736  1 838 102 839  922   83  11  933 197
## 14 777  2 839  62 841  933   92  13  946 169
## 15 746  2 841  95 843  946  103   6  952 206
## 16 804  6 843  39 849  952  103  10  962 158
## 17 767  1 849  82 850  962  112  10  972 205
## 18 785  1 850  65 851  972  121  12  984 199
## 19 775  1 851  76 852  984  132  12  996 221
## 20 802  1 852  50 853  996  143   7 1003 201
# histogram of (AT)
hist(AT, breaks = 20, col = "skyblue", main = "Distribution of arrival times", xlab = "Arrival Time (minutes)")

total_time_span <- closeTime - openTime

# Calculate arrival rate
arrival_rate <- length(AT) / total_time_span

# Display arrival rate
print(paste("Arrival Rate:", arrival_rate, "customers per minute"))
## [1] "Arrival Rate: 0.0303030303030303 customers per minute"

interpretation:

A visualization showcases the distribution of customer arrivals at the bank throughout its operating hours, with a peak occurring between approximately 12:50pm (770) and 1:25pm (805)

# Set up the plotting layout
par(mfrow = c(1, 2))

# ST Reception
dotchart(table(ST), main = "Service Times for Reception", xlab = "Frequency", pch = 19, col = "lightgreen")
## Warning in dotchart(table(ST), main = "Service Times for Reception", xlab =
## "Frequency", : 'x' is neither a vector nor a matrix: using as.numeric(x)
# ST Bank Employee
dotchart(table(ST2), main = "Service Times for Bank Employee", xlab = "Frequency", pch = 19, col = "lightpink")
## Warning in dotchart(table(ST2), main = "Service Times for Bank Employee", : 'x'
## is neither a vector nor a matrix: using as.numeric(x)

interpretation:

this dotplot illustrates the frequency distribution of service times for both reception and bank employee.

  • for the Service time (reception): it is observed that the most common service times are 1 and 2 mins,with 1 being recorded 6 times and 2 being recorded 5 times. the service times of 3,4,5 and 6mins are recorded fewer than 4 times each, indicating less frequent occurrences compared to shorter service times.

  • for the Service time (bank employee):The most common service time is 11mins recorded 6 times,followed by service times of 12 and 10mins, each recorded 3 times.The remaining values vary between 1 and 2mins indicating shorter service times that are less common

df <- data.frame(
  Customer = 1:numCustomers,
  Wait_Time_Reception = TCW,
  Wait_Time_Bank_Employee = TCW2
)
library('ggplot2')
## Warning: package 'ggplot2' was built under R version 4.3.2
ggplot(df, aes(x = Customer)) +
  geom_line(aes(y =Wait_Time_Reception,color ="Reception")) +
  geom_line(aes(y =Wait_Time_Bank_Employee,color ="Bank Employee")) +
  scale_color_manual(values= c("Reception" ="blue","Bank Employee"= "red")) +
  labs(title ="Customer wait times comparison",
       x = "Customer",
       y = "Wait Time (minutes)",
       color = "Service") +
  theme_minimal()

interpretation:

It’s clear from the graph that the waiting time for the bank employee is noticeably greater than the waiting time before being served by the reception, which is logically consistent with most banking scenarios.

cat("number of customers who had to wait (Reception):", sum(TCW!=0), "\n")# reception
## number of customers who had to wait (Reception): 18
cat("number of customers who had to wait (Bank Employee):", sum(TCW2!=0), "\n")#bank employee
## number of customers who had to wait (Bank Employee): 19

interpretation:

Out of 20 total customers, 19 had to wait both at the reception and before being served by a bank employee. This emphasizes the common experience of waiting times in the banking process

cat("Average waiting time (Reception):", mean(TCW), "\n")# reception
## Average waiting time (Reception): 45.6
cat("Average waiting time (Bank Employee):", mean(TCW2), "\n")#bank employee
## Average waiting time (Bank Employee): 67.75

interpretation:

  • The average waiting time at the reception is approximately 45.6mins about 3/4 of an hour before receiving assistance.,while the average waiting time before being served by a bank employee is approximately 67.75mins which mean more than an hour before receiving service from the bank employee

  • waiting times of over an hour are generally not considered reasonable for most banking scenario. While some complexities in services or high customer traffic may contribute to longer waiting times, average waiting times exceeding an hour could indicate inefficiencies in the queuing system or staffing levels.

# Calculate server utilization
rec_util <- sum(ST)/ (max(TSE)- min(AT))  #reception
emp_util <- sum(ST2) / (max(TSE2) - min(AT2)) #bank employee
cat("Reception Utilization:", rec_util, "\n")
## Reception Utilization: 0.4666667
cat("Employee Utilization:", emp_util, "\n")
## Employee Utilization: 1

interpretation:

  • Reception Utilization: The reception is utilized at approximately 81%, meaning that it is effectively utilized for 81% of the total available time. This indicates that there is some idle time at the reception, suggesting potential capacity for additional customer service or tasks.

  • Employee Utilization: The bank employee is fully utilized 100%, indicating that there is no idle time during the operating hours. While full utilization might seem efficient, it could also indicate potential overloading of the bank employee, which might lead to longer waiting times or decreased service quality.