knitr::opts_chunk$set( collapse = TRUE, comment = "#>" )

library(edeaR) library(dplyr)

The function calculate_queueing_times can be used to calculate for each activity instance in the log when it was started, and since when it was queued. (That is, each activity instance except the first one for each case).

For example, for the sepsis event log

library(eventdataR) calculate_queuing_times(sepsis) -> queuing_times

The result is the following:

queuing_times

We can use the output to compare the times time in queue for different activities, for example.

library(ggplot2) #> Warning: package 'ggplot2' was built under R version 3.6.3 queuing_times %>% ggplot(aes(activity, time_in_queue)) + geom_boxplot()

Or between different resources:

queuing_times %>% ggplot(aes(resource, time_in_queue)) + geom_boxplot()

If we remove the “?” resource:

queuing_times %>% filter(resource != "?") %>% ggplot(aes(resource, time_in_queue)) + geom_boxplot()

Based on the information about queuing times, we can also compute the length of the queue. This can be done using the function calculate_queue_length. For this, we need to decide at which time interval we want to compute the length of the queue. For example, we can compute the length of the queue for each day, each week, each month, etc. The sepsis data covers approximately 1.5 years. Computing the queue for each week will thus give us about 75 different observations.

queuing_times %>% calculate_queuing_length(time_interval = "week")

The first observation is the data above will always be the first timestamp for which an event was recorded. At this point, the queue will always be zero. The second observation is the queue length after one week, etc. We can plot this data to see the evolution of the queue over time.

queuing_times %>% calculate_queuing_length(time_interval = "week") %>% ggplot(aes(date, queue_length)) + geom_line()

Of course, you need to be careful when interpreting both extremes of this time range, because we only have complete cases. At the start of the time range, the process is “building up” activity, and the queue goes up. At the end of the time range, the last cases are being finished, and the queue gradually empties. It takes some knowledge about the data to decide on a time frame that is proper for analysis.

The length of the queue shown above refers to all queued activity instances in the process. We can also look at queue length by either activity or by resource. This can be done by changing the level argument in the calculation function.

queuing_times %>% calculate_queuing_length(time_interval = "week", level = "resource") queuing_times %>% calculate_queuing_length(time_interval = "week", level = "activity")

Again, these can be plotted conveniently (we ignore the unknown resource):

queuing_times %>% filter(resource != "?") %>% calculate_queuing_length(time_interval = "week", level = "resource") %>% ggplot(aes(date, queue_length, color = resource)) + geom_line()

If we increase the time interval, the queue length is calculated after longer periods of time, so the data becomes more sparse. For example, calculating after a month instead of a week:

queuing_times %>% filter(resource != "?") %>% calculate_queuing_length(time_interval = "month", level = "resource") %>% ggplot(aes(date, queue_length, color = resource)) + geom_line()

We can set it to a integer number to indicate an interval of x days. For example, every 3 days:

queuing_times %>% filter(resource != "?") %>% calculate_queuing_length(time_interval = 3, level = "resource") %>% ggplot(aes(date, queue_length, color = resource)) + geom_line()

The time interval should be chosen carefully. Note that a very small interval (the smallest possible is “day”) can be computationally expensive if your event log covers a long time period.

The calculations of queues is based on some assumptions that are important to understand when drawing conclusions about these numbers.

Firstly, it starts from the log, and nothing more. It does not take any process model notion into account. We assume that an activity instance could have started if the previous one was finished. However, if the activity in question and the previous one can be executed in parallel, the activity in question could have been started earlier, and thus we underestimate its time in the queue.

Relatedly, if the activity in question actually overlaps with the previous one, you will get a negative queue time, because following the above theory, it started to early. (Of course, this can only happen when you have start and end events). The current implemention does not notify you if this happens, but could check for it in the result of the queueing times, and decide how to handle it (e.g. remove with zero or NA).

Secondly, there might be other factors, which are not present in the data, that impact when something starts to queue or not. If somewhere between two activities a decision is made on how to proceed with the case, the queueing of the second activity didn’t really start after the first, but after the decision was made.

Finally, an important remark should be made regarding the resource. If we compute the queue length of a resource, as shown above, all the activities that this resouces executed are added to the queue once the previous activity instance was finished. This might not accurately represent reality, because it assume that executions are assigned to a resource queue up-front, i.e. once they are enabled (taking into account the previous two points on the heuristic we use to define that moment), and not at a latter stage. It might for instance be the situation that queued cases are added to a queue that is not necessarily tied to a single resource, but from which resources can pick a task once they are free to start some (or at any point in time between the task being added to the list, and the task being started).

Because of these reasons, some caution is necessary when analysing queuing times and length, as the heuristic, solely based on the avaiable process data does not take into account a process/workflow or the context of task assignment.

**Any scripts or data that you put into this service are public.**

Embedding an R snippet on your website

Add the following code to your website.

For more information on customizing the embed code, read Embedding Snippets.