Мой вопрос на самом деле длиннее этого. Однако я разделяю вопрос на две части, поскольку он действительно длинный.
Я пытаюсь создать пользовательское распознавание именованных сущностей (NER) с помощью Spacy для продуктов. Я составил список слов, связанных с едой, и выполнил инструкции в разделе «Простой стиль обучения» на сайте Spacy https://spacy.io/usage/training#ner
Первый вопрос Чтобы создать TRAIN_DATA , то, что я сделал, было прочитано во всем "состоянии объединения" из этого набора данных kaggle https://www.kaggle.com/rtatman/state-of-the-union-corpus-1989-2017; токенизировал их в предложения, а затем просто случайно добавил в ключевые слова в случайное предложение из состояния объединения адреса. Затем я нашел его позицию в тексте и поместил в формат, описанный в документации Spacy. Могу я это сделать?
Вот мой код. Второй вопрос касается тестирования нового NER. Он поднимает первую сущность, но затем останавливается. Это улучшается, когда я предлагаю токенизировать текст, но проблема заключается в моем непонимании алгоритма Spacy. Я хотел бы задать это отдельным вопросом, так как этот вопрос уже слишком длинный:
import random
import pandas as pd
import os
import re
import nltk
from nltk.tokenize import PunktSentenceTokenizer
from random import randrange
import spacy
from spacy.util import minibatch, compounding
import warnings
from nltk.stem import WordNetLemmatizer
lemmatizer = WordNetLemmatizer()
food = pd.DataFrame(data = {"Description":["carrot","garlic", "beef", "pork"]) ## My actual dataset is in an excel file, and is much longer
food = food[["Description"]]
food["Description"] = food["Description"].apply(lambda x: x.lower())
food["Description"] = food["Description"].apply(lambda x: lemmatizer.lemmatize(x))
food.drop_duplicates(subset = ["Description"], inplace=True)
food["Description"] = food["Description"].apply(lambda x: x.strip())
os.chdir(r"C:\Users\Kah\AppData\Roaming\nltk_data\corpora\state_union") ##Where I have saved the state of the union speeches
random_text = ""
for directory, folder,files in os.walk(r"C:\Users\Kah\AppData\Roaming\nltk_data\corpora\state_union"):
for file in files:
if "txt" in file:
with open(file, mode = "r") as text:
data = text.read()
data = re.sub(r'[^\x00-\x7f]',r'', data)
data = re.sub("\n",r" ", data)
random_text = random_text + " " + data.lower()
sent_tokenizer = PunktSentenceTokenizer()
random_sent = sent_tokenizer.tokenize(random_text)
df = pd.DataFrame({"Sent": random_sent})
df["Word"] = df["Sent"].apply(lambda x: nltk.word_tokenize(x))
##Return empty spaces in random text
df["Empty spaces"] = df["Sent"].apply(lambda x: [idx for idx, item in enumerate(x.lower()) if " " in item])
df["str blank"] = df["Empty spaces"].astype(str)
df = df.loc[df["str blank"] != "[]",:].copy(deep=True)
###Steps
##Pick a random sentence in df, pick a random empty space, insert target text (chemical or food), return start and end position
##This yields
#(Sentence, dict("entities":[(beg str, end str, ENTITY_NAME)]})
##Identify the shape of the random text so a computer can randomly pick a sentence
##Use randrange to randomly pick a sentence, add the word randomly in the sentence, then prepare the tag for training
df_shape = df.shape[0]
def tagger(series, df, label):
train = []
for x in series:
try:
randline = randrange(df_shape)-1
rand_sent = df["Sent"][randline]
rand_space = df["Empty spaces"][randline][randrange(len(df["Empty spaces"][randline]))]
rand_sent = f"{rand_sent[:rand_space]} {x}{rand_sent[rand_space:]}"
start_index = rand_sent.find(x)
end_index= start_index + len(x)
word_tag ={"entities":[(start_index, end_index, label)]}
tag = (rand_sent, word_tag)
print(f"{x} completed")
train.append(tag)
except:
pass
return train
food = pd.concat([food]*10)
train_food = tagger(food["Description"], df, "FOOD")