Классификация текста с помощью Spacy: выход за пределы основ для повышения производительности - PullRequest
3 голосов
/ 24 марта 2020

Я пытаюсь обучить текстовый классификатор на наборе учебных текстов (сообщения 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_au c Гол). А вот код 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))

Проблема

Я получаю низкую производительность (измеряется RO C в тестовом наборе данных, на котором у меня нет меток), также по сравнению с более простыми алгоритмами, которые можно написать с помощью scikit learn (например, tfidf, bow, embeddings word) et c)

Попытки

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

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

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

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

  1. Используйте предварительно обученные модели, такие как Bert. Код I используется аналогично этому
  2. Пытался сбалансировать классы с самого начала, используя меньший тренировочный набор.
  3. Пытался оставить пунктуацию и поставить sentencizer в начало nlp конвейера

Дополнительная информация (в основном из комментариев)

  • Q: Что такое RO ​​C базовой линии такие модели, как Multinomial Naive Bayes или SVM?
    У меня есть легкий доступ к РПЦ, оцениваемым только по текстам (без субреддитов или векторов). 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)
    даст ro c (с использованием Bow CountVectorizer) = 0,53 (то же самое с ядром rbf, но rbf + class_weight = None или «сбалансированный» дает 0,63 (то же самое без ограничение на cache_size)). Во всяком случае, XGBregressor с параметрами, установленными с gridsearch, даст ro c = 0,88. Тот же XGB, но также с подсчетами CountVectorizer и векторами scikit Doc2Ve c (в сочетании с lr, как указано выше) дает около 93. Код ансамбля, который вы видите выше, только для текстов, дает около 83. С subreddts и векторами (обработанными как выше) дает 89

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

Вопросы

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

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

...