El documento es un intento por mostrar algunas funciones del lenguaje R para el manejo de datos y presentación de los mismos de manera gráfica, tabular, etc.
Suponga que usted trabaja en un callcenter, como coordinador de un grupo de teleoperadores y debe hacer un reporte diario y semanal sobre la actividad que se ha presentado durante la jornada de operación. Por lo tanto su tarea es realizar dicho informe con la información que se ha recopilado.
Se creará una base de datos (para simular la información obtenida del callcenter) y así realizar una exploración y visualización de datos. Los datos fueron creados, usando valores aleatorios y de acuerdo a algunas lecturas hechas en la web.
En la primera parte del documento, se trabajará con datos que corresponden a una jornada laboral de 89 agentes, es decir a un día de trabajo. En una segunda parte, los datos conformados corresponden a una semana (6 días) de trabajo de un equipo de 15 teleoperadores, es decir que se tiene la información diaria de cada uno durante 6 días.
Los contact center o callcenter, monitorean el tiempo de las llamadas de los agentes o teleoperadores durante el transcurso de cada jornada laboral, con el objetivo de obtener índices de calidad del servicio que presta la compañía a sus clientes. Algunas de las varibales monitoreadas es el AHT (Average Handling Time), entre muchas otras; que además, permiten hacer una proyección sobre la cantidad de teleoperadores requeridos para la jornada en función del número de clientes y llamadas que se generan por día.
Se crea una base de datos con algunas variables que son monitoreadas en un callcenter.
Esta es sólo una forma de crear la base de datos, otras opciones también son posibles.
La base de datos contiene las variables:
agente:
id del teleoperador.llamadas:
número de llamadas recibidas en la jornada.llamadas_tr:
número de llamadas transferidas a otras dependencias.aht:
Average Handling Time (segundos).datos_dia <- data.frame(agente = c(seq(1:89)),
fecha = c(rep("2021-03-19", 89)),
llamadas = c(11,17,15,20,9,12,8,24,27,19,21,29,15,13,14,33,23,15,18,5,22,13,131,12,
24,20,23,8,7,7,203,32,32,26,6,20,14,13,28,7,19,11,10,16,15,11,36,17,
15,3,10,11,8,7,29,13,14,10,8,7,6,27,12,23,16,29,31,12,31,22,10,13,32,
35,20,18,34,31,36,32,19,38,16,16,25,35,32,21,20),
llamadas_tr = c(3,7,4,2,1,3,3,12,8,7,1,8,3,3,3,8,9,2,1,1,6,1,0,3,8,0,2,2,1,1,0,6,9,4,0,9,
1,2,6,3,2,3,2,6,3,1,12,9,1,2,2,3,2,1,11,7,1,2,1,1,1,10,6,4,3,9,4,4,9,5,
0,3,13,11,7,1,3,9,12,3,2,13,2,5,12,15,11,12,3),
aht = c(809,765,753,798,888,741,1100,580,565,745,519,784,926,635,534,723,702,387,
500,1025,535,752,619,551,784,554,617,963,1818,1409,698,448,685,596,577,723,734,
1043,684,2065,666,420,527,553,698,884,396,654,727,391,527,556,839,1159,377,
782,698,527,716,853,1176,340,697,618,602,652,716,988,676,689,906,625,586,650,
908,683,580,571,680,745,659,669,973,667,696,483,761,913,620)
)
Se guarda la base de datos en formato csv en el directorio de trabajo, con el nombre datos_callcenter_dia.csv
.
write_csv(x = datos_dia, file = "datos_callcenter_dia.csv")
library(tidyverse)
calldia <- read_csv(file = "datos_callcenter_dia.csv")
── Column specification ───────────────────────────────────────────────────────
cols(
agente = col_double(),
fecha = col_date(format = ""),
llamadas = col_double(),
llamadas_tr = col_double(),
aht = col_double()
)
La presentación de los datos en este formato de tabla facilita el filtrado de las variables y ordemanamiento de menor a mayor o viceversa.
library(DT)
datatable(calldia, rownames = FALSE)
library(skimr)
skim(calldia)
── Data Summary ────────────────────────
Values
Name calldia
Number of rows 89
Number of columns 5
_______________________
Column type frequency:
Date 1
numeric 4
________________________
Group variables None
── Variable type: Date ────────────────────────────────────────────────────────
skim_variable n_missing complete_rate min max median
1 fecha 0 1 2021-03-19 2021-03-19 2021-03-19
n_unique
1 1
── Variable type: numeric ─────────────────────────────────────────────────────
skim_variable n_missing complete_rate mean sd p0 p25 p50 p75
1 agente 0 1 45 25.8 1 23 45 67
2 llamadas 0 1 22 24.5 3 12 17 27
3 llamadas_tr 0 1 4.69 3.89 0 2 3 8
4 aht 0 1 728. 264. 340 580 685 784
p100 hist
1 89 ▇▇▇▇▇
2 203 ▇▁▁▁▁
3 15 ▇▂▂▂▁
4 2065 ▇▆▁▁▁
El resumen señala que la variable fecha
es de tipo Date
y que la variable agente
está en formato numeric
. En algunos casos las fechas vienen en formato character
lo que hace necesario hacer una transformación de la variable; por otra parte en este ejemplo, se cambiará el formato de la variable agente
a un formato factor
cuando sea requerido.
La siguiente, es una forma de crear una tabla con el resumen numérico de las variables, en el que podemos ver por ejemplo el promedio de llamadas recibidas durante el día y el valor promedio de aht, etc. (Es una forma poco práctica cuando se tienen muchas variables, hay otras funciones que facilitan su construcción.)
matrix(nrow = 4, ncol = 6, byrow = FALSE,
dimnames = list(c("agentes", "llamadas", "llamadas_tr", "aht"),
c("total", "promedio", "mediana", "d_e", "min", "max")),
c(max(calldia$agente), sum(calldia$llamadas), sum(calldia$llamadas_tr),
"", "", mean(calldia$llamadas), mean(calldia$llamadas_tr),
mean(calldia$aht), "", median(calldia$llamadas), median(calldia$llamadas_tr), median(calldia$aht), "", sd(calldia$llamadas),
sd(calldia$llamadas_tr), sd(calldia$aht), "", min(calldia$llamadas),
min(calldia$llamadas_tr), min(calldia$aht), "", max(calldia$llamadas),
max(calldia$llamadas_tr), max(calldia$aht))
) %>%
as_tibble() %>%
select(c(everything())) %>%
mutate(across(is.character, as.numeric)) %>%
mutate(across(is.numeric, round, digits = 2)) %>%
mutate(variable= c("agentes", "llamadas", "llamadas_tr", "aht")) %>%
relocate(variable, total, min, max, everything())
Se observa que durante la jornada de trabajo el valor promedio de aht fué de 728,24 segundos y los valores de desviación estándar para validar la dispersión que tienen cada una de las variables.
Si bien el paso a continuación no es necesario (debido a que las variables se encuentran en el formato adecuado para operar con ellas), se hace con el fín de ilustrar el uso de algunas funciones que permiten la transformación de variables a otros formatos.
library(lubridate)
calldia %>%
mutate(agente = as_factor(agente),
fecha = as_date(fecha))
Para verificar podemos pedir la clase de las variables.
class(calldia$fecha)
[1] "Date"
El formato Date
es importante para poder hacer operaciones sobre este tipo de datos, como por ejemplo extraer el día de la semana o el mes. Por ejemplo, si pasamos la función day
del paquete lubridate
sobre el vector fecha
, extraerá el número del día de la fecha correspondiente para cada posición del vector, también se puede extraer el número de la semana, etc. En este caso podemos obtener el día correspodiente a la fecha, el cual es viernes, y el mes que corresponde a Marzo.
library(lubridate)
wday(calldia$fecha, label = TRUE, abbr = FALSE)
[1] viernes viernes viernes viernes viernes viernes viernes viernes viernes
[10] viernes viernes viernes viernes viernes viernes viernes viernes viernes
[19] viernes viernes viernes viernes viernes viernes viernes viernes viernes
[28] viernes viernes viernes viernes viernes viernes viernes viernes viernes
[37] viernes viernes viernes viernes viernes viernes viernes viernes viernes
[46] viernes viernes viernes viernes viernes viernes viernes viernes viernes
[55] viernes viernes viernes viernes viernes viernes viernes viernes viernes
[64] viernes viernes viernes viernes viernes viernes viernes viernes viernes
[73] viernes viernes viernes viernes viernes viernes viernes viernes viernes
[82] viernes viernes viernes viernes viernes viernes viernes viernes
7 Levels: domingo < lunes < martes < miércoles < jueves < ... < sábado
month(calldia$fecha, label = TRUE, abbr = FALSE)
[1] marzo marzo marzo marzo marzo marzo marzo marzo marzo marzo marzo marzo
[13] marzo marzo marzo marzo marzo marzo marzo marzo marzo marzo marzo marzo
[25] marzo marzo marzo marzo marzo marzo marzo marzo marzo marzo marzo marzo
[37] marzo marzo marzo marzo marzo marzo marzo marzo marzo marzo marzo marzo
[49] marzo marzo marzo marzo marzo marzo marzo marzo marzo marzo marzo marzo
[61] marzo marzo marzo marzo marzo marzo marzo marzo marzo marzo marzo marzo
[73] marzo marzo marzo marzo marzo marzo marzo marzo marzo marzo marzo marzo
[85] marzo marzo marzo marzo marzo
12 Levels: enero < febrero < marzo < abril < mayo < junio < ... < diciembre
Un gráfico es la perfecta ayuda visual para representar los datos, y arroja una idea del comportamiento de las variables.
Explorando los datos, se evidencia que hay dos agentes con un alto número de llamadas. El agente 31 con 203 llamadas, y el agente 23 con 131. Estos datos son filtrados para obtener la representación gráfica. El total de llamadas sín remover los valores mencionados es 1958.
calldia %>%
filter(llamadas < 50) %>%
ggplot(mapping = aes(x = llamadas))+
geom_histogram(color = "gray", fill = "cadetblue", binwidth = 1)+
scale_x_continuous(c(1:45), breaks = seq(1:45), name = "Número de llamadas")+
labs(y = "Frecuencia", title = "Número de Llamadas", subtitle = "Diagrama de Barras", caption = "El número total de llamadas es 1958")
Una rápida conclusión que se observa con el gráfico es que hay aproximadamente 15 agentes de los 89, que recibieron más de 30 llamadas; por otra parte, los agentes que recibieron menos de 10 llamadas son aproximadamente 14.
calldia %>%
ggplot(mapping = aes(x = llamadas_tr))+
geom_histogram(color = "gray", fill = "firebrick", binwidth = 1, alpha = 0.9)+
scale_x_continuous(c(1:45), breaks = seq(1:45), name = "Llamadas Transferidas")+
labs(y = "Frecuencia", title = "Llamadas Transferidas", subtitle = "Diagrama de Barras", caption = "Llamadas transferidas: 417")
Podemos observar que cerca de la mitad de los agentes transfieren entre 1 y 3 llamadas, y que el número de llamadas transferidas es de 417.
Usaremos las variables Número de llamadas, llamadas transferidas y aht.
Se crean dos gráficos, en un mismo panel, para mirar el comportamiento de las variables.
g1 <- calldia %>%
filter(llamadas < 50) %>%
mutate(agente = as_factor(agente)) %>%
ggplot(mapping = aes(x = llamadas, y = llamadas_tr, label = agente)) +
geom_point(mapping = aes(color = agente))+
geom_text(nudge_x = 0,
nudge_y = 0,
check_overlap = TRUE)+
geom_smooth(se = FALSE)+
theme(legend.position = "none")+
labs(y = "Llamadas transferidas", title = "Número de Llamadas vs Llamadas Transferidas", caption = "Cada punto representa a un agente con su número de ID.")
g2 <- calldia %>%
mutate(agente = as_factor(agente)) %>%
filter(llamadas < 50) %>%
ggplot(mapping = aes(x = llamadas, y = aht, label = agente)) +
geom_point(mapping = aes(color = agente))+
geom_text(nudge_x = 0,
nudge_y = 0,
check_overlap = TRUE)+
geom_smooth(se = FALSE)+
theme(legend.position = "none")+
labs(title = "Número de Llamadas vs AHT", caption = "Cada punto representa a un agente con su número de ID.")
library(gridExtra)
grid.arrange(g1, g2, nrow = 1, ncol = 2,
widths = c(5,5),
heights = c(10))
Vemos que en el gráfico de la derecha, a medida que el número de llamadas aumenta, también aumenta el número de llamadas transferidas, si bien tiene sentido este comportamiento, en la vida real no necesariamente se presentará de esta manera, dependerá de la situación en particular de cada agente. También es posible inferir que el agente 86 es el que tiene más llamadas transferidas con aproximádamente 15.
Rápidamente podemos consultar el número de agentes que no tuvieron llamadas transferidas:
table(calldia$llamadas_tr == 0)
FALSE TRUE
84 5
Vemos con este resultado que, son 5 los agentes que no transfirieron llamadas. Si queremos saber cuáles son estos agentes, podemos filtrar estos valores:
calldia %>%
filter(llamadas_tr == 0)
Para el gráfico que reprensenta el AHT (izquierda), vemos un comportamiento decreciente, coincide con la información obtenida de algunas fuentes de referencia, debido a que en el denominador de la fórmula usada para calcular el AHT aparece el número de llamadas, por lo tanto al crecer este valor, el AHT disminuye respecto al número de llamadas.
calldia %>%
mutate(agente = as_factor(agente)) %>%
ggplot(mapping = aes(x = aht, y = llamadas_tr, label = agente)) +
geom_point(mapping = aes(color = agente))+
geom_text(nudge_x = 0,
nudge_y = 0,
check_overlap = TRUE)+
geom_smooth(se = FALSE)+
theme(legend.position = "none")+
labs(y = "Llamadas Transferidas", x = "AHT", title = "AHT vs Llamadas Transferidas", caption = "Cada punto representa a un agente con su número de ID.")
Un tercer gŕafico muestra el comportamiento del AHT según el número de llamadas transferidas.
Un gráfico interactivo para nuestro informe, puede ser de gran ayuda cuando se desea presentar la información durante una reunión, permitiendo una rápida vista de algunas variables de nuestro gráfico entre algunas otras opciones.
Una de las métricas que se estudia en la operación de un callcenter es el AHT, en muchos casos este valor permite valorar el desempeño de un agente. En el gráfico, la línea verde a trazos marca el valor AHT de 700 segundos y representa el AHT exigido al teleoperador como indicador de calidad de su trabajo, en este caso en particular. Cada punto en el gŕafico representa a un teleoperador. (Note que la librería plotly
no es compatible con algunos elementos de ggplot2
, como el subtítulo entre otros.)
library(plotly)
ggplotly(
calldia %>%
mutate(agente = as_factor(agente)) %>%
filter(llamadas < 50) %>%
ggplot(mapping = aes(x = llamadas, y = aht, color = agente)) +
geom_point()+
geom_abline(slope = 0, intercept = 700, linetype = "dotdash", color = "forestgreen", alpha = 0.7)+
theme_get()+
scale_y_continuous(limits = c(0,2000), n.breaks = 15, name = "AHT (s)")+
scale_x_continuous(limits = c(0,40), n.breaks = 10, name = "Llamadas")+
labs(title = "Número de llamadas y AHT", subtitle = "AHT exigido de 700 s", caption = "Cada punto representa a un teleoperador.")+
theme(legend.position = "none"), width = 700, height = 400
)
NA
Haciendo una pequeña consulta, podemos ver cuántos de los teleoperadores cumplen con el valor de AHT exigido, y se hacen acreedores de una comisión. Se ha dado un margen de cumplimiento que esté entre los valores de aht de 670 y 730.
Se genera una tabla con una nueva columna comision
que tiene valores si
, para los teleoperadores que cumplieron con el aht exigido y para quienes no cumplieron un valor de no
.
El número de agentes que cumplieron en este caso fué 17.
calldia %>%
filter(aht >= 670 & aht <= 730)
Crearemos una tabla para nuestro informe en la que haya una columna comision
para validar si el agente cumplió con la meta del aht, de ser así la casilla dirá sí para el agente que cumplió con el aht pedido, de lo contrario la casilla estará marcada con un no.
library(DT)
calldia$comision <- ifelse(calldia$aht >= 670 & calldia$aht <= 730, "si", "no")
datatable(calldia, rownames = FALSE)
Ahora representaremos el gráfico que contiene los agentes cuyos valores de aht estuvieron en el valor exigido para poder obtener una bonificación.
calldia %>%
filter(aht < 1500,
aht >= 670 & aht <= 730) %>%
filter(llamadas < 50) %>%
mutate(agente = as_factor(agente)) %>%
ggplot(mapping = aes(x = llamadas, y = aht, label = agente)) +
geom_smooth(se = TRUE)+
geom_point(mapping = aes(color = agente))+
geom_text(nudge_x = 0.5,
nudge_y = -3,
check_overlap = TRUE)+
geom_abline(slope = 0, intercept = 730, linetype = "dashed", color = "firebrick2")+
geom_abline(slope = 0, intercept = 670, linetype = "dashed", color = "firebrick2")+
geom_abline(slope = 0, intercept = 700, color = "forestgreen", linetype = "dashed")+
scale_y_continuous(limits = c(650,750), n.breaks = 15, name = "AHT (s)")+
scale_x_continuous(limits = c(5,40), n.breaks = 10, name = "Llamadas")+
labs(title = "Cumplimiento de AHT", caption = "El agente 31 con AHT 698 no se muestra en el gráfico.")+
theme(legend.position = "none")
La línea de tendencia de color azul, representa el comportamiento de los valores de aht en general respecto al número de llamadas y la franja gris es la incertidumbre de ese comportamiento.
En un mismo gráfico es representada la densidad para las variables de nuestro caso para ver en dónde se concentran más los valores de las variables.
d1 <- calldia %>%
ggplot(mapping = aes(x = aht)) +
geom_density(color = "cadetblue", fill = "cadetblue")+
labs(title = "Densidad AHT")
d2 <- calldia %>%
ggplot(mapping = aes(x = llamadas))+
geom_density(color = "cadetblue", fill = "cadetblue")+
labs(title = "Densidad llamadas")
d3 <- calldia %>%
ggplot(mapping = aes(x = llamadas_tr))+
geom_density(color = "cadetblue", fill = "cadetblue")+
labs(title = "Densidad llamadas transferidas")
grid.arrange(d1, d2, d3, nrow = 2, ncol = 2)
Hasta aquí hemos representado las variables obtenidas para un día laboral con 89 agentes que operan en un callcenter, lo hemos hecho de manera tabular y de manera gráfica para valores numéricos, obteniendo algunas conclusiones. En la segunda parte se creará una base de datos con información de 6 días.
En esta segunda parte del documento, se tienen datos de un equipo conformado por 15 agentes que trabajan durante 6 días.
Esta vez, se tiene la información de seis días de trabajo de un equipo conformado por 15 teleoperadores, las variables serán muy parecidas, una diferencia por ejemplo, se ve en las seis fechas diferentes y se tendrán 15 agentes.
datos_semana <- data.frame(agente = rep(c(1:15), times = 6, length.out = 90),
fecha = rep(c("2020-02-15", "2020-02-16", "2020-02-17", "2020-02-18", "2020-02-19", "2020-02-20"),
each = 15, length.out = 90),
llamadas = c(11,17,15,20,9,12,8,24,27,19,21,29,15,13,14,33,23,15,18,5,22,13,131,12,
24,20,23,8,7,7,203,32,32,26,6,20,14,13,28,7,19,11,10,16,15,11,36,17,
15,3,10,11,8,7,29,13,14,10,8,7,6,27,12,23,16,29,31,12,31,22,10,13,32,
35,20,18,34,31,36,32,19,38,16,16,25,35,32,21,20,0),
llamadas_tr = c(3,7,4,2,1,3,3,12,8,7,1,8,3,3,3,8,9,2,1,1,6,1,0,3,8,0,2,2,1,1,0,6,9,4,0,9,
1,2,6,3,2,3,2,6,3,1,12,9,1,2,2,3,2,1,11,7,1,2,1,1,1,10,6,4,3,9,4,4,9,5,
0,3,13,11,7,1,3,9,12,3,2,13,2,5,12,15,11,12,3,0),
aht = c(809,765,753,798,888,741,1100,580,565,745,519,784,926,635,534,723,702,387,
500,1025,535,752,619,551,784,554,617,963,1818,1409,698,448,685,596,577,723,734,
1043,684,2065,666,420,527,553,698,884,396,654,727,391,527,556,839,1159,377,
782,698,527,716,853,1176,340,697,618,602,652,716,988,676,689,906,625,586,650,
908,683,580,571,680,745,659,669,973,667,696,483,761,913,620,0)
)
Se archiva la base de datos en formato csv con el nombre de callcenter_semana
.
write_csv(x = datos_semana, file = "callcenter_semana.csv")
callsemana <- read_csv(file = "callcenter_semana.csv")
── Column specification ───────────────────────────────────────────────────────
cols(
agente = col_double(),
fecha = col_date(format = ""),
llamadas = col_double(),
llamadas_tr = col_double(),
aht = col_double()
)
callsemana
La siguiente es una forma rápida de obtener un resumen de la base de datos, se obtiene información acerca de valores ausentes, el tipo de variables, etc.
skim(callsemana)
── Data Summary ────────────────────────
Values
Name callsemana
Number of rows 90
Number of columns 5
_______________________
Column type frequency:
Date 1
numeric 4
________________________
Group variables None
── Variable type: Date ────────────────────────────────────────────────────────
skim_variable n_missing complete_rate min max median
1 fecha 0 1 2020-02-15 2020-02-20 2020-02-17
n_unique
1 6
── Variable type: numeric ─────────────────────────────────────────────────────
skim_variable n_missing complete_rate mean sd p0 p25 p50 p75
1 agente 0 1 8 4.34 1 4 8 12
2 llamadas 0 1 21.8 24.4 0 11.2 17 26.8
3 llamadas_tr 0 1 4.63 3.90 0 2 3 7.75
4 aht 0 1 720. 273. 0 578. 684. 784.
p100 hist
1 15 ▇▇▇▇▇
2 203 ▇▁▁▁▁
3 15 ▇▂▂▂▁
4 2065 ▁▇▂▁▁
Se obtiene un resumen numérico de la semana para cada teleoperador, donde ser presentan algunos valores de las variables como el promedio, el valor máximo, el percentil 25, 50 y 75, entre otros.
Se presenta la base de datos para tener una vista general de las variables. Nuevamente, este formato facilita filtrar la información para buscar un dato en particular u ordenar de manera específica, adicionalmente se agregan opciones para descargar el archivo en formato pdf, excel, csv para que la persona que lea el informe pueda obtener una copia de la tabla que presentamos.
library(DT)
callsemana %>%
group_by(agente) %>%
summarise(total_llam = sum(llamadas),
prom_llam = mean(llamadas),
max_llam = max(llamadas),
de_llam = sd(llamadas),
p25_llam = quantile(llamadas, probs = 0.25),
p50_llam = quantile(llamadas, probs = 0.50),
p75_llam = quantile(llamadas, probs = 0.75),
tot_tran = sum(llamadas_tr),
prom_tran = mean(llamadas_tr),
max_tran = max(llamadas_tr),
de_tran = sd(llamadas_tr),
p25_tran = quantile(llamadas_tr, probs = 0.25),
p50_tran = quantile(llamadas_tr, probs = 0.50),
p75_tran = quantile(llamadas_tr, probs = 0.75),
prom_aht = mean(aht),
max_aht = max(aht),
de_aht = sd(aht),
p25_aht = quantile(aht, probs = 0.25),
p50_aht = quantile(aht, probs = 0.50),
p75_aht = quantile(aht, probs = 0.75)) %>%
mutate(across(is.numeric, round, digits = 2)) %>%
datatable(rownames = FALSE,
options = list(
dom = 'Bfrtip', buttons = c('copy', 'excel', 'pdf', 'csv')
),
extensions = 'Buttons', fillContainer = TRUE
)
gf1 <- callsemana %>%
ggplot(mapping = aes(x = agente, y = llamadas)) +
geom_col(fill = "cadetblue")+
scale_x_continuous(breaks = seq(1:15))+
scale_y_continuous(breaks = seq(from = 0, to = 300, by = 20))+
labs(y = "Llamadas", x = "Agente", title = "Llamadas por Agente",
subtitle = "Total de la Semana.")
gf3 <- callsemana %>%
ggplot(mapping = aes(x = agente, y = llamadas_tr)) +
geom_col(fill = "cadetblue")+
scale_x_continuous(breaks = seq(1:15))+
scale_y_continuous(breaks = seq(from = 0, to = 100, by = 5))+
labs(y = "Llamadas Transferidas", x = "Agente", title = "Llamadas Transferidas por Agente",
subtitle = "Total de la Semana.")
gf4 <- callsemana %>%
group_by(fecha , agente) %>%
mutate(agente = as_factor(agente)) %>%
summarise(totllam = sum(llamadas),
tottr = sum(llamadas_tr),
proptr = totllam/tottr) %>%
filter(totllam < 100) %>%
ggplot()+
geom_col(mapping = aes(x = agente, y = totllam), fill = "dodgerblue")+
geom_col(mapping = aes(x = agente, y = tottr), fill = "cyan4")+
labs(title = "Total de Llamadas Recibidas y Transferidas", x = "Agente", y = "Llamadas")+
scale_y_continuous(breaks = seq(from = 0, to = 180, by = 15))
`summarise()` has grouped output by 'fecha'. You can override using the `.groups` argument.
grid.arrange(gf1, gf3, gf4, nrow = 2, ncol = 2)
Obtenemos un panel de tres gráficos que representan el número total de llamadas recibidas y transferidas, en la parte superior observamos las variables de manera individual, y el gráfico de la parte inferior izquierda muestra las dos variables en un mismo diagrama de barras.
El gráfico de la zona superior izquierda muestra que los agentes 1 y 8 tienen el mayor número de llamadas recibidas durante la semana. Consultando el número de llamadas total recibidas durante la semana es de 1958.
Se presenta un gráfico de cajas para tener una idea de la dispersión de la variable llamadas.
callsemana %>%
mutate(agente = as_factor(agente)) %>%
filter(llamadas < 50) %>%
ggplot(mapping = aes(x = agente, y = llamadas, fill = agente))+
geom_boxplot()+
labs(title = "Boxplot Semana de Variable Llamadas", subtitle = "Por Agente", x = "Agente", y = "Llamadas")+
theme(legend.position = "none")
Se puede representar la densidad de las variables de diferentes formas, en este ejemplo se presentan dos para observar el comportamiento de la variable llamadas
.
callsemana %>%
filter(llamadas < 100) %>%
ggplot(mapping = aes(x = llamadas)) +
geom_density( fill = "dodgerblue4") +
facet_wrap(facets = ~agente, scales = "free")+
theme(legend.position = "none")+
labs(title = "Densidad Variable Llamadas", subtitle = "Por agente",
x = "Llamadas", y = "Densidad")
library(ggridges)
callsemana %>%
mutate(agente = as_factor(agente)) %>%
ggplot(mapping = aes(x = llamadas, y = agente))+
geom_density_ridges(fill = "dodgerblue", alpha = 0.7)+
labs(title = "Densidad variable llamadas", x = "Llamadas", y = "Agente")
callsemana %>%
filter(llamadas < 100) %>%
ggplot(mapping = aes(x = llamadas, y = aht)) +
geom_smooth(se = FALSE) +
facet_wrap(facets = ~agente, scales = "free")+
theme(legend.position = "none")+
labs(title = "Llamadas vs AHT", subtitle = "Por agente",
x = "Llamadas", y = "AHT")
callsemana %>%
filter(llamadas < 100) %>%
ggplot(mapping = aes(x = llamadas, y = llamadas_tr)) +
geom_smooth(se = FALSE) +
facet_wrap(facets = ~agente, scales = "free")+
theme(legend.position = "none")+
labs(title = "Llamadas vs transferidas", subtitle = "Por agente",
x = "Llamadas", y = "Transferidas")
Presentar un resumen de las variables para cada día de operación.
callsemana %>%
group_by(fecha) %>%
summarise(promllam = mean(llamadas),
maxllam = max(llamadas),
del = sd(llamadas),
p25l = quantile(llamadas, probs = 0.25),
p50l = quantile(llamadas, probs = 0.50),
p75l = quantile(llamadas, probs = 0.75),
promtran = mean(llamadas_tr),
maxtran = max(llamadas_tr),
det = sd(llamadas_tr),
p25t = quantile(llamadas_tr, probs = 0.25),
p50t = quantile(llamadas_tr, probs = 0.50),
p75t = quantile(llamadas_tr, probs = 0.75),
promaht = mean(aht),
maxaht = max(aht),
deaht = sd(aht),
p25aht = quantile(aht, probs = 0.25),
p50aht = quantile(aht, probs = 0.50),
p75aht = quantile(aht, probs = 0.75)
) %>%
mutate(across(is.numeric, round, digits = 2))
Se tomará nuevamente un valor de AHT entre los valores 670 y 730 como métrica; si el teleoperador alcanza estos valores de AHT al final del día podrá tener derecho a la bonificación, que se verá reflejado en la siguiente tabla.
callsemana$bonificacion <- ifelse(callsemana$aht >= 670 & callsemana$aht <= 730, "si", "no")
callsemana
También se presenta el número de agentes que bonificaron por día a continuación:
callsemana %>%
mutate(bonificacion = as_factor(bonificacion)) %>%
group_by(fecha, bonificacion) %>%
summarise(nro_agentes = n())
`summarise()` has grouped output by 'fecha'. You can override using the `.groups` argument.
Es posible construir un gráfico que resuma la información de la tabla anterior, lo haremos interactivo para observar cuáles agentes cumplen con el valor de aht.
library(plotly)
ggplotly(
callsemana %>%
mutate(agente = as_factor(agente)) %>%
ggplot(mapping = aes(x = fecha, y = aht))+
geom_ribbon(mapping = aes(ymin = 670, ymax = 730), fill = "cadetblue", alpha = 0.4)+
geom_line(aes(col = agente))+
geom_abline(slope = 0, intercept = 700, color = "forestgreen", alpha = 0.6, linetype = "dotdash")+
scale_x_date(date_breaks = "day")+
scale_y_continuous(breaks = seq(from = 0, to = 2500, by = 200))+
labs(title = "Valores de AHT por día"),
width = 800, height = 500
)
callsemana %>%
ggplot(mapping = aes(x = fecha, y = llamadas))+
geom_smooth()+
scale_x_date(date_breaks = "day")+
labs(title = "LLamadas por día")+
facet_wrap(facets = ~agente, scales = "free")
NA
callsemana %>%
ggplot(mapping = aes(x = fecha, y = llamadas_tr))+
geom_smooth()+
scale_x_date(date_breaks = "day")+
labs(title = "LLamadas Tranferidas por Día")+
facet_wrap(facets = ~agente, scales = "free")
NA
callsemana %>%
filter(llamadas <= 50) %>%
ggplot()+
geom_col(mapping = aes(x = agente, y = llamadas), fill = "aquamarine3")+
geom_col(mapping = aes(x = agente, y = llamadas_tr), fill = "chocolate2")+
facet_wrap(facets = ~fecha, scales = "free")+
scale_x_continuous(seq(from = 1, to = 15), n.breaks = 15, name = "Agente")+
scale_y_continuous(breaks = seq(from = 0, to = 40, by = 5), name = "Llamadas")+
labs(title = "Total Llamadas Recibidas y Transferidas por Día")
El lenguaje R, es una buena herramienta para la exploración de datos y manipulación de datos tabulares, permitiendo trabajar con múltiples formatos como csv, xls, txt, etc; además, proporciona funciones de graficación flexibles que proveen visualizaciones que facilitan la interpretación de la información que en conjunto, con las funciones de manejo de datos de los diferentes paquetes (tidyverse, dplyr, lubridate, DT, skimr…) y las funciones para presentar tablas dinámicas, convierten a R en una excelente opción para el análisis de datos.