首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >将spaCy ` `Doc`‘转换为CoNLL 2003示例

将spaCy ` `Doc`‘转换为CoNLL 2003示例
EN

Stack Overflow用户
提问于 2022-10-26 18:35:32
回答 3查看 146关注 0票数 1

我计划使用培训Spark自定义NER模型,它使用CoNLL 2003格式(这个博客甚至留下一些训练样本数据来加速后续工作)。这个“示例数据”对我没有用处,因为我有自己的培训数据来训练模型;但是,这个数据包含了一个spaCy 文档对象的列表,老实说,我不知道如何进行这种转换。到目前为止,我发现了三种方法,每一种方法都有相当大的弱点:

  1. 在spacy的文档中,我发现了示例代码关于如何使用项目构建单个Doc到CoNLL,但是注意到它使用了一个空白的spacy模型,因此不清楚“我自己标记的数据”在哪里发挥作用;此外,,似乎conll_formatter组件是“在管道的末尾添加的”,因此似乎“没有真正完成从Doc到CoNLL的直接转换”.我的抓取正确吗?
  2. 在Prodigy论坛(同样是spaCy设计师的另一个产品),我发现了这个目的,然而,"CoNLL“(我想是2003年?)格式似乎不完整: POS标记似乎缺少(可以通过Token.pos_轻松获得),以及“语法块”(其spaCy等效项似乎不存在)。在CoNLL 2003正式文件中提到了这四个字段。
  3. 说到“从Doc到CONLL的直接转换”,我也发现了基于textacy库的实现,但是这个实现似乎被0.11.0版本所反对,因为"CONLL-U .没有强制或保证“,所以我不确定是否使用它(BTW,编写这些行时最最新的textacy实现,是0.12.0)。

我的当前代码如下:

代码语言:javascript
复制
import spacy
from spacy.training import offsets_to_biluo_tags
from spacy.tokens import Span

print("SPACY HELPER MODEL")
base_model = "en_core_web_sm"
nlp = spacy.load(base_model)
to_disable= ['parser', 'lemmatizer', 'ner']
_ = [nlp.remove_pipe(item) for item in to_disable]
print("Base model used: ", base_model)
print("Removed components: ", to_disable)
print("Enabled components: ", nlp.pipe_names)

# Assume text is already available as sentences...
# so no need for spaCy `sentencizer` or similar
print("\nDEMO SPACY DOC LIST BUILDING...", end="")
doc1 = nlp("iPhone X is coming.")
doc1.ents = [Span(doc1, 0, 2, label="GADGET")]
doc2 = nlp("Space X is nice.")
doc2.ents = [Span(doc1, 0, 2, label="BRAND")]
docs = [doc1, doc2]
print("DONE!")

print("\nCoNLL 2003 CONVERSION:\n")
results = []
for doc in docs:
    # Preliminary: whole sentence
    whole_sentence = doc.text
    # 1st item (CoNLL 2003): word
    words = [token.text for token in doc]
    # 2nd item (CoNLL 2003): POS
    pos = [token.tag_ for token in doc]
    # 3rd item (CoNLL 2003): syntactic chunk tag
    sct = ["[UNKNOWN]" for token in doc]
    # 4th item (CoNLL 2003): named entities
    spacy_entities = [
        (ent.start_char, ent.end_char, ent.label_)
        for ent in doc.ents
    ]
    biluo_entities = offsets_to_biluo_tags(doc, spacy_entities)
    results.append((whole_sentence, words, pos, sct, biluo_entities))

for result in results:
    print(
        "\nDOC TEXT (NOT included in CoNLL 2003, just for demo): ",
        result[0], "\n"
    )
    print("-DOCSTART- -X- -X- O")
    for w,x,y,z in zip(result[1], result[2], result[3], result[4]):
        print(w,x,y,z)

# Pending: write to a file, but that's easy, and out of topic.

作为输出:

代码语言:javascript
复制
DOC TEXT (NOT included in CoNLL 2003, just for demo):  iPhone X is coming.

-DOCSTART- -X- -X- O
iPhone NNP [UNKNOWN] B-GADGET
X NNP [UNKNOWN] L-GADGET
is VBZ [UNKNOWN] O
coming VBG [UNKNOWN] O
. . [UNKNOWN] O

DOC TEXT (NOT included in CoNLL 2003, just for demo):  Space X is nice.

-DOCSTART- -X- -X- O
Space NNP [UNKNOWN] B-BRAND
X NNP [UNKNOWN] L-BRAND
is VBZ [UNKNOWN] O
nice JJ [UNKNOWN] O
. . [UNKNOWN] O

你以前做过这样的事吗?

谢谢!

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2022-11-02 18:37:52

在@AlbertoAndreotti的帮助下,我设法找到了一个实用的解决办法:

代码语言:javascript
复制
import spacy
from spacy.training import offsets_to_biluo_tags
from spacy.tokens import Span

print("SPACY HELPER MODEL")
base_model = "en_core_web_sm"
nlp = spacy.load(base_model)
to_disable= ['parser', 'lemmatizer', 'ner']
_ = [nlp.remove_pipe(item) for item in to_disable]
print("Base model used: ", base_model)
print("Removed components: ", to_disable)
print("Enabled components: ", nlp.pipe_names)

# Assume text is already available as sentences...
# so no need for spaCy `sentencizer` or similar
print("\nDEMO SPACY DOC LIST BUILDING...", end="")
doc1 = nlp("iPhone X is coming.")
doc1.ents = [Span(doc1, 0, 2, label="GADGET")]
doc2 = nlp("Space X is nice.")
doc2.ents = [Span(doc1, 0, 2, label="BRAND")]
docs = [doc1, doc2]
print("DONE!")

print("\nCoNLL 2003 CONVERSION:\n")
results = []
for doc in docs:
    # Preliminary: whole sentence
    whole_sentence = doc.text
    # 1st item (CoNLL 2003): word
    words = [token.text for token in doc]
    # 2nd item (CoNLL 2003): POS
    pos = [token.tag_ for token in doc]
    # 3rd item (CoNLL 2003): syntactic chunk tag
    # sct = pos  # Redundant, so will be left out
    # 4th item (CoNLL 2003): named entities
    spacy_entities = [
        (ent.start_char, ent.end_char, ent.label_)
        for ent in doc.ents
    ]
    biluo_entities = offsets_to_biluo_tags(doc, spacy_entities)
    results.append((whole_sentence, words, pos, biluo_entities))

for result in results:
    print(
        "\nDOC TEXT (NOT included in CoNLL 2003, just for demo): ",
        result[0], "\n"
    )
    print("-DOCSTART- -X- -X- O")
    for w,x,y,z in zip(result[1], result[2], result[2], result[3]):
        print(w,x,y,z)

作为补充信息,我发现3缺失项“语法分块标记”与一个更广泛的问题“短语分块”有关,这个问题恰巧是计算机科学中一个尚未解决的问题,对于这个问题,只得到了一些近似,因此无论使用哪个库,将第3项具体转换为CoNLL 2033都可能会出现错误。然而,似乎星火NLP根本不在乎第二和第三项,所以这里建议的解决办法,是可以接受的。

要了解更多细节,您可能需要关注这个线程

票数 0
EN

Stack Overflow用户

发布于 2022-10-27 03:41:28

如果您查看一个示例CoNLL文件,您将看到它们只是分开的条目,在它们之间有一个空行。所以你只需要使用for循环。

代码语言:javascript
复制
for doc in docs:
    for sent in doc.sents:
        print("#", doc) # optional but makes it easier to read
        print(sent._.conll_str)
        print()

CoNLL文件是按句子分割的,而不是spaCy文档,但是如果您没有语句边界,您可以只在文档上循环。似乎还有一个选项可以直接打开组件中的标头,请参阅它们的自述文件。

票数 1
EN

Stack Overflow用户

发布于 2022-11-03 12:57:20

不知道这能不能帮上忙,但我能补充的是,

  • 火花-NLP纳不会使用你的POS标签,所以如果你能用foo-bar值填充它们,那就简化了你的工作。
  • 检查JSL注解实验室产品。它允许你标签数据,它顺利地集成到星火-NLP纳.这是免费的。
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/74212658

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档