首页 > 解决方案 > 在 SpaCy 中创建自定义组件

问题描述

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

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

  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.

标签: python-3.xnlpspacy

解决方案


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

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

有关详细信息,请参阅Doc 文档。

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

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


推荐阅读