Как создать набор обучающих данных с нуля для пользовательской модели тегов standfordNLP/Stanza NER с несколькими классами в формате BIOES/BILOU?

Я использую NLP для специального приложения и хочу обучить свою собственную модель тегов NER в StanfordNLP, в настоящее время известном как Stanza.

Модель по умолчанию ограничена очень общими тегами, такими как LOC, PER, MISC, COUNTRY, TIME и т. Д.

Мои пользовательские теги более конкретны, например. Еда, Спорт, Программное обеспечение, Бренд. Как я могу узнать о форматировании данных, которые я удалил из Интернета или из файлов PDF в формате BIOES/BILOU?https://en.wikipedia.org/wiki/Inside%E2%80%93outside%E2%80%93beginning_(tagging)

Обязательно ли мне помечать их вручную? или напишите сценарий для генерации данных в формате, показанном ниже:

Alex S-PER
is O
playing O
basketball I-SPORT
with O
Marty B-PER
. O
Rick E-PER
likes O
to O
eat O
Pizza I-FOOD
in O
Los B-LOC
Angeles E-LOC

Если да, то какие инструменты и библиотеки я могу использовать в Python?

Заранее спасибо.

1 ответ

Вы можете написать фрагмент кода для выполнения этой задачи.

Вот решение, которое я сделал.

from flashtext import KeywordProcessor
import stanza
nlp = stanza.Pipeline(lang='en', processors='tokenize,ner,pos')


# Tag tokens with standard NLP BIO tags
def bio_tagger(entity, start_char, end_char, tag):
    bio_tagged = {"tag":None, "end_char":None, "start_char":None}
    ne_tagged = entity.split()
    if len(ne_tagged) == 1:
        bio_tagged["start_char"] = start_char
        bio_tagged["end_char"] = start_char + len(ne_tagged[0])
        bio_tagged["tag"] = "B-"+tag
    elif len(ne_tagged) == 2:
        bio_tagged["start_char"] = start_char
        bio_tagged["end_char"] = start_char + len(ne_tagged[0])
        bio_tagged["tag"] = "B-"+tag

        bio_tagged["start_char"] = end_char - len(ne_tagged[-1])
        bio_tagged["end_char"] = end_char 
        bio_tagged["tag"] = "E-"+tag
    elif len(ne_tagged) >= 3:
        bio_tagged["start_char"] = start_char
        bio_tagged["end_char"] = start_char + len(ne_tagged[0])
        bio_tagged["tag"] = "B-"+tag

        bio_tagged["start_char"] = end_char - len(ne_tagged[-1])
        bio_tagged["end_char"] = end_char 
        bio_tagged["tag"] = "E-"+tag

        cursor = start_char + len(ne_tagged[0]) + 2
        for tok in ne_tagged[1:-1]:
            bio_tagged["start_char"] = cursor
            bio_tagged["end_char"] = cursor + len(tok) 
            bio_tagged["tag"] = "I-"+tag
            cursor = cursor + len(tok)  + 2
    return bio_tagged


def bio_corpus_builder(text, tags2dict):
    #tags2dict {'SPORT':['football','basektball'],
    #           'FOOD':['banana','orange']}
    corpus = []
    document = []

    for tag, tag_values in tags2dict.items():
        keyword_processor = KeywordProcessor()
        keyword_processor.add_keywords_from_list(tag_values)

        for sent in get_sentences(text):
            word_tag_tagger = []
            each_token = {"text": None, "upos":None, "xpos":None,"tag":None, "end_char":None, "start_char":None}
            entities_found = keyword_processor.extract_keywords(sent, span_info=True)
            if entities_found:
                # construct custom tag
                for word_tag in entities_found:
                    word_tag_tagger.append(bio_tagger(word_tag[0], word_tag[1], word_tag[2], tag))
                # read original tag  
                doc = nlp(sent)
                sentence = doc.sentences[0]
                print(word_tag_tagger)
                each_sent = []
                for token in sentence.tokens:
                    each_token["text"] = token.text
                    each_token["tag"] = token.ner
                    each_token["end_char"] = token.end_char
                    each_token["start_char"] = token.start_char
                    each_token["upos"] = token.to_dict()[0]["upos"]
                    each_token["xpos"] = token.to_dict()[0]["xpos"]

                    each_sent.append(dict(each_token))

                #update tagging
                for tok in each_sent:
                    for word2tags in word_tag_tagger:
                        if (int(tok["start_char"]) == int(word2tags["start_char"])) and (int(tok["end_char"]) == int(word2tags["end_char"])):
                            tok["tag"] = word2tags['tag']


                document.append(each_sent)
        del keyword_processor
    return document


# if "__name__"=="__main__":
tags2dict ={'SPORT':['football','basektball'],'FOOD':['banana','orange']}
text = "Barack Obama was born in Hawaii. He love basektball."

bio_corpus_builder(text, tags2dict)

#output
# [[{'text': 'He',
#    'upos': 'PRON',
#    'xpos': 'PRP',
#    'tag': 'O',
#    'end_char': 2,
#    'start_char': 0},
#   {'text': 'love',
#    'upos': 'VERB',
#    'xpos': 'VBP',
#    'tag': 'O',
#    'end_char': 7,
#    'start_char': 3},
#   {'text': 'basektball',
#    'upos': 'NOUN',
#    'xpos': 'NN',
#    'tag': 'B-SPORT',
#    'end_char': 18,
#    'start_char': 8},
#   {'text': '.',
#    'upos': 'PUNCT',
#    'xpos': '.',
#    'tag': 'O',
#    'end_char': 19,
#    'start_char': 18}]]
Другие вопросы по тегам