Классификация текста с помощью 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, вложения слов и т. Д.)

Попытки

Я попытался повысить производительность с помощью следующих процедур:

  1. Различные предварительные обработки / лемматизации текстов: лучший вариант, кажется, удаляет все знаки препинания, числа, стоп-слова, из словарного запаса, а затем лемматизирует все оставшиеся слова
  2. Испытанные архитектуры textcat: ансамбль, лук (также с ngram_size а также attrпараметры): лучшим, по-видимому, является ансамбль, согласно документации по spaCy.
  3. Пытался включить информацию о субреддите: я сделал это, обучив отдельный текстовый кот на тех же 4000 авторов. subreddit столбец (см. пункт 5., чтобы узнать, как используется информация, полученная на этом этапе).
  4. Пытался включить информацию о вложениях слов: с использованием векторов документов из en_core_web_lg-2.2.5 Модель spaCy, я обучил на тех же 4000 агрегированных публикациях авторов многослойный перцептрон scikit (см. пункт 5., чтобы узнать, как используется информация, полученная на этом этапе).
  5. Затем, чтобы смешать информацию, поступающую из субреддитов, публикаций и векторов документов, я обучил логистической регрессии на 1000 прогнозов трех моделей (я также пытался сбалансировать классы на этом последнем шаге с помощью adasyn

Используя эту логистическую регрессию, я получаю ROC = 0,89 для тестового набора данных. Если я удалю любой из этих шагов и использую промежуточную модель, ROC снизится.

Я также пробовал следующие шаги, которые снова просто снизили ROC:

  1. Используйте предварительно обученные модели, такие как bert. Код, который я использовал, аналогичен этому
  2. Пытался сбалансировать занятия с самого начала, используя меньшую обучающую выборку.
  3. Пытался оставить знаки препинания и поставить 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

  • В: Вы пробовали не объединять?
    Если я не объединяю, производительность (только для несвязанных текстов, так что снова нет векторов / субреддитов) аналогична случаю, в котором я объединяю, но я бы тогда не знал, как объединить несколько прогнозов для одного и того же автора в один предсказание. Потому что помните, что у меня есть больше комментариев от каждого автора, и я должен предсказать бинарную особенность в отношении авторов.

Вопросы

  1. Есть ли у вас какие-либо предложения по поводу кода spaCy, который я использую (например, какой-либо другой способ использования сабреддитов и / или информации о векторах документов)?
  2. Как я могу улучшить общую модель?

Любое предложение высоко ценится.
Пожалуйста, будьте как можно более точными в плане кода / объяснений / ссылок, поскольку я новичок в НЛП.

0 ответов

Другие вопросы по тегам