Что такое Process Mining или как из системных логов получить данные для оптимизации бизнес-процессов. Ликбез и практический пример процессной аналитики c Python-библиотекой PM4PY.
Что такое Process Mining
Для продвижения моего нового курса для бизнес-аналитиков и руководителем по управлению продуктами и процессами на основе данных, сегодня расскажу, что такое Process Mining и покажу практический пример анализа логов с помощью Python-библиотеки PM4PY.
Хотя термин Process Mining (PM) появился уже более 20 лет назад, этот подход к анализу и улучшению бизнес-процессов на основе системных логов, до сих пор реализован только в отдельных компаниях. Во многом это связано с недостаточным уровнем процессной зрелости и высокой долей ручных операций. Дополнительным препятствием для практического внедрения процессной аналитики может стать отсутствие дата-инженеров и корпоративных хранилищ данных.
Исходными данными для процессной аналитики являются логи прикладных информационных систем, где фиксируются все события пользовательского поведения и действия пользователей. Впрочем, PM-системы могут получать исходные данные не только из DWH, но и непосредственно из прикладных систем, если необходим мониторинг процессов в реальном времени. Результаты анализа обычно визуализируются на дэшбордах, показывая графы выполнения пользовательских действий и статистику событий. Также многие системы формируют список рекомендаций для улучшения исследованной деятельности.

К системам класса Process Mining относятся Proceset, Minit, ARIS Process Performance Manager, ProM, Celonis Process Mining. Также для процессной аналитики можно использовать специализированные библиотеки, например, Python-пакет интеллектуального анализа процессов PM4Py. Как работает, рассмотрим далее на примере XES-файла с событиями пользовательского поведения в процессе обработки заявки.
Практический пример анализа логов пользовательского поведения
В качестве входных данных для интеллектуального анализа процессов Python-пакет PM4Py принимает файлы форматов CSV и XES, который специально разработан для хранения событийных логов процессной аналитики. Формат XES (eXtensible Event Stream) основан на XML и более предпочтителен по сравнению с CSV — простым табличным форматом без иерархической структуры. XES поддерживает вложенные структуры, позволяя моделировать сложные процессы с различными атрибутами событий, легко расширяется новыми атрибутами и элементами без нарушения общей структуры файла. Также XES позволяет включать метаданные о самом логе: описание процесса, источник данных и прочие важные характеристики.
Кроме того, XES поддерживает различные типы данных для атрибутов событий (строки, числа, даты), что повышает точность и надежность анализа. Также XES эффективно обрабатывает временные метки и последовательности событий, что критично для анализа процессов. Наконец, многие специализированные PM-инструменты оптимизированы для работы с XES-файлами, хотя поддерживают и CSV.
Структура XES-файла состоит из следующих основных элементов:
- Трейсы (Traces) — последовательности событий, связанных с конкретными экземплярами процесса. Каждый трейс начинается с уникального идентификатора.
- События (Events) — отдельные шаги или действия внутри трейса. Каждое событие может содержать различные атрибуты: название события, временные метки, ответственные ресурсы и другие данные.
- Глобальные атрибуты (Global Attributes) — общие свойства, применяемые ко всему журналу, например, информация о модели или источнике данных.
Для рассматриваемого примера я сгенерировала такой XES-файл:
<?xml version="1.0" encoding="UTF-8"?> <log> <trace> <string key="concept:name" value="Трасса_1" /> <event> <string key="concept:name" value="принять заявку" /> <string key="concept:position" value="клиентский менеджер" /> <date key="timestamp:start" value="2025-02-01T09:00:00" /> <date key="timestamp:end" value="2025-02-01T09:30:00" /> <date key="time:timestamp" value="2025-02-01T09:00:00" /> </event> <!-- XOR-разветвление --> <event> <string key="concept:name" value="взять заявку в работу" /> <string key="concept:position" value="пресейл-аналитик" /> <date key="timestamp:start" value="2025-02-01T09:31:00" /> <date key="timestamp:end" value="2025-02-01T09:45:00" /> <date key="time:timestamp" value="2025-02-01T09:31:00" /> </event> <event> <string key="concept:name" value="открыть карточку клиента" /> <string key="concept:position" value="пресейл-аналитик" /> <date key="timestamp:start" value="2025-02-01T09:46:00" /> <date key="timestamp:end" value="2025-02-01T10:00:00" /> <date key="time:timestamp" value="2025-02-01T09:46:00" /> </event> <event> <string key="concept:name" value="завершить заявку" /> <string key="concept:position" value="клиентский менеджер" /> <date key="timestamp:start" value="2025-02-01T10:01:00" /> <date key="timestamp:end" value="2025-02-01T10:15:00" /> <date key="time:timestamp" value="2025-02-01T10:01:00" /> </event> </trace> <trace> <string key="concept:name" value="Трасса_2" /> <event> <string key="concept:name" value="принять заявку" /> <string key="concept:position" value="клиентский менеджер" /> <date key="timestamp:start" value="2025-02-02T09:00:00" /> <date key="timestamp:end" value="2025-02-02T09:30:00" /> <date key="time:timestamp" value="2025-02-02T09:00:00" /> </event> <!-- XOR-разветвление --> <event> <string key="concept:name" value="отклонить заявку" /> <string key="concept:position" value="клиентский менеджер" /> <date key="timestamp:start" value="2025-02-02T09:31:00" /> <date key="timestamp:end" value="2025-02-02T09:45:00" /> <date key="time:timestamp" value="2025-02-02T09:31:00" /> </event> <event> <string key="concept:name" value="завершить заявку" /> <string key="concept:position" value="клиентский менеджер" /> <date key="timestamp:start" value="2025-02-02T09:46:00" /> <date key="timestamp:end" value="2025-02-02T10:00:00" /> <date key="time:timestamp" value="2025-02-02T09:46:00" /> </event> </trace> <!-- Трасса с AND-разветвлением --> <trace> <string key="concept:name" value="Трасса_3" /> <event> <string key="concept:name" value="принять заявку" /> <string key="concept:position" value="клиентский менеджер" /> <date key="timestamp:start" value="2025-02-03T09:00:00" /> <date key="timestamp:end" value="2025-02-03T09:30:00" /> <date key="time:timestamp" value="2025-02-03T09:00:00" /> </event> <!-- AND-разветвление: параллельные действия --> <event> <string key="concept:name" value="проверить документы" /> <string key="concept:position" value="менеджер проекта" /> <date key="timestamp:start" value="2025-02-03T09:31:00" /> <date key="timestamp:end" value="2025-02-04T09:45:00" /> <date key="time:timestamp" value="2025-02-03T09:31:00" /> </event> <event> <string key="concept:name" value="согласовать бюджет" /> <string key="concept:position" value="менеджер проекта" /> <date key="timestamp:start" value="2025-02-03T09:31:00" /> <date key="timestamp:end" value="2025-02-13T09:50:00" /> <date key="time:timestamp" value="2025-02-03T09:31:00" /> </event> <!-- Слияние после параллельных действий --> <event> <string key="concept:name" value="завершить заявку" /> <string key="concept:position" value="клиентский менеджер" /> <date key="timestamp:start" value="2025-02-03T09:51:00" /> <date key="timestamp:end" value="2025-02-03T10:00:00" /> <date key="time:timestamp" value="2025-02-03T09:51:00" /> </event> </trace> <!-- Трасса с OR-разветвлением --> <trace> <string key="concept:name" value="Трасса_4" /> <event> <string key="concept:name" value="принять заявку" /> <string key="concept:position" value="клиентский менеджер" /> <date key="timestamp:start" value="2025-02-04T09:00:00" /> <date key="timestamp:end" value="2025-02-04T09:30:00" /> <date key="time:timestamp" value="2025-02-04T09:00:00" /> </event> <!-- OR-разветвление: выбор нескольких опций --> <event> <string key="concept:name" value="провести анализ рисков" /> <string key="concept:position" value="бизнес-аналитик" /> <date key="timestamp:start" value="2025-02-04T09:31:00" /> <date key="timestamp:end" value="2025-02-09T09:50:00" /> <date key="time:timestamp" value="2025-02-04T09:31:00" /> </event> <event> <string key="concept:name" value="провести исследование рынка" /> <string key="concept:position" value="бизнес-аналитик" /> <date key="timestamp:start" value="2025-02-07T09:31:00" /> <date key="timestamp:end" value="2025-02-11T09:45:00" /> <date key="time:timestamp" value="2025-02-04T09:31:00" /> </event> <!-- Объединение после OR-разветвления --> <event> <string key="concept:name" value="завершить заявку" /> <string key="concept:position" value="клиентский менеджер" /> <date key="timestamp:start" value="2025-02-04T09:51:00" /> <date key="timestamp:end" value="2025-02-04T10:00:00" /> <date key="time:timestamp" value="2025-02-04T09:51:00" /> </event> </trace> <!-- Дополнительные трассы для полноты логики процесса --> <trace> <string key="concept:name" value="Трасса_5" /> <event> <string key="concept:name" value="принять заявку" /> <string key="concept:position" value="клиентский менеджер" /> <date key="timestamp:start" value="2025-02-05T09:00:00" /> <date key="timestamp:end" value="2025-02-05T09:20:00" /> <date key="time:timestamp" value="2025-02-05T09:00:00" /> </event> <event> <string key="concept:name" value="открыть карточку заявки" /> <string key="concept:position" value="клиентский менеджер" /> <date key="timestamp:start" value="2025-02-05T09:21:00" /> <date key="timestamp:end" value="2025-02-05T09:40:00" /> <date key="time:timestamp" value="2025-02-05T09:21:00" /> </event> <event> <string key="concept:name" value="взять заявку в работу" /> <string key="concept:position" value="пресейл-аналитик" /> <date key="timestamp:start" value="2025-02-05T09:41:00" /> <date key="timestamp:end" value="2025-02-05T10:00:00" /> <date key="time:timestamp" value="2025-02-05T09:41:00" /> </event> <event> <string key="concept:name" value="завершить заявку" /> <string key="concept:position" value="клиентский менеджер" /> <date key="timestamp:start" value="2025-02-05T10:01:00" /> <date key="timestamp:end" value="2025-02-05T10:20:00" /> <date key="time:timestamp" value="2025-02-05T10:01:00" /> </event> </trace> </log>
Предположим, это сырая выгрузка из CRM-системы, где работают различные специалисты, принимая, маршрутизируя и выполняя пользовательские заявки. Регламент процесса отсутствует или неактуален. Поэтому получим BPMN-диаграмму процесса на основе реальных данных, построив ее с помощью Python-библиотеки PM4Py из событий этого лог-файла.
Чтобы вы могли повторить это упражнение без установки дополнительного ПО, в качестве среды разработки можно использовать Google Colab.
Сперва установим библиотеки и импортируем модули.
!pip install pm4py pandas import pm4py from pm4py.objects.log.importer.xes import importer as xes_importer from collections import defaultdict import statistics
Далее загрузим исходный XES-файл в пользовательскую директорию.

Наконец, напишем и запустим код для анализа логов и построения BPMN-диаграммы:
# Функция для форматирования длительности def format_duration(minutes): if minutes > 90: days = minutes // (24 * 60) minutes_rem = minutes % (24 * 60) hours = minutes_rem // 60 minutes_final = minutes_rem % 60 parts = [] if days > 0: parts.append(f"{int(days)} дн.") if hours > 0: parts.append(f"{int(hours)} ч.") if minutes_final > 0: parts.append(f"{int(minutes_final)} мин.") return ' '.join(parts) else: return f"{round(minutes, 2)} мин" # Импорт XES-лога log = xes_importer.apply('/content/log_4_article.xes') # Вычислим среднюю длительность каждого действия activity_durations = defaultdict(list) for trace in log: for event in trace: start_time = event.get('time:timestamp') # есть отдельные атрибуты для начала и конца события end_time = event.get('timestamp:end') if end_time: duration = (end_time - start_time).total_seconds() / 60 # в минутах activity_durations[event['concept:name']].append(duration) average_durations = {activity: statistics.mean(durations) for activity, durations in activity_durations.items()} # Определим исполнителей для каждого действия activity_performers = defaultdict(set) for trace in log: for event in trace: performer = event.get('concept:position', 'Неизвестно') activity_performers[event['concept:name']].add(performer) # Дополняем названия действий for trace in log: for event in trace: activity = event['concept:name'] performers = ", ".join(activity_performers[activity]) avg_duration_minutes = average_durations[activity] formatted_duration = format_duration(avg_duration_minutes) # Обновляем название действия с форматированной длительностью event['concept:name'] = ( f"Задача: {activity}\n\n" f"Исполнитель: {performers}\n" f"Средняя длительность: {formatted_duration}" ) # Создаем BPMN-модель и визуализируем её bpmn_model = pm4py.discover_bpmn_inductive(log) pm4py.view_bpmn(bpmn_model)
В результате выполнения кода получим BPMN-диаграмму.

К сожалению, PM4Py не поддерживает весь многообразный алфавит нотации BPMN, не позволяя показать промежуточные события, различные шлюзы, кроме XOR, пулы и дорожки. Однако, полученная диаграмма довольно наглядно показывает логику выполнения процесса, позволяя сформировать гипотезы о возможностях его улучшения.

Как это сделать, а также какие еще возможности для процессного анализа и совершенствования предоставляет подход Process Mining и его реализация в PM4Py, вы узнаете на моем новом курсе Школы прикладного бизнес-анализа и проектирования информационных систем в нашем лицензированном учебном центре обучения и повышения квалификации системных и бизнес-аналитиков в Москве: