Преобразование сгенерированной Spacy зависимости в формат CoNLL не может обрабатывать более одного ROOT?

Я использовал библиотеку SpaCy для генерации зависимостей и сохранения ее в формате CoNLL, используя приведенный ниже код.

import pandas as pd
import spacy

df1 = pd.read_csv('cleantweets', encoding='latin1')
df1['tweet'] = df1['tweet'].astype(str)
tweet_list = df1['tweet'].values.tolist()
nlp = spacy.load("en_core_web_sm")
for i in tweet_list:
    doc = nlp(i)
    for sent in doc.sents:
        print('\n')
        for i, word in enumerate(sent):
            if word.head is word:
                head_idx = 0
            else:
                 head_idx = doc[i].head.i + 1
            print("%d\t%s\t%d\t%s\t%s\t%s" % (
                i+1, 
                word.head,
                head_idx,
                word.text,
                word.dep_,
                word.pos_, 
                ))

Это работает, но в моем наборе данных есть несколько предложений, которые Spacy разбивает на две части, потому что у них два КОРНЯ. В результате получается два поля для одного предложения в формате CoNLL.

Пример: случайное предложение из моего набора данных: "Теанна Трамп, наверное, чище твиттер, но"

в формате CoNLL он сохраняется как:

    1   trump   2   teanna      compound
    2   cleaner 4   trump       nsubj
    3   cleaner 4   probably    advmod
    4   cleaner 4   cleaner     ROOT
    5   hoe     6   twitter     amod
    6   cleaner 4   hoe         dobj


    1   but 2   but ROOT

Есть ли способ сохранить все это в одном поле вместо двух, даже если у него две КОРНИ, так что "но" становится 7-м элементом в поле номер 1? Это означает, что вместо этого это будет выглядеть так

    1   trump   2   teanna      compound
    2   cleaner 4   trump       nsubj
    3   cleaner 4   probably    advmod
    4   cleaner 4   cleaner     ROOT
    5   hoe     6   twitter     amod
    6   cleaner 4   hoe         dobj
    7   but     2   but         ROOT

1 ответ

Решение

Я бы рекомендовал использовать (или адаптировать) текстовый экспортер CoNLL, чтобы получить правильный формат, см.: Как сгенерировать.conllu из объекта Doc?

Парсер Spacy выполняет сегментацию предложений, и вы повторяете doc.sents, поэтому вы увидите каждое экспортированное предложение отдельно. Если вы хотите обеспечить собственную сегментацию предложения, вы можете сделать это с помощью специального компонента, например:

def set_custom_boundaries(doc):
    for token in doc[:-1]:
        if token.text == "...":
            doc[token.i+1].is_sent_start = True
    return doc

nlp.add_pipe(set_custom_boundaries, before="parser")

Подробности (особенно о том, как обращаться с None vs. False vs. True): https://spacy.io/usage/linguistic-features

Модели Spacy по умолчанию не обучаются тексту, подобному твиттеру, поэтому синтаксический анализатор, вероятно, не будет хорошо работать с границами предложений здесь.

(Пожалуйста, задавайте несвязанные вопросы как отдельные вопросы, а также просмотрите документы spacy: https://spacy.io/usage/linguistic-features)

Другие вопросы по тегам