Pandas, Process mining

Как составить «Слово процесса»

Время прочтения: 4 мин.

Что первое приходит в голову, когда вы слышите о «Process mining»? Я представляю граф процесса, состоящий из n вершин и m ребер.  Для чего он нужен? Думаю, все и так знают — он помогает анализировать переходы между активностями. Все это замечательно, когда активностей и переходов мало, пример на рис.1

Рисунок 1

А если активностей больше 5? Количество возможных переходов возрастает, и граф становится сложно «читать». Для удобства анализа всех возможных переходов можно использовать «Слово процесса» (СП)

СП — это комбинации закодированных активностей лога, которая поможет вам при анализе бизнес процесса. Рассмотрим далее, как составить такое «Слово». Возьмем процесс формирования заявок, заявка должна пройти путь Черновик — На согласовании – Утвержден. Данные по заявкам я сохранила в csv файл, состоящий из 3 столбцов: ИД, Статус и Изменено.

Пример 1 заявки

Импортируем библиотеки pandas, itertools и string

import pandas as pd
from itertools import combinations
from string import ascii_uppercase as alphabet

Читаем лог в датафрейм, я еще переименовываю столбцы.

df = pd.read_csv('C:\\Users\\Golovataya-AM\\Desktop\\for ipr.csv', sep = ';', encoding = 'cp1251')
df = df.rename(columns = {'ИД':'id_column','Статус':'activity_column', 'Изменено': 'dt_column'})
df.head(3)

Теперь наш датафрейм выглядит так:

Считаем количество уникальных активностей (в нашем примере всего 3 активности — Черновик, на согласовании, утвержден) и записываем в список uniq_activ.

uniq_activ = df['activity_column'].unique()

Формируем список, состоящий из латинского алфавита. Для этого мы импортировали библиотеки string и itertools.

simbol = [''.join(item) for item in combinations(alphabet,1)]

После соединения списков uniq_activ и symbol получаем датафрейм, содержащий символы и их расшифровки, т.е. уникальные активности заявки.

uniq_activ_encoder = pd.DataFrame({'activity_column':uniq_activ,'symbol':simbol[:len(uniq_activ)]})

Теперь можно джойнить фреймы df и uniq_activ_encoder, но не забываем сортировку по времени. Иначе СП получится неправильным, так как последовательность активностей будет нарушена.

df = df.merge(uniq_activ_encoder, on='activity_column',how='left').sort_values(by=['id_column','dt_column','activity_column'])

Добавляем разделитель “,” и схлопываем все значение из столбца  ‘symbol_’ , группируя по ИД.

str.slice() нужен, чтобы удалить последнюю «запятую»
df['symbol_']=df['symbol']+','
df['process_word'] = df.groupby('id_column')['symbol_'].transform('sum').str.slice(stop=-1)

У нас получился датафрейм, содержащий ИД задачи и СП, описывающее все шаги и их последовательность.

df[['id_column','process_word']].drop_duplicates().reset_index(drop=True)\

Внесем корректировки в наш скрипт. Сейчас мы анализируем процесс, состоящий из трех действий. А если ваши задачи будут содержать 25 действий или 1500? Чтобы наше «Слово» работало с любым объемом активностей, расширим количество уникальных символов. Так как английский алфавит ограничен и содержит всего 26 букв, добавим комбинации, что позволит увеличить уникальные значения, например, до 17 576. Считаем количество действий и записываем в условие. Если активностей меньше 26, символ равен букве, если длина списка uniq_activ меньше 650, то создается комбинация.

if len(uniq_activ)<26:
    simbol =[''.join(item) for item in alphabet]
elif len(uniq_activ)<650:
    simbol=[''.join(item) for item in combinations(alphabet,2)]
else:
    simbol =[''.join(item) for item in combinations(alphabet,3)]

Финальная версия СП.

import pandas as pd
from itertools import combinations
from string import ascii_uppercase as alphabet
df = pd.read_csv('C:\\Users\\...\\log.csv', sep = ';', encoding = 'cp1251')
df = df.rename(columns = {'ИД':'id_column','Активность':'activity_column', 'Дата: 'dt_column'})
uniq_activ = df['activity_column'].unique()
if len(uniq_activ)<26:
    simbol =[''.join(item) for item in alphabet]
elif len(uniq_activ)<650:
    simbol=[''.join(item) for item in combinations(alphabet,2)]
else:
    simbol =[''.join(item) for item in combinations(alphabet,3)]
uniq_activ_encoder = pd.DataFrame({'activity_column':uniq_activ,'symbol':simbol[:len(uniq_activ)]})
df = df.merge(uniq_activ_encoder, on='activity_column',how='left').sort_values(by=['id_column','dt_column','activity_column'])
df['symbol_']=df['symbol']+','
df['process_word'] = df.groupby('id_column')['symbol_'].transform('sum').str.slice(stop=-1)
df[['id_column', 'process_word']].drop_duplicates()

Тестируем полученный скрипт на логе, с количеством уникальных активностей 36. Теперь каждая активность кодируется 2 буквами.

Мы получили тот же граф процесса, но в буквенной форме, где все возможные пути описаны комбинацией символов. При тестировании на большом количестве активностей этот способ мне показался удобнее.

Советуем почитать