在 SpaCy 中创建自定义组件

Creating custom component in SpaCy

我正在尝试创建 SpaCy 管道组件以 return 有意义的文本跨度(我的语料库包含 pdf 文档,其中有很多我不感兴趣的垃圾 - 表格,headers,等等)

更具体地说,我正在尝试创建一个函数:

  1. 接受一个docobject作为参数
  2. 遍历 doc tokens
  3. 当满足某些规则时,产生 Span object

Note I would also be happy with returning a 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 is a method that does what I explain above and it returns a list of Span objects

这不是我期望的结果,因为我作为方法 returns a list.

传入的函数

我想你会得到一个 functools 部分回来,因为你正在访问 chunks 作为一个属性,尽管已经将它作为参数传递给 method。如果您希望 spaCy 在您访问某些内容作为属性时进行干预并为您调用该方法,则需要

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

请参阅Doc documentation for more details

但是,如果您计划为每个文档计算此属性,我认为您应该将其作为管道的一部分。这是一些简单的示例代码,可以同时执行这两种操作。

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 将其作为管道的一部分是更好的方法您解析的每个文档都需要此输出。