Классификация текста с помощью Spacy: выход за рамки основ для повышения производительности
Я пытаюсь обучить классификатор текста на обучающем наборе текстов (сообщения Reddit) с двумя эксклюзивными классами (1 и 0) в отношении особенности авторов сообщений, а не самих сообщений.
Классы несбалансированы: примерно 75:25, что означает, что 75% авторов - "0", а 25% - "1".
Весь набор данных состоит из 3 столбцов: первый представляет автора сообщения, второй - сабреддит, которому принадлежит сообщение, а третий - фактическое сообщение.
Данные
Набор данных выглядит так:
In [1]: train_data_full.head(5)
Out[1]:
author subreddit body
0 author1 subreddit1 post1_1
1 author2 subreddit2 post2_1
2 author3 subreddit2 post3_1
3 author2 subreddit3 post2_2
4 author5 subreddit4 post5_1
Где postI_J- J-й пост I-го автора. Обратите внимание, что в этом наборе данных один и тот же автор может появиться более одного раза, если он / она опубликовали более одного раза.
В отдельном наборе данных у меня есть класс, к которому принадлежит каждый автор.
Первым делом я сгруппировал по авторам:
def proc_subs(l):
s = set(l)
return " ".join([st.lower() for st in s])
train_data_full_agg = train_data_full.groupby(["author"], as_index = False).agg({'subreddit': proc_subs, "body": " ".join})
train_data_full_agg.head(5)
Out[2]:
author subreddit body
author1 subreddit1 subreddit2 post1_1 post1_2
author2 subreddit3 subreddit2 subreddit3 post2_1 post2_2 post2_3
author3 subreddit1 subreddit5 post3_1 post3_2
author4 subreddit7 post4_1
author5 subreddit1 subreddit2 post5_1 post5_2
Всего 5000 авторов, 4000 используются для обучения и 1000 для проверки (оценка roc_auc). А вот код spaCy, который я использую (train_texts
это подмножество train_data_full_agg.body.tolist()
Использую для тренировок, пока test_texts
тот, который я использую для проверки).
# Before this line of code there are others (imports and data loading mostly) which i think are irrelevant
train_data = list(zip(train_texts, train_labels))
nlp = spacy.blank("en")
if 'textcat' not in nlp.pipe_names:
textcat = nlp.create_pipe("textcat", config={"exclusive_classes": True, "architecture": "ensemble"})
nlp.add_pipe(textcat, last = True)
else:
textcat = nlp.get_pipe('textcat')
textcat.add_label("1")
textcat.add_label("0")
def evaluate_roc(nlp,textcat):
docs = [nlp.tokenizer(tex) for tex in test_texts]
scores , a = textcat.predict(docs)
y_pred = [b[0] for b in scores]
roc = roc_auc_score(test_labels, y_pred)
return roc
dec = decaying(0.6 , 0.2, 1e-4)
pipe_exceptions = ['textcat']
other_pipes = [pipe for pipe in nlp.pipe_names if pipe not in pipe_exceptions]
with nlp.disable_pipes(*other_pipes):
optimizer = nlp.begin_training()
for epoch in range(10):
random.shuffle(train_data)
batches = minibatch(train_data, size = compounding(4., 32., 1.001) )
for batch in batches:
texts1, labels = zip(*batch)
nlp.update(texts1, labels, sgd=optimizer, losses=losses, drop = next(dec))
with textcat.model.use_params(optimizer.averages):
rocs.append(evaluate_roc(nlp, textcat))
Проблема
У меня низкая производительность (измеренная с помощью ROC на тестовом наборе данных, на котором у меня нет меток), также по сравнению с более простыми алгоритмами, которые можно было бы написать с помощью scikit learn (например, tfidf, bow, вложения слов и т. Д.)
Попытки
Я попытался повысить производительность с помощью следующих процедур:
- Различные предварительные обработки / лемматизации текстов: лучший вариант, кажется, удаляет все знаки препинания, числа, стоп-слова, из словарного запаса, а затем лемматизирует все оставшиеся слова
- Испытанные архитектуры textcat: ансамбль, лук (также с
ngram_size
а такжеattr
параметры): лучшим, по-видимому, является ансамбль, согласно документации по spaCy. - Пытался включить информацию о субреддите: я сделал это, обучив отдельный текстовый кот на тех же 4000 авторов.
subreddit
столбец (см. пункт 5., чтобы узнать, как используется информация, полученная на этом этапе). - Пытался включить информацию о вложениях слов: с использованием векторов документов из
en_core_web_lg-2.2.5
Модель spaCy, я обучил на тех же 4000 агрегированных публикациях авторов многослойный перцептрон scikit (см. пункт 5., чтобы узнать, как используется информация, полученная на этом этапе). - Затем, чтобы смешать информацию, поступающую из субреддитов, публикаций и векторов документов, я обучил логистической регрессии на 1000 прогнозов трех моделей (я также пытался сбалансировать классы на этом последнем шаге с помощью adasyn
Используя эту логистическую регрессию, я получаю ROC = 0,89 для тестового набора данных. Если я удалю любой из этих шагов и использую промежуточную модель, ROC снизится.
Я также пробовал следующие шаги, которые снова просто снизили ROC:
- Используйте предварительно обученные модели, такие как bert. Код, который я использовал, аналогичен этому
- Пытался сбалансировать занятия с самого начала, используя меньшую обучающую выборку.
- Пытался оставить знаки препинания и поставить
sentencizer
в началеnlp
трубопровод
Дополнительная информация (в основном из комментариев)
В: Каков ROC базовых моделей, таких как полиномиальный наивный байесовский анализ или SVM?
У меня есть легкий доступ к ROC, оцененным только по текстам (без субреддитов или векторов). Svm настроен так:
svm= svm.SVC(C=1.0, kernel='poly', degree=2, gamma='scale', coef0=0.0, shrinking=True, probability=True, tol=0.001, cache_size=200, class_weight=None, max_iter=-1)
Дает roc (с использованием лука CountVectorizer) = 0,53 (то же самое с ядром rbf, но rbf + class_weight = None или "сбалансированный" дает 0,63 (то же самое без ограничения на cache_size)). В любом случае, XGBregressor с параметрами, установленными с помощью gridsearch, даст roc = 0,88. Тот же XGB, но также с субреддитами CountVectorizer и векторами scikit Doc2Vec (в сочетании с lr, как указано выше) дает около 93. Код ансамбля, который вы видите выше, только для текстов даст около 83. С субреддтами и векторами (обработанными, как указано выше) дает 89В: Вы пробовали не объединять?
Если я не объединяю, производительность (только для несвязанных текстов, так что снова нет векторов / субреддитов) аналогична случаю, в котором я объединяю, но я бы тогда не знал, как объединить несколько прогнозов для одного и того же автора в один предсказание. Потому что помните, что у меня есть больше комментариев от каждого автора, и я должен предсказать бинарную особенность в отношении авторов.
Вопросы
- Есть ли у вас какие-либо предложения по поводу кода spaCy, который я использую (например, какой-либо другой способ использования сабреддитов и / или информации о векторах документов)?
- Как я могу улучшить общую модель?
Любое предложение высоко ценится.
Пожалуйста, будьте как можно более точными в плане кода / объяснений / ссылок, поскольку я новичок в НЛП.