Создание пользовательского компонента в SpaCy - PullRequest
1 голос
/ 31 марта 2020

Я пытаюсь создать конвейерный компонент SpaCy, который будет возвращать фрагменты значимого текста (мой корпус содержит документы в формате pdf с большим количеством ненужного мне мусора - таблицы, заголовки и т. Д. c.)

Более конкретно, я пытаюсь создать функцию, которая:

  1. принимает объект doc в качестве аргумента
  2. итерирует по doc tokens
  3. Когда определенные правила соблюдаются, дают Span объект

Примечание Я также был бы рад вернуть list([span_obj1, span_obj2])

Каков наилучший способ сделать что-то подобное? Я немного запутался в разнице между компонентом конвейера и атрибутом расширения.

До сих пор я пробовал:

nlp = English()

Doc.set_extension('chunks', method=iQ_chunker)

####

raw_text = get_test_doc()

doc = nlp(raw_text)

print(type(doc._.chunks))

>>> <class 'functools.partial'>

iQ_chunker - метод, который делает то, что я объясняю выше, и он возвращает список Span объектов

, это не те результаты, которые я ожидаю, так как функция, которую я передаю как метод, возвращает list.

1 Ответ

1 голос
/ 31 марта 2020

Я полагаю, что вы получаете частичку functools, потому что вы обращаетесь к chunks как к атрибуту, несмотря на то, что передали его в качестве аргумента для method. Если вы хотите, чтобы spaCy вмешивался и вызывал метод для вас, когда вы обращаетесь к чему-либо как к атрибуту, он должен быть

Doc.set_extension('chunks', getter=iQ_chunker)

. Для получения более подробной информации см. Документацию Do c .

Однако, если вы планируете вычислить этот атрибут для каждого отдельного документа , я думаю, вы должны вместо этого включить его в свой конвейер. Вот простой пример кода, который делает это обоими способами.

import spacy
from spacy.tokens import Doc

def chunk_getter(doc):
    # the getter is called when we access _.extension_1,
    # so the computation is done at access time
    # also, because this is a getter,
    # we need to return the actual result of the computation
    first_half = doc[0:len(doc)//2]
    secod_half = doc[len(doc)//2:len(doc)]

    return [first_half, secod_half]

def write_chunks(doc):
    # this pipeline component is called as part of the spacy pipeline,
    # so the computation is done at parse time
    # because this is a pipeline component,
    # we need to set our attribute value on the doc (which must be registered)
    # and then return the doc itself
    first_half = doc[0:len(doc)//2]
    secod_half = doc[len(doc)//2:len(doc)]

    doc._.extension_2 = [first_half, secod_half]

    return doc


nlp = spacy.load("en_core_web_sm", disable=["tagger", "parser", "ner"])

Doc.set_extension("extension_1", getter=chunk_getter)
Doc.set_extension("extension_2", default=[])

nlp.add_pipe(write_chunks)

test_doc = nlp('I love spaCy')
print(test_doc._.extension_1)
print(test_doc._.extension_2)

Это просто печатает [I, love spaCy] дважды, потому что это два способа сделать одно и то же, но я думаю, что сделать его частью вашего конвейера с помощью nlp.add_pipe - лучший способ сделать это, если вы ожидаете нужен этот вывод на каждый документ, который вы анализируете.

...