Разместить здесь вашу рекламу


Найти всё. Text Mining

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

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

Немного скучной теории: формулировка заключений финансовых управляющих не регламентируется специальными правилами и потому может выглядеть по-разному и может находится в разных частях документа. Но в подобных заключениях (если они имеются) всегда будут упоминаться номер специального счета (для физ. лица он начинается с 4), сумма и фразы, подразумевающие разрешение на снятие денежных средств. С помощью данных эвристик можно локализовать нужный нам кусок текста!

Воспользуюсь python и библиотеками regex и Natasha. С помощью регулярных выражений локализирую нужные предложения, а разбивать текст на предложения и вытаскивать необходимые поля буду с Natasha. Многие знакомы с отличными способностями библиотеки Natasha к распознаванию именованных сущностей (имена, города, названия компаний и т.д.). Но, помимо этого, она умеет находить даты, суммы денег и даже адреса!

Импортирую нужные библиотеки:

import os
import pandas as pd
from natasha import (Doc, Segmenter, NewsEmbedding, NewsMorphTagger,
                     NewsSyntaxParser, MorphVocab, NewsNERTagger,
                     DatesExtractor, MoneyExtractor)
import re
from collections import Counter
import openpyxl
import datetime
pd.options.display.max_columns = 100
pd.options.display.max_rows = 100
import warnings 
warnings.filterwarnings('ignore')

Напишу функцию get_info, которая на вход будет принимать текст и предложения, а на выходе возвращает номер счета, сумму и период. Сначала с помощью регулярных выражений нахожу центральное предложение и беру соседние 2 предложения.

def get_info(text, sents):
  try:
    match = re.finditer('4\d{19}', text) 
    marks = [m.start() for m in match]
    bill = None
    money = None
    date1 = None
    date2 = None 
    for ind, i in enumerate(sents):
      for mark in marks:
   if i.start <= mark and i.stop > mark: 
      mini_sents = [sents[ind-1], i ,sents[ind+1]] # берем 3 предложения
      bill_text = ' '.join([x.text for x in mini_sents]) 

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

patterns = ['не более', 'в пределах', 'разблокир\w+', 'не может превышать', 'превыша\w+', 'самостоятельно', 'имеет право', 'распоряж\w+', '[Дд]еньги снимаются']              
      matches = []
      [matches.extend(re.findall(pattern, bill_text)) for pattern in patterns]
     if matches:
       matches = money_extractor(bill_text) # распознавание денег 
       facts = [i.fact.as_json for i in matches]
       facts = [f.get('amount') for f in facts]
       money = facts
       bill = re.search('4\d{19}',bill_text) # забираем счет 
  try:
    start = [m.start() for m in 
re.finditer('\s+с\s+\d{2}', bill_text)][0]
	   # находим упоминание периода
         dates = dates_extractor(bill_text[start:]) # распознавание дат 
         dates = [datetime.date(d.fact.as_json.get('year'), 
                                d.fact.as_json.get('month'), 
                                d.fact.as_json.get('day')) 
                 for d in dates]
         date1 = dates[0]
         date2 = dates[1]                
       except:
         pass
                            
       if money:
         money = [0]
            
       return bill, money, date1, date2
    except:
       return None, None, None, None

Создаю датафрейм:

data = pd.DataFrame({'ЗНО':[], 'Номер счета' : [], 'Дата 1' : [], 
                      'Дата 2' : [], 'Сумма' : []})

В цикле открываю и считаю информацию из файлов, убираю символы переноса и табуляции. Затем передаю текст в Natasha для токенизации и распознавания сущностей. Вызываю написанную мной функцию get_info и дописываю в датафрейм найденную информацию.

segmenter = Segmenter()
emb = NewsEmbedding()
morph_tagger = NewsMorphTagger(emb)
syntax_parser = NewsSyntaxParser(emb)
morph_vocab = MorphVocab()
ner_tagger = NewsNERTagger(emb)

path = 'docs/'
filenames = os.listdir(path)

for filename in filenames:
  with open(path + filename, 'r') as file:
    text += file.read()
  text = text.replace('\n', ' ')
  text = text.replace('\t', ' ')
  doc = Doc(text)
  dates_extractor = DatesExtractor(morph_vocab)
  money_extractor = MoneyExtractor(morph_vocab)
  doc.segment(segmenter)
  doc.tag_morph(morph_tagger)
  doc.parse_syntax(syntax_parser)
  doc.tag_ner(ner_tagger)
    num, money, date1, date2 = get_info(doc.text, doc.sents)
  data = pd.concat([pd.DataFrame({
    'ЗНО':[filename.split('.')[0].split('_')[0]], 
	# ЗНО в нашем случае являлось название документа
               'Номер счета' : [num], 'Дата 1' : [date1], 
               'Дата 2' : [date2], 'Сумма' : [money]}), data])

На выходе получаю желаемые данные в виде таблицы:

Таким образом, с помощью специальных эвристик и уже существующих инструментов мне удалось автоматизировано и качественно получить желаемую информацию из нескольких сотен тысяч документов и, при этом, не изобретать колесо. На этом всё, надеюсь была полезна, всем успехов!

Источник: https://habr.com/ru/post/673726/


Интересные статьи

Интересные статьи

Привет, меня зовут Диана. Мне 25 лет, по образованию я математик, сейчас работаю продакт-менеджером. Хочу рассказать о том, как я пришла в IT-компанию на вакансию «Просто хороший человек», какой опыт ...
Атма Мани, переводом статьи которого мы делимся к старту флагманского курса по Data Science, — ведущий инженер по продуктам ArcGIS API для Python в компании Esri. В этом материале он рассказывает, как...
Однажды я заметил, что один из моих скриптов, сканирующих почтовые журналы, не выдал сообщение об одной записи, о наличии которой в журнале мне было известно (о ней меня оповестил дру...
Если вы последние лет десять следите за обновлениями «коробочной версии» Битрикса (не 24), то давно уже заметили, что обновляется только модуль магазина и его окружение. Все остальные модули как ...
На примере данных из системы управления ИТ-услугами (ITSM). В предыдущей статье SAP Process Mining или как разобраться в своих бизнес-процессах мы говорили о Process Mining и о его применении ...