Как мне обрабатывать исключения с помощью генераторов Python, использующих spaCy - PullRequest
1 голос
/ 25 июня 2019

Я использую метод spacy language.pipe для обработки текстов в виде потока и получения объектов Doc по порядку.(https://spacy.io/api/language#pipe).

Этот метод работает быстрее, чем обработка файлов один за другим, и в качестве входных данных используется объект генератора.

Если система обнаруживает «плохой файл», я хочу убедиться, что могуидентифицировать его. Однако я не уверен, как этого добиться с помощью генераторов Python. Каков наилучший подход для обеспечения обнаружения ошибки? У меня в настоящее время нет файла, вызывающего ошибку, но, скорее всего, он будет найден в работе.

Я использую spaCy версии 2.1 и Python 3.6.3

import os
import spacy

nlp = spacy.load('en')

def genenerator():
    path = "C:/Temp/tmp/" #place any text files here for testing

    try:
        for root, _, files in os.walk(path, topdown=False):
            for name in files:
                with open(os.path.join(root, name), 'r', encoding='utf-8', errors='ignore') as inputFileStream:
                    docText = inputFileStream.read()
                yield (docText, name)

    except Exception as e:
        print('Error opening document. Doc name: {}'.format(os.path.join(root, name)), str(e))

def processfiles():
    try:
        for doc, file in nlp.pipe(genenerator(), as_tuples = True, batch_size=1000):
            print (file)

    except Exception as e:
        print('Error processing file: {}'.format(file), str(e))

if __name__ == '__main__':
    processfiles()

Редактировать - я попытался лучше объяснить свою проблему.

Конкретная вещь, которую я должен уметьдля этого нужно точно определить, какой файл вызвал проблему в spaCy, в частности, я хочу точно знать, какой файл завершился ошибкой во время этого оператора для doc, файл в nlp.pipe (genenerator (), as_tuples = True, batch_size = 1000):

Я предполагаю, что возможно столкнуться с файлом, вызывающим проблему в spaCy во время оператора pipe (например, во время обработки тега или парсера p).ipeline).

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

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

1 Ответ

0 голосов
/ 26 июня 2019

Похоже, ваша основная проблема в том, что ваш оператор try / catch в настоящее время останавливает выполнение при первой обнаруженной ошибке. Чтобы продолжить выдавать файлы при возникновении ошибки, вам нужно поместить ваш try/catch дальше в цикл for, то есть вы можете обернуть менеджер контекста with open.

Обратите также внимание, что в Python одеяло try/catch считается анти-шаблоном, поэтому обычно вам нужно явно отлавливать и обрабатывать ошибки вместо использования общего назначения Exception. Я включил более явные IOerror и OSError в качестве примеров.

Наконец, поскольку вы можете отлавливать ошибки в самом генераторе, функция nlp.pipe больше не нуждается в параметре as_tuple.

from pathlib import Path
import spacy


def grab_files(path):
    for path in Path(path).rglob('*'):
        if path.is_file():
            try:
                with open(str(path), 'r', encoding='utf-8', errors='ignore') as f:
                    yield f.read()
            except (OSError, IOError) as err:
                print(f'ERROR: {path}', err)


nlp = spacy.load('en')
for doc in nlp.pipe(grab_files('C:/Temp/tmp/'), batch_size=1000):
    print(doc)  # ... do something with spacy Doc here

* Редактировать - чтобы ответить на дополнительный вопрос.

Обратите внимание, что вы по-прежнему читаете содержимое текстовых документов по одному, как если бы вы работали без генератора, однако выполнение этого с помощью генератора возвращает объект, который задерживает выполнение до тех пор, пока вы не передадите его в nlp.pipe метод. Затем SpaCy обрабатывает одну партию текстовых документов одновременно с помощью своей внутренней функции util.minibatch. Эта функция оканчивается на yield list(batch), который выполняет код, который открывает / закрывает файлы (по 1000 в вашем случае). Что касается любых ошибок, не связанных с SpaCy, то есть ошибок, связанных с открытием / чтением файла, код, который я разместил, должен работать как есть.

Однако в том виде, в каком он есть, и ваш os.walk, и мой Path(path).rglob без разбора выбирают любой файл в каталоге независимо от его типа. Например, если в вашей папке /tmp есть файл .png, то SpaCy вызовет TypeError во время процесса токенизации. Если вы хотите зафиксировать подобные ошибки, лучше всего их предвидеть и избегать, прежде чем отправлять их в SpaCy, например, внося в свой код белый список, который допускает только определенные расширения файлов (.rglob('*.txt')).

Если вы работаете над проектом, который по тем или иным причинам не может быть прерван из-за ошибки, независимо от стоимости. И если предположить, что вам абсолютно необходимо знать, на какой стадии конвейера произошла ошибка, то одним из подходов может быть создание настраиваемого компонента конвейера для каждого компонента конвейера SpaCy по умолчанию (Tagger, DependencyParser и т. Д.), Который вы собираетесь использовать. Затем вам нужно будет обернуть указанные компоненты в общую логику обработки / регистрации ошибок. Сделав это, вы сможете обработать свои файлы, используя свой полностью настроенный конвейер. Но, если в твоей голове нет пистолета, я бы его не рекомендовал. Намного лучше было бы предвидеть ошибки, которые вы ожидаете, и обрабатывать их внутри вашего генератора. Возможно, у кого-то с лучшим знанием внутренних органов SpaCy будет лучшее предложение.

...