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

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

Модель по умолчанию ограничена очень общими тегами, такими как LO C, PER, MIS C, СТРАНА, ВРЕМЯ и т. Д. c.

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

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

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 Ответ

0 голосов
/ 30 апреля 2020

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

Вот решение, которое я принял.

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}]]
...