如何从spaCy文档中过滤令牌

Kon*_*Pal 4 python nlp spacy

我想使用spaCy解析文档并应用令牌过滤器,以便最终的spaCy文档不包含过滤的令牌。我知道我可以过滤标记的序列,但是我对具有实际Doc结构很感兴趣。

text = u"This document is only an example. " \
    "I would like to create a custom pipeline that will remove specific tokesn from the final document."

doc = nlp(text)

def keep_token(tok):
    # This is only an example rule
    return tok.pos_ not not in {'PUNCT', 'NUM', 'SYM'}

final_tokens = list(filter(keep_token, doc))

# How to get a spacy.Doc from final_tokens?
Run Code Online (Sandbox Code Playgroud)

我试图Doc从令牌列表中重建一个新的spaCy ,但是该API尚不清楚如何实现。

gda*_*ras 8

我很确定您到现在为止都找到了解决方案,但是因为它没有在此处发布,所以我认为添加它可能会很有用。

您可以通过以下方式删除令牌:将doc转换为numpy数组,从numpy数组中删除,然后再转换回doc。

码:

import spacy
from spacy.attrs import LOWER, POS, ENT_TYPE, IS_ALPHA
from spacy.tokens import Doc
import numpy

def remove_tokens_on_match(doc):
    indexes = []
    for index, token in enumerate(doc):
        if (token.pos_  in ('PUNCT', 'NUM', 'SYM')):
            indexes.append(index)
    np_array = doc.to_array([LOWER, POS, ENT_TYPE, IS_ALPHA])
    np_array = numpy.delete(np_array, indexes, axis = 0)
    doc2 = Doc(doc.vocab, words=[t.text for i, t in enumerate(doc) if i not in indexes])
    doc2.from_array([LOWER, POS, ENT_TYPE, IS_ALPHA], np_array)
    return doc2

# load english model
nlp  = spacy.load('en')
doc = nlp(u'This document is only an example. \
I would like to create a custom pipeline that will remove specific tokens from \
the final document.')
print(remove_tokens_on_match(doc))
Run Code Online (Sandbox Code Playgroud)

您可以看一下我在这里回答的类似问题。

  • 这种方法是否违背了使用 numpy 数组的目的?也就是说,如果您有大量文本,则循环遍历文档中的所有标记来检查其标签,然后转换为 numpy 数组,然后转换为文档,在计算上效率很低。直接在列表理解中过滤标签不是更快吗?我正在寻找一种方法来一次性过滤掉文档中的标记,而不必循环遍历标记,这就是我希望 numpy 技巧能够做到的。但是,您的代码仍然会迭代文档中的每个标记,从而导致计算速度变慢。有任何想法吗? (2认同)

pol*_*m23 2

根据您想要做什么,有几种方法。

1. 获取原始文件

SpaCy 中的令牌具有对其文档的引用,因此您可以执行以下操作:

original_doc = final_tokens[0].doc
Run Code Online (Sandbox Code Playgroud)

这样你仍然可以从原始句子中获取 PoS、解析数据等。

2. 构建一个没有删除标记的新文档

您可以将所有标记的字符串附加到空格并创建一个新文档。有关 的信息,请参阅令牌文档text_with_ws

doc = nlp(''.join(map(lambda x: x.text_with_ws, final_tokens)))
Run Code Online (Sandbox Code Playgroud)

但这可能不会给你你想要的东西 - PoS 标签不一定是相同的,并且生成的句子可能没有意义。

如果这两者都不是您想要的,请告诉我,也许我可以提供帮助。

  • 我知道第二种解决方案,这基本上是我们目前正在做的解决方法。但它有两个问题: 1. PoS 标签可能会按照您准确指出的那样发生变化 2. 您需要重新解析文档,因此性能下降。 (3认同)