Есть условный call-центр на 4 оператора. Необходимо увидеть их загрузку.
Есть время прихода звонка, время завершения звонка, время диалога и номер оператора, который ответил на звонок. В результате хочется увидеть гистограмму нагрузки с возможностью смотреть срез по 10 минут.
Я так понимаю, что на диаграмме можно будет увидеть какие звонки приходят на линию и остаются в режиме ожидания, т.к. все операторы заняты.
Благодарю!
P.S.: Я думал, что можно было бы создать какой-то CALENDARAUTO, где по секундам будет весь год, Из этой таблицы обращаться в таблицу со звонками и возвращать кол-во операторов ведущих диалог в данный момент времени. Но знатокам виднее.
Доброе время суток. ivanka, вы всё же могли бы объяснить - что вы хотите посчитать - нагрузку на оператора (и к стати, что это такое - в моём понимании это отношение времени за телефоном отнесенное к некоторой единицы измерения, например, часу) или сколько клиент дожидался, когда ему ответит оператор? Следующие
Цитата
ivanka написал: CALENDARAUTO, где по секундам будет весь год
Зачем вам посекундный календарь если
Цитата
ivanka написал: с возможностью смотреть срез по 10 минут.
Зачем лишние 600 секунд информации в базе? Вы бы детализировали - что вы хотите. Или вы предпочитаете контактировать только с представителями своего профиля работ, чтобы не писать деталей? Так не факт, что они заглянут в тему.
Андрей VG, благодарю вас за обратную связь! Уточняю. В call-центре 4 человека, необходимо увидеть, как часто бывает так, что говорят все 4 сразу. Я думаю, что поняв как это считать, я справлюсь с подсчётом пропущенных звонков, в момент, когда все 4 оператора заняты и бывают ли такие ситуации.
Я уверен, что у знатоков куда более изящные решения, чем я могу на сегодня предположить, но т.к. пока задача на стадии обсуждения, я публикую свои мысли (помидоры не кидать):
Допустим, у нас есть таблица № 1 похожая на CALENDARAUTO (в примере её нет), но только с записью даты и каждой секунды в эту дату, пример: 10.01.2019 14:55:17 10.01.2019 14:55:18 10.01.2019 14:55:19 и т.д.
При этом, в таблице присутствуют записи только в рамках рабочего времени: с 8:00 до 22:00 (чтобы уменьшить кол-во строк).
Зададим условие, что момент времени = 10.01.2019 14:55:18 в Таблице 1 - это переменная "А".
У нас есть Таблица № 2 с тремя столбцами: дата и время ответа оператора = T1 дата и время окончания звонка = T2 продолжительность сек = t3
В любой момент времени, будет ситуация, где есть 3 значения Т1 по отношению к переменной А, например:
Можно предположить, что А = одно событие. На самом деле, А может быть равно множеству событий (тем, которые равны А и тем, которые уже произошли, но не завершились):
Т1 = 10.01.2019 14:55:17 (меньше А) - будет продолжаться t3 сек, а значит происходит одновременно с А Т1 = 10.01.2019 14:55:18 (равно А) - происходит одновременно с А
Т.о. необходимо, чтобы запрос отправился из Таблицы 1 (список дат и секунды) в Таблицу 2 (время звонка) И проверил 2 параметра:
Если в пределах даты 10.01.2019, было событие Т1, которое меньше А, и Если Т1 + t3 больше А, значит это событие ещё происходит, то вернуть 1. Если в А = Т1, то вернуть 1.
Итого, в момент А мы имеем 2 события. - этот расчёт покажется кол-во звонков, на которые ответили и которые длятся в момент времени. В итоге, можно получить кривую, которая условно будет показывать загрузку "линии".
Я не стал реализовывать Вашу логику, сделал по своему. В примере во вложении представлена таблица, в которой по каждому звонку есть информация: как долго звонящий ждал ответа оператора, и сколько операторов было занято на других линиях в момент каждого звонка. Пример используемой меры с кратким описанием:
Код
CALCULATE(
COUNTROWS('звонки');
FILTER(ALL('звонки');
'звонки'[дата и время ответа оператора]<=MAX('звонки'[дата и время звонка на АТС])&&
'звонки'[дата и время окончания звонка]>=MAX('звонки'[дата и время звонка на АТС])
)
//по каждому ID звонка мера считает, сколько операторов было занято на момент этого звонка.
// первое условие - позволяет отфильтровать все строки в таблице, у которых дата и время звонка были раньше текущего звонка, т.е. все более ранние звонки.
// второе условие - позволяет отфильтровать все строки таблицы, у которых "дата и время окончания звонка оператором" больше времени текущего звонка
// пересечение этих двух условий позволяет посчитать кол-во занятых операторов в момент звонка по каждому ID.
)
График для примера оценки нагрузки звонков по дням и часам. Это как пример, на его основе Вы можете задать любые интервалы времени П.С. немного обрезал исходные данные, чтобы в лимит по килобайтам уложиться
Vladimir Chebykin написал: 'звонки'[дата и время ответа оператора] =MAX('звонки'[дата и время звонка на АТС])
Условия данной меры не входят в диапазон моего восприятия. У нас есть:
'звонки'[дата и время ответа оператора] - начало разговора = t1
звонки'[дата и время окончания звонка] - конец разговора = t2
MAX('звонки'[дата и время звонка на АТС])&& - поступление звонка на АТС в момент времени = t3
Владимир, подскажите пожалуйста, зачем мы сравниваем t1 и t2 c максимальным значением t3? В моём понимании, ваш способ берёт t1 и по всему столбцу "дата и время звонка на АТС" ищем максимальное значение t3. Не пойму это логику. Мы вроде как должны сравнивать t1 и t2 просто с t3....
Я сравнивал t3, потому что так понял вопрос про нагрузку операторов при звонках. Т.е. я понял это так: сколько свободных операторов было в момент каждого звонка. Это не совсем то, что Вам нужно - ок.
Во вложении вариант, который построен по вашей логике. Сгенерирован посекундный календарь, в календаре отмечены каждая секунда времени, в которую разговаривал оператор (от начала и до конца звонка). Время разговоров каждого оператора наложены на график, дополнительные срезы фильтруют график (почасовой и 10-минутный срезы). Чтобы уложиться в 300 кб, пришлось сильно порезать исходные данные и сгенерировать календарь на пару часов - не более. А так же для примера привел только двух трех операторов, иначе уже большой объем получается. Думаю, разберетесь и переложите логику на полный файл.
Если вы работаете в PBI попробуйте добавить визуализацию Gantt 2.2.3
Код PQ
Код
let
Excel = Excel.Workbook(File.Contents("ПУТЬ К ВАШЕМУ ФАЙЛУ"), null, true){[Item="звонки",Kind="Table"]}[Data],
#"Change type" = Table.TransformColumnTypes(Excel,{{"ID звонка", Int64.Type}, {"дата и время звонка на АТС", type datetime}, {"Тел. клиента", type text}, {"оператор", type text}, {"дата и время ответа оператора", type datetime}, {"дата и время окончания звонка", type datetime}, {"продолжительность сек", Int64.Type}}),
#"Rename columns" = Table.RenameColumns(#"Change type",{{"ID звонка", "idCall"}, {"дата и время звонка на АТС", "dateCallsToPBX"}, {"Тел. клиента", "idClient"}, {"оператор", "idOperator"}, {"дата и время ответа оператора", "dateOperatorResponse"}, {"дата и время окончания звонка", "dateEndCall"}, {"продолжительность сек", "durationCall"}}),
#"Remove null" = Table.SelectRows(#"Rename columns", each [dateOperatorResponse] <> null),
#"Added state and time by second" = Table.AddColumn(#"Remove null", "Custom", each List.Generate(
()=>[dateCallsToPBX],
(x)=>x<=[dateEndCall],
(x)=> x + #duration(0, 0, 0, 1),
(x)=>[time = x, state = if x < [dateOperatorResponse] then "client is waiting" else "#" & [idOperator] & " operator is busy"]
)),
#"Expanded list" = Table.ExpandListColumn(#"Added state and time by second", "Custom"),
#"Expanded record" = Table.ExpandRecordColumn(#"Expanded list", "Custom", {"time", "state"}, {"time", "state"}),
#"Select columns" = Table.SelectColumns(#"Expanded record",{"idCall", "dateCallsToPBX", "idClient", "idOperator", "time", "state"}),
#"Grouped Rows" = Table.Group(#"Select columns", {"idCall", "state"}, {{"Total time", each Table.RowCount(_), type number}, {"Start", each List.Min([time]), type datetime}, {"End", each List.Max([time]), type datetime}}),
#"Filtered Rows" = Table.SelectRows(#"Grouped Rows", each [Start] >= #datetime(2019, 1, 2, 0, 0, 0) and [Start] <= #datetime(2019, 1, 2, 11, 0, 0)) // < -- тут отфильтрован 1 день и 3 часа
in
#"Filtered Rows"
В визуализации установите (поля визуализации - имя поля из таблицы) Task - state Start Date - Start Duration - Total time Tooltips - idCall
В формате визуализации (кнопка с валиком):
General -> Group Task -> On General -> Duration unit -> Seconds General -> Duration min -> 1 Category Labels -> Width -> 180 (ширина с нименованием) Date type -> Type -> Houe (это будет влиять на шкалу)
Но честно говоря, куда интересней посмотреть на другое . С учетом что это праздничные дни и малая выборка.... 2 оператора могут принять 60 звонков в час с ожиданием клиента на линии 5-8 секунд, думаю это время ПЗР (увидить звонок - подготовиться к разговору, закончить разговор). При этом свобного времени будет еще около 15-20 минут в час на каждого оператора
Средняя продолжительность разговора 30 сек (рис 1) Среднее время ожидания клиента на линии 5 сек (рис2) Около 40 звонков в час. Основные звонки в первую половину дня до 60 (рис3) Низкая активность между 12 и 14 часами (видимо клиенты обедают)
Пики время ожидания между 10 и 11 часами и 13-15 часами (рис 4) Но если разделить время ожидания на количество звонков, то выделяются 3 пика - начало рабочего дня, обед и окончание рабочего дня. (рис 4.)
Быстрее всех заканчивает разговор оператор №702 В среду (2 января) и субботу (5 января) - низкая активность звонков
DrillPipe написал: В визуализации установите (поля визуализации - имя поля из таблицы) Task - state Start Date - Start Duration - Total time Tooltips - idCall В формате визуализации (кнопка с валиком): General -> Group Task -> On General -> Duration unit -> Seconds General -> Duration min -> 1 Category Labels -> Width -> 180 (ширина с нименованием) Date type -> Type -> Houe (это будет влиять на шкалу)
Где бы об этом почитать Открывал BI пару раз. Для кода Power Query место нашел. А вот остальное где - ума не приложу
Скрипт к графику 1 (на продолжительность разговора)
Код
# The following code to create a dataframe and remove duplicated rows is always executed and acts as a preamble for your script:
# dataset <- data.frame(idCall, durationCall)
# dataset <- unique(dataset)
# Paste or type your script code here:
library(ggplot2)
CALL <- dataset$'durationCall'
MEDIAN.CALL <- median(dataset$'durationCall')
MEAN.CALL <- mean(dataset$'durationCall')
ggplot(dataset, aes(CALL)) + geom_density(alpha = 0.3, size = 0.5, colour = "blue", fill = "Cyan") + geom_rug(colour = "brown") + labs(y = "", x = "Average duration of a conversation with a client")+scale_y_continuous(name = "", breaks = NULL) + geom_vline(xintercept = MEDIAN.CALL, colour = "brown")
Данные из файла указанные в первом посту, в PQ только переименовал заголовки + добавил расчет времени ожидания
DrillPipe написал: это и было создано в R script visual в PBI
Я с PBI давно не работал, ох как все быстро меняется! Очень круто, что там уже есть поддержка и R, и Python. Скоро руки дойдут до него и пойдет моя душа в рай!
ivanka написал: Андрей VG , благодарю вас за обратную связь!Уточняю. В call-центре 4 человека, необходимо увидеть, как часто бывает так, что говорят все 4 сразу.Я думаю, что поняв как это считать, я справлюсь с подсчётом пропущенных звонков, в момент, когда все 4 оператора заняты и бывают ли такие ситуации.
Добрый день.
А с какой телефонией вы работаете?
В целом не совсем понимаю, для чего вам вытягивать необходимые данные через эксель и выгрузку ваших звонков.
Как я понимаю, вас интересуют потери вызовов на провайдере (до IVR), и потери в очереди ожидания (на IVR).
Вы же можете посмотреть количество потерянных вызовов в очереди либо из вашей телефонии (запросить эти данные у тех.поддержки атс (ну или кто у вас занимается обслуживанием), эта статистика легко делается), либо запросить данные у вашего оператора связи (потери до IVR).
Если у вас будет много потерь на IVR, то вы сможет посмотреть среднее время ожидания клиента в очереди до его сброса (СПА - связь прервана абонентом) не дождавшись ответа оператора, и среднее время ожидания клиента в очереди до ответа оператора. Имея эти цифры вы уже сможете провести оптимизацию самого IVR и понять ваш SL (Service Level), после чего рассчитать сколько операторов вам нужно будет вывести в линию дополнительно.
Это уже больше в тему КЦ, буду рад помочь по его вопросам если нужно, но уже в ЛС все же.
UPD: Да и по вашей выгрузке цифры не особо бьются. У вас продолжительность разговора отображается как разница между столбцами "дата и время ответа оператора" и "дата и время окончания звонка" именно в секундных значениях. Разница в минутах не идет в расчет продолжительности разговора.