spacy — разделение предложений в docs gold

#python #spacy

#python #spacy

Вопрос:

Моя цель — распределить документы, которые уже были помечены и сопоставлены с аннотациями gold.

У меня есть набор данных аннотированных документов в классическом формате spacy

 {
   "text": "This is a sentence, this is another sentence...",
   "entities": [(100, 112, "PERSON"), (150, 154, "LOCATION"),...]
}
 

и я преобразовал его в набор данных с тегами BILUO, где приведенный выше образец будет выглядеть следующим образом

 {
    "text": "This is a sentence, this is another sentence...",
    "spacy_tokens": ["This", "is", "a", "sentence", ",", "this",...],
    "ner_tags": ["O", "O", ..., "B-PERSON", "I-PERSON", "L-PERSON",...]
}
 

используя следующий код

         nlp = spacy.load('de_core_news_sm')
        
        for i, (doc, gold) in enumerate(zip(docs, golds)):
            doc = nlp.make_doc(doc)
            gold = GoldParse(doc, **gold)
            sample = {
                "text": str(doc),
                "tokens": [w for w in doc],
                "ner_tags": [tag for tag in gold.ner]
            }
 

Вопрос

Мой вопрос в том, как я могу теперь (ретроспективно) разделить образцы дальше по предложениям. Т.е. Когда я добавляю a sentencizer в конвейер spacy, я могу разделить doc , но как мне синхронизировать gold.sent_starts с разделением предложений?

Ответ №1:

Предполагая, что вы spacy_tokens синхронизированы с вашим ner_tags *, тогда вам нужно создать документ с точно такой токенизацией и запустить его через sentencizer, чтобы получить token.is_sent_start значения:

 import spacy
from spacy.tokens import Doc

nlp = spacy.blank("en")
nlp.add_pipe(nlp.create_pipe("sentencizer"))

text = "He doesn't like London and Berlin. I do."
words = ["He", "doesn't", "like", "London", "and", "Berlin", ".", "I", "do", "."]
ner = ["O", "O", "O", "U-LOC", "O", "U-LOC", "O", "O", "O", "O"]

words, spaces = spacy.util.get_words_and_spaces(words, text)
doc = Doc(nlp.vocab, words=words, spaces=spaces)
doc = nlp.get_pipe("sentencizer")(doc)
sent_starts = [t.is_sent_start for t in doc]
 

Если вы не создадите документ, предоставив токенизацию gold с Doc(words=) помощью, English токенизация по умолчанию для nlp(text) будет ['He', 'does', "n't", 'like', 'London', 'and', 'Berlin', '.', 'I', 'do', '.'] , и все sent_start (или другие) теги будут не синхронизированы.


* Приведенный выше код подходит только text для смещения символов entities , но если ваш gold включает words , то gold.ner выравнивается с gold.words , но не обязательно с [t.text for t in doc] .