Страницы: 1
RSS
PQ. PP. Вычисление нагрузки на операторов в "Х" момент времени, вычисление нагрузки по секундам
 
Здравствуйте!
Прошу помочь с решением задачи.

Есть условный call-центр на 4 оператора.
Необходимо увидеть их загрузку.

Есть время прихода звонка, время завершения звонка, время диалога и номер оператора, который ответил на звонок.
В результате хочется увидеть гистограмму нагрузки с возможностью смотреть срез по 10 минут.

Я так понимаю, что на диаграмме можно будет увидеть какие звонки приходят на линию и остаются в режиме ожидания, т.к. все операторы заняты.

Благодарю!

P.S.: Я думал, что можно было бы создать какой-то CALENDARAUTO, где по секундам будет весь год, Из этой таблицы обращаться в таблицу со звонками и возвращать кол-во операторов ведущих диалог в данный момент времени. Но знатокам виднее.
Изменено: ivanka - 14.02.2020 16:48:12
 
Доброе время суток.
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 по отношению к переменной А, например:

А = 10.01.2019 14:55:18,
и есть:
Т1 = 10.01.2019 14:55:17 (меньше А)
Т1 = 10.01.2019 14:55:18 (равно А)
Т1 = 10.01.2019 14:55:19 (больше А)

Можно предположить, что А =  одно событие.
На самом деле, А может быть равно множеству событий (тем, которые равны А и тем, которые уже произошли, но не завершились):

Т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 события. - этот расчёт покажется кол-во звонков, на которые ответили и которые длятся в момент времени.
В итоге, можно получить кривую, которая условно будет показывать загрузку "линии".

А как реализовать не пойму.  
Изменено: ivanka - 17.02.2020 12:23:31
 
Я не стал реализовывать Вашу логику, сделал по своему. В примере во вложении представлена таблица, в которой по каждому звонку есть информация: как долго звонящий ждал ответа оператора, и сколько операторов было занято на других линиях в момент каждого звонка.
Пример используемой меры с кратким описанием:
Код
CALCULATE(
   COUNTROWS('звонки');
      FILTER(ALL('звонки');
         'звонки'[дата и время ответа оператора]<=MAX('звонки'[дата и время звонка на АТС])&&
         'звонки'[дата и время окончания звонка]>=MAX('звонки'[дата и время звонка на АТС])
         )
//по каждому ID звонка мера считает, сколько операторов было занято на момент этого звонка.
// первое условие - позволяет отфильтровать все строки в таблице, у которых дата и время звонка были раньше текущего звонка, т.е. все более ранние звонки.
// второе условие - позволяет отфильтровать все строки таблицы, у которых "дата и время окончания звонка оператором" больше времени текущего звонка
// пересечение этих двух условий позволяет посчитать кол-во занятых операторов в момент звонка по каждому ID.
      )

График для примера оценки нагрузки звонков по дням и часам. Это как пример, на его основе Вы можете задать любые интервалы времени
П.С. немного обрезал исходные данные, чтобы в лимит по килобайтам уложиться
Изменено: Vladimir Chebykin - 17.02.2020 14:25:22
 
Цитата
Vladimir Chebykin написал:
'звонки'[дата и время ответа оператора] =MAX('звонки'[дата и время звонка на АТС])
Условия данной меры не входят в диапазон моего восприятия.
У нас есть:
  1. 'звонки'[дата и время ответа оператора] - начало разговора = t1
  2. звонки'[дата и время окончания звонка] - конец разговора = t2

  3. MAX('звонки'[дата и время звонка на АТС])&& - поступление звонка на АТС в момент времени = t3
Владимир, подскажите пожалуйста, зачем мы сравниваем t1 и t2 c максимальным значением t3?
В моём понимании, ваш способ берёт t1 и по всему столбцу "дата и время звонка на АТС" ищем максимальное значение t3. Не пойму это логику.
Мы вроде как должны сравнивать t1 и t2 просто с t3....
Изменено: ivanka - 17.02.2020 18:10:37
 
Я сравнивал t3, потому что так понял вопрос про нагрузку операторов при звонках. Т.е. я понял это так: сколько свободных операторов было в момент каждого звонка. Это не совсем то, что Вам нужно - ок.
 
Во вложении вариант, который построен по вашей логике. Сгенерирован посекундный календарь, в календаре отмечены каждая секунда времени, в которую разговаривал оператор (от начала и до конца звонка). Время разговоров каждого оператора наложены на график, дополнительные срезы фильтруют график (почасовой и 10-минутный срезы). Чтобы уложиться в 300 кб, пришлось сильно порезать исходные данные и сгенерировать календарь на пару часов - не более. А так же для примера привел только двух трех операторов, иначе уже большой объем получается. Думаю, разберетесь и переложите логику на полный файл.
Изменено: Vladimir Chebykin - 18.02.2020 09:41:10 (UPD: добавил третьего оператора)
 
Vladimir Chebykin, благодарю за решение! Протестирую его в Power BI.
 
Если вы работаете в 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, большое спасибо за ликбез. Это действительно важно не только суметь обработать данные, но и внятно их представить.
 
Цитата
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 место нашел. А вот остальное где - ума не приложу
 
DrillPipe, классные графики - очень на "R" походит. Для статистического анализа очень наглядны.
 
Михаил Л,
Визуальные элементы в Power BI
Галлерея визуальных элементов

Если желаете узнать побольше от участников формуа про визуализацию - создайте новый запрос, так как это не соответствует теме
 
Vladimir Chebykin,
это и было создано в R script visual в PBI

Скрипт к графику 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:
Да и по вашей выгрузке цифры не особо бьются. У вас продолжительность разговора отображается как разница между столбцами "дата и время ответа оператора" и "дата и время окончания звонка" именно в секундных значениях. Разница в минутах не идет в расчет продолжительности разговора.
Изменено: L_A_K - 21.02.2020 12:38:34
Страницы: 1
Наверх