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

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

У каждого чата есть свой уникальный идентификатор, у сообщения – тег отправителя, дата и время создания.

Для текущей задачи потребовался список возможных документов, которые могут запросить в ходе сделки с недвижимостью. В данном случае перечень документов был получен с помощью кластеризации сообщений от консультантов. Записываем найденные документы в список без предлогов.

Перед поиском документов необходимо очистить сообщения от стоп-слов (предлоги, часто употребляемые слова, например, приветствия и т.д.), символов, ссылок и чисел. Также заменить частые аббревиатуры на полные названия, например ДКП – на договор купли-продажи. После фильтрации текста производим токенизацию и стемминг. Список документов преобразовываем в список n-грамм.

document_list_tokens = []
for d in document_list:
    document_list_tokens.append([Porter.stem(el) for el in d.split()])
documents_one_grams = [el for el in document_list_tokens if len(el) == 1]
documents_bigrams = [el for el in document_list_tokens if len(el) == 2]
documents_3grams = [el for el in document_list_tokens if len(el) == 3]
documents_4grams = [el for el in document_list_tokens if len(el) == 4]

Листинг 1. Преобразование документов в список n-грамм.

С помощью библиотеки nltk токены сообщений также преобразовываем в список n-грамм и сравниваем их с n-граммами документов. На выходе получаем вектор, где значение «1» на конкретной позиции означает, встречался ли документ в сообщении.

from nltk import ngrams
def search_docs(tokens):
    res_dict = {}
    res = []
    for t in tokens:
        if [t] in documents_one_grams:
            if res_dict.get(t):
                res_dict[t] += 1
            else:
                res_dict[t] = 1
    token_bigrams = ngrams(tokens,2)
    for gram in token_bigrams:
        if list(gram) in documents_bigrams:
            if res_dict.get(gram):
                res_dict[gram] += 1
            else:
                res_dict[gram] = 1
    token_3grams = ngrams(tokens,3)
    for gram in token_3grams:
        if list(gram) in documents_3grams:
            if res_dict.get(gram):
                res_dict[gram] += 1
            else:
                res_dict[gram] = 1
    token_4grams = ngrams(tokens,4)
    for gram in token_4grams:
        if list(gram) in documents_4grams:
            if res_dict.get(gram):
                res_dict[gram] += 1
            else:
                res_dict[gram] = 1
    
    for d in document_list_tokens:
        val = res_dict.get(tuple(d)) 
        val_one_gram = None
        if len(d) == 1:
            val_one_gram = res_dict.get(str(d[0]))
        if val is None and val_one_gram is None:
            res.append(0)
        else:
            res.append(1)
    return res

Листинг 2. Поиск документов.

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

            Для каждого сообщения выделяем n-граммы документов, которые в нем встречаются, и запоминаем порядок. Далее соединяем каждый документ попарно со следующим по порядку.  

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

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

            В итоге был получен следующий граф процесса:

Данная статья показывает, как применять process mining в тех случаях, когда статусы событий определяются с помощью анализа текста. Метод, описанный в статье, подходит и для других задач, например для анализа чатов технической поддержки. Анализируя сообщения в чатах таким образом, можно выявить типичные ошибки и изменить процесс в сторону уменьшения затрачиваемого клиентом времени, оценить работу консультантов.              

Код, используемый в этой статье, можно найти по ссылке на Github’е