<p><div><div><div><div data-show-faces="false" data-height="21" data-width="100" data-layout="button_count" data-send="true" data-href="https://www.r-bloggers.com/call-centre-workforce-planning-using-erlang-c-in-r-language-2/"></div></div><div></div></div><div></div></div>
<div>
(This article was first published on <strong><a href="https://lucidmanager.org/call-centre-workforce-planning-erlang-c-in-r/"> The Devil is in the Data – The Lucid Manager</a></strong>, and kindly contributed to <a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers)</a> </div>
<p>We all hate the experience of calling a service provider and being placed on hold for a very long time. Organisations that take their level of service seriously plan their call centres so that the waiting times for customers is within acceptable limits. Having said this, <a rel="nofollow" href="http://lucidmanager.org/queuing/" target="_blank">making people wait</a> for something can in some instances increase the level of perceived value.</p>
<p>Call centre performance can be expressed by the Grade of Service, which is the percentage of calls that are answered within a specific time, for example, 90% of calls are answered within 30 seconds. This Grade of Service depends on the volume of calls made to the centre, the number of available agents and the time it takes to process a contact. Although working in a call centre can be chaotic, the <a rel="nofollow" href="https://www.callcentrehelper.com/erlang-c-formula-example-121281.htm" target="_blank">Erlang C formula</a> describes the relationship between the Grade of Service and these variables quite accurately.</p>
<p>Call centre workforce planning is a complex activity that is a perfect problem to solve in R code. This article explains how to use the Erlang C formula in the R language to manage a contact centre by calculating the number of agents needed to meet a required Grade of Service. This approach is extended with a Monte Carlo situation to understand the stochastic nature of the real world better.</p>
<h2>The Erlang C Formula</h2>
<p>The Erlang C formula describes the probability that a customer needs to queue instead of being immediately serviced <img alt="(P_w)" title="(P_w)" src="https://s0.wp.com/latex.php?latex=%28P_w%29&bg=ffffff&%23038;fg=000&%23038;s=0" class="latex">. This formula is closely related to the <a rel="nofollow" href="https://en.wikipedia.org/wiki/Poisson_distribution" target="_blank">Poisson distribution</a> which describes queues such as traffic lights.</p>
<p><img alt="P_w = frac{frac{A^N}{N!}frac{N}{N-A}}{Big( sum_{i=0}^{N-1} frac{A^i}{i!} Big)+frac{A^N}{N!}frac{N}{N-A}}" title="P_w = frac{frac{A^N}{N!}frac{N}{N-A}}{Big( sum_{i=0}^{N-1} frac{A^i}{i!} Big)+frac{A^N}{N!}frac{N}{N-A}}" src="https://s0.wp.com/latex.php?latex=P_w+%3D+%5Cfrac%7B%5Cfrac%7BA%5EN%7D%7BN%21%7D%5Cfrac%7BN%7D%7BN-A%7D%7D%7B%5CBig%28+%5Csum_%7Bi%3D0%7D%5E%7BN-1%7D+%5Cfrac%7BA%5Ei%7D%7Bi%21%7D+%5CBig%29%2B%5Cfrac%7BA%5EN%7D%7BN%21%7D%5Cfrac%7BN%7D%7BN-A%7D%7D&bg=ffffff&%23038;fg=000&%23038;s=2" class="latex"></p>
<p>The intensity of traffic <img alt="A" title="A" src="https://s0.wp.com/latex.php?latex=A&bg=ffffff&%23038;fg=000&%23038;s=0" class="latex"> is the number of calls per hour multiplied by the average duration of a call. Traffic intensity is measured in dimensionless Erlang units which expresses the time it would take to manage all calls if they arrived sequentially. The intensity is a measure of the amount of effort that needs to be undertaken in an hour. In reality, calls arrive at random times during the hour, which is where the Poisson distribution comes in. The waiting time is also influenced by the number of available operators <img alt="N" title="N" src="https://s0.wp.com/latex.php?latex=N&bg=ffffff&%23038;fg=000&%23038;s=0" class="latex">. The intensity defines the minimum number of agents needed to manage the workload.</p>
<p>We can now deconstruct this formula in a common sense way by saying that the level of service increases as the intensity (the combination of call volume and average duration) reduces and the number of operator increases. The more staff, the higher the level of service, but precisely how many people do you need to achieve your desired grade of service efficiently?</p>
<p>The Grade of Service <img alt="S" title="S" src="https://s0.wp.com/latex.php?latex=S&bg=ffffff&%23038;fg=000&%23038;s=0" class="latex"> is a function of the outcome of the Erlang C formula (<img alt="P_w" title="P_w" src="https://s0.wp.com/latex.php?latex=P_w&bg=ffffff&%23038;fg=000&%23038;s=0" class="latex">), the number of agents (<img alt="N" title="N" src="https://s0.wp.com/latex.php?latex=N&bg=ffffff&%23038;fg=000&%23038;s=0" class="latex">), the call intensity (<img alt="A" title="A" src="https://s0.wp.com/latex.php?latex=A&bg=ffffff&%23038;fg=000&%23038;s=0" class="latex">), call duration (<img alt="lambda" title="lambda" src="https://s0.wp.com/latex.php?latex=%5Clambda&bg=ffffff&%23038;fg=000&%23038;s=0" class="latex">) and lastly the target answering time <img alt="(t" title="(t" src="https://s0.wp.com/latex.php?latex=%28t&bg=ffffff&%23038;fg=000&%23038;s=0" class="latex">).</p>
<p><img alt="S = 1 - Large[ P_w e^ {-[(N-A](t/ lambda)]} large]" title="S = 1 - Large[ P_w e^ {-[(N-A](t/ lambda)]} large]" src="https://s0.wp.com/latex.php?latex=S+%3D+1+-+%5CLarge%5B+P_w+e%5E+%7B-%5B%28N-A%5D%28t%2F+%5Clambda%29%5D%7D+%5Clarge%5D&bg=ffffff&%23038;fg=000&%23038;s=2" class="latex"></p>
<p>The Erlang C formula can be reworked to provide that answer. I sourced this formula from <a rel="nofollow" href="https://www.callcentrehelper.com/erlang-c-formula-example-121281.htm" target="_blank">callcenterhelper.com</a> but must admit that I don’ t fully understand it and will take it at face value.</p>
<p>We now have a toolset for call centre planning which we can implement in the R language.</p>
<h2>Erlang C in R</h2>
<p>The Erlang C formula contains some factorials and powers, which become problematic when dealing with large call volumes or a large number of agents. The Multiple Precision Arithmetic package enables working with <a rel="nofollow" href="http://lucidmanager.org/euler-problem-20/" target="_blank">large integer factorials</a>, but there is no need to wield such strong computing powers. To make life easier, the Erlang C formula includes the <a rel="nofollow" href="https://en.wikipedia.org/wiki/Erlang_(unit)#Erlang_B_formula" target="_blank">Erlang B formula</a>, the inverse of which can be calculated using a small loop.</p>
<p>This implementation is very similar to an unpublished R package by <a rel="nofollow" href="https://github.com/phubers/erlang" target="_blank">Patrick Hubers</a>, enhanced with work from <a rel="nofollow" href="https://www.callcentrehelper.com/erlang-c-formula-example-121281.htm" target="_blank">callcenterhelper.com</a>. This code contains four functions:</p>
<ol>
<li><code>intensity</code>: Determines intensity in Erlangs based on the rate of calls per interval, the total call handling time and the interval time in minutes. All functions default to an interval time of sixty minutes.</li>
<li><code>erlang_c</code>: Calculates The Erlang C formula using the number of agents and the variables that determine intensity.</li>
<li><code>service_level</code>: Calculates the service level. The inputs are the same as above plus the period for the Grade of Service in seconds.</li>
<li><code>resource</code>: Seeks the number of agents needed to meet a Grade of Service. This function starts with the minimum number of agents (the intensity plus one agent) and keeps searching until it finds the number of agents that achieve the desired Grade of Service.</li>
</ol>
<p>You can view the code below or download it from <a rel="nofollow" href="https://github.com/pprevos/r.prevos.net/blob/master/Marketing/CallCentre.R" target="_blank">GitHub</a>.</p>
<pre>
intensity &lt;- function(rate, duration, interval = 60) {
    (rate / (60 * interval)) * duration
}

erlang_c &lt;- function(agents, rate, duration, interval = 60) {
    int &lt;- intensity(rate, duration, interval)
    erlang_b_inv &lt;- 1
    for (i in 1:agents) {
        erlang_b_inv &lt;- 1 + erlang_b_inv * i / int
    }
    erlang_b &lt;- 1 / erlang_b_inv
    agents * erlang_b / (agents - int * (1 - erlang_b))
}

service_level &lt;- function(agents, rate, duration, target, interval = 60) {
    pw &lt;- erlang_c(agents, rate, duration, interval)
    int &lt;- intensity(rate, duration, interval)
    1 - (pw * exp(-(agents - int) * (target / duration)))
}

resource &lt;- function(rate, duration, target, gos_target, interval = 60) {
    agents &lt;-round(intensity(rate, duration, interval) + 1)
    gos &lt;- service_level(agents, rate, duration, target, interval)
    while (gos &lt; gos_target * (gos_target > 1) / 100) {
        agents &lt;- agents + 1
        gos &lt;- service_level(agents, rate, duration, target, interval)
    }
    return(c(agents, gos))
}
</pre>
<h2>Call Centre Workforce Planning Using an Erlang C Monte Carlo Simulation</h2>
<p>I have used the Erlang C model to recommend staffing levels in a contact centre some years ago. What this taught me is that the mathematical model is only the first step towards call centre workforce planning. There are several other metrics that can be built on the Erlang C model, such as average occupancy of agents and average handling time.</p>
<p>The Erlang C formula is, like all mathematical models, an idealised version of reality. Agents are not always available; they need breaks, toilet stops and might even go on leave. Employers call this loss of labour shrinkage, which is a somewhat negative term to describe something positive for the employee. The Erlang C model provides you with the number of ‘bums on seats’.</p>
<p>The Erlang C formuala is, like every model, not a perfect represention of reality. The formula tends to overestimate the required resrouces because it assumes that people will stay on hold indefinitely, while the queu will automatically shorten as people losse patience.</p>
<p>The number of employees needed to provide this capacity depends on the working conditions at the call centre. For example, if employees are only available to take calls 70% of their contracted time, you will need <img alt="1/0.7=1.4" title="1/0.7=1.4" src="https://s0.wp.com/latex.php?latex=1%2F0.7%3D1.4&bg=ffffff&%23038;fg=000&%23038;s=0" class="latex"> staff members for each live agent to meet the Grade of Service.</p>
<p>Another problem is the stochastic nature of call volumes and handling times. The Erlang C model requires a manager to estimate call volume and handling time (intensity) as a static variable, while in reality, it is stochastic and subject to variation. Time series analysis can help to predict call volumes, but every prediction has a degree of uncertainty. We can manage this uncertainty by using a Monte Carlo simulation.</p>
<p>All the functions listed above are rewritten so that they provide a vector of possible answers based on the average call volume and duration and their standard deviation. This simulation assumes a normal distribution for both call volume and the length of each call. The outcome of this simulation is a distribution of service levels.</p>
<h3>Monte Carlo Simulation</h3>
<p>For example, a call centre receives on average 100 calls per half hour with a standard deviation of 10 calls. The average time to manage a call, including wrap-up time after the call, is 180 seconds with a standard deviation of 20 seconds. The centre needs to answer 80% of calls within 20 seconds. What is the likelihood of achieving this level of service?</p>
<p>The average intensity of this scenario is 10 Erlangs. Using the resource formula suggests that we need 14 agents to meet the Grade of Service. Simulating the intensity of the scenario 1000 times suggests we need between 6 and 16 agents to manage this workload.</p>
<pre>
> resource(100, 180, 20, 80, 30)
[1] 14.0000000  0.88835
> intensity_mc(100, 10, 180, 20) %>% summary()
 Min. 1st Qu. Median Mean 3rd Qu. Max. 
5.480 8.975 9.939 10.025 10.993 15.932
</pre>
<p>The next step is to simulate the expected service level for this scenario. The plot visualises the outcome of the Monte Carlo simulation and shows that 95% of situations the Grade of Service is more than 77% and half the time it is more than 94%.</p>
<pre> 
> service_level_mc(15, 100, 10, 180, 20, 20, 30, sims = 1000) %>%
+ quantile(c(.05, .5, .95)) 
5%        50%       95% 
0.7261052 0.9427592 0.9914338 
</pre>
<p>This article shows that Using Erlang C in R helps managers with call centre workforce planning. Perhaps we need a Shiny application to develop a tool to manage the complexity of these functions. I would love to hear from people with practical experience in managing call centres in how they analyse data.</p>
<figure class="wp-caption"><a rel="nofollow" href="http://lucidmanager.org/call-centre-workforce-planning-erlang-c-in-r/service_levels/" target="_blank"><img data-orig-file="https://i0.wp.com/lucidmanager.org/wp-content/uploads/sites/2/2018/07/service_levels.png?fit=2096%2C2097&amp;ssl=1" data-orig-size="2096,2097" data-medium-file="https://i0.wp.com/lucidmanager.org/wp-content/uploads/sites/2/2018/07/service_levels.png?fit=300%2C300&amp;ssl=1" data-attachment-id="5402" data-image-meta="{" data-image-description="" src="https://i0.wp.com/lucidmanager.org/wp-content/uploads/sites/2/2018/07/service_levels.png?resize=731%2C731" data-permalink="https://lucidmanager.org/call-centre-workforce-planning-erlang-c-in-r/service_levels/" data-large-file="https://i0.wp.com/lucidmanager.org/wp-content/uploads/sites/2/2018/07/service_levels.png?fit=731%2C731&amp;ssl=1" alt="Simulated service levels using Erlang C in R and Monte Carlo simulation" data-image-title="service_levels" sizes="(max-width: 731px) 100vw, 731px" width="450" data-comments-opened="1" class="wp-image-5402" data-recalc-dims="1"></a><figcaption class="wp-caption-text">Simulated service levels using Erlang C in R and Monte Carlo simulation.</figcaption></figure>
<p>You can view the code below or download it from <a rel="nofollow" href="https://github.com/pprevos/r.prevos.net/blob/master/Marketing/CallCentre.R" target="_blank">GitHub</a>.</p>
<pre>
library(tidyverse)

intensity_mc &lt;- function(rate_m, rate_sd, duration_m, duration_sd, interval = 60, sims = 1000) { (rnorm(sims, rate_m, rate_sd) / (60 * interval)) * rnorm(sims, duration_m, duration_sd) } intensity_mc(100, 10, 180, 20, interval = 30) %>% summary

erlang_c_mc &lt;- function(agents, rate_m, rate_sd, duration_m, duration_sd, interval = 60) {
    int &lt;- intensity_mc(rate_m, rate_sd, duration_m, duration_sd, interval)
    erlang_b_inv &lt;- 1
    for (i in 1:agents) {
        erlang_b_inv &lt;- 1 + erlang_b_inv * i / int
    }
    erlang_b &lt;- 1 / erlang_b_inv
    agents * erlang_b / (agents - int * (1 - erlang_b))
}

service_level_mc &lt;- function(agents, rate_m, rate_sd, duration_m, duration_sd, target, interval = 60, sims = 1000) {
    pw &lt;- erlang_c_mc(agents, rate_m, rate_sd, duration_m, duration_sd, interval)
    int &lt;- intensity_mc(rate_m, rate_sd, duration_m, duration_sd, interval, sims)
    1 - (pw * exp(-(agents - int) * (target / rnorm(sims, duration_m, duration_sd))))
}

data_frame(ServiceLevel = service_level_mc(agents = 12,
                                           rate_m = 100,
                                           rate_sd = 10,
                                           duration_m = 180,
                                           duration_sd = 20,
                                           target = 20,
                                           interval = 30,
                                           sims = 1000)) %>%
    ggplot(aes(ServiceLevel)) +
        geom_histogram(binwidth = 0.1, fill = &quot;#008da1&quot;)
</pre>
<p>The post <a rel="nofollow" href="https://lucidmanager.org/call-centre-workforce-planning-erlang-c-in-r/" target="_blank">Call Centre Workforce Planning Using Erlang C in R language</a> appeared first on <a rel="nofollow" href="https://lucidmanager.org/" target="_blank">The Lucid Manager</a>.</p>
	<p>
<div>
<div>To <strong>leave a comment</strong> for the author, please follow the link and comment on their blog: <strong><a href="https://lucidmanager.org/call-centre-workforce-planning-erlang-c-in-r/"> The Devil is in the Data – The Lucid Manager</a></strong>.</div>
<hr>
<a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers.com</a> offers <strong><a rel="nofollow" href="https://feedburner.google.com/fb/a/mailverify?uri=RBloggers">daily e-mail updates</a></strong> about <a rel="nofollow" href="https://www.r-project.org/" title="The R Project for Statistical Computing">R</a> news and <a rel="nofollow" href="https://www.r-bloggers.com/search/tutorial" title="R tutorials">tutorials</a> on topics such as: <a rel="nofollow" href="https://www.r-bloggers.com/search/data%20science" title="Data science">Data science</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/Big%20Data" title="Big Data">Big Data, <a rel="nofollow" href="https://www.r-users.com/" title="R jobs">R jobs</a>, visualization (<a rel="nofollow" href="https://www.r-bloggers.com/search/ggplot2" title="ggplot and ggplot2 tutorials">ggplot2</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/boxplot" title="Boxplots using lattice and ggplot2 tutorials">Boxplots</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/map" title="Maps and gis">maps</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/animation" title="Animation in R">animation</a>), programming (<a rel="nofollow" href="https://www.r-bloggers.com/search/RStudio" title="RStudio IDE for R">RStudio</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/sweave" title="Sweave and literate programming">Sweave</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/LaTeX" title="LaTeX in R">LaTeX</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/SQL" title="SQL and databases">SQL</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/eclipse" title="Eclipse IDE for R">Eclipse</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/git" title="git and github, Version Control System">git</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/hadoop" title="Large data in R using Hadoop">hadoop</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/Web+Scraping" title="Web Scraping of google, facebook, yahoo, twitter and more using R">Web Scraping</a>) statistics (<a rel="nofollow" href="https://www.r-bloggers.com/search/regression" title="Regressions and ANOVA analysis tutorials">regression</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/PCA" title="principal component analysis tutorial">PCA</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/time+series" title="Time series">time series</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/trading" title="finance trading">trading</a>) and more...
<img alt="" width="1" src="http://feeds.feedburner.com/~r/RBloggers/~4/OORLor_s3CI" height="1"></a></div>