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

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

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

Подбор слов триггеров осуществляется с помощью библиотеки pymorphy2, которая является морфологическим анализатором русского языка для обработки текста в NLP задачах. Стояла задача максимально четко их определить, чтобы, после выгрузки методом Web-scraping и отбором слов-триггеров, в отклонения попали только интересующие нас закупки. Это была наиболее трудоемкая процедура, так как пришлось проанализировать Базу решений ФАС, чтобы сопоставить список слов-триггеров, которые несопоставимы и являются конкурирующими между собой.

Массив технических заданий выгружается автоматизированным методом Web-scraping с сайта. Для того, чтобы преобразовать и распознать каждый из форматов: pdf, Excel, Word, rar, zip в текстовый документ для последующей обработки через Pymorphy2 необходимо установить ABBYY FineReader и LibreOffice, первая из которых через скрипт запускает задачу HotFolder, которая в свою очередь распознает сканы документов для возможности поиска текста в документе.

Преобразование уже распознанного текста документов в нормальную форму можно представить следующей функцией converter, функция countWords подсчитывает количество вхождений слов в тексте, текст очищается от слов, которые имеют длину меньше 4, а также от именованных слов, которые не имеют смысловой необходимости, такие как имена, адреса, даты, которые содержатся в словаре Rus_stop_words.

import pymorphy2
def del_stop_words(input, Rus_stop_words):
    try:
        return ' '.join([word for word in input.split() if word not in Rus_stop_words])
    except AttributeError:
        pass

def delete(input):
    try:
        return ' '.join([word for word in input.split() if len(word)>4])
    except AttributeError:
        pass

morph = pymorphy2.MorphAnalyzer()

def converter (sentence):
    list = []
    words = sentence.split()
    for item in words:
        list.append(morph.parse(item)[0].normal_form)
    return ' '.join(list)    
def countWords(a_list):
    words = {}
    for i in range(len(a_list)):
        item = a_list[i]
        count = a_list.count(item)
        words[item] = count
    return sorted(words.items(), key = lambda item: item[1], reverse=True)
      
with open('stop_rus_words.txt', 'r', encoding="utf-8-sig") as fs:
    Rus_stop_words = fs.read().split(',')
fs.close()

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

resultdict={}
for text in dff['Text']:
    aa=countWords(text.split())
    a=dict(aa)
    for key in a:
        try:
            resultdict[key] +=a[key]
        except KeyError:
            resultdict[key] =a[key]

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

Таким образом, после преобразования данных с сайта закупок по словам триггерам сформировалась риск-ориентированная выборка. На анализ отобранных закупок экспертом было потрачено всего несколько часов, чтобы классифицировать их с признаком ограничения конкуренции. Задача выполнена за несколько часов без утомительного просмотра многочисленных технических заданий на сайте ЕИС.