Share This
Связаться со мной
Крути в низ
Categories
//🤖 Практическое руководство по NLP: изучаем классификацию текстов с помощью библиотеки fastText

🤖 Практическое руководство по NLP: изучаем классификацию текстов с помощью библиотеки fastText

Рассматриваем практическое применение supervised NLP модели fastText для обнаружения сарказма в новостных заголовках.

prakticheskoe rukovodstvo po nlp izuchaem klassifikaciju tekstov s pomoshhju biblioteki fasttext 3b442b5 - 🤖 Практическое руководство по NLP: изучаем классификацию текстов с помощью библиотеки fastText

Около 80% всей информации не структурировано, а текст является одним из наиболее распространенных типов неструктурированных данных. Из-за ее беспорядочной природы, анализ, понимание, организация и сортировка текстовой информации становятся сложными и трудоемкими задачами. Здесь на помощь приходят NLP и классификация текста.

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

Используя модели классификаторов, компании могут автоматически структурировать все виды текста, начиная с электронных писем, юридических документов, постов в социальных сетях, сообщений в чат-ботах, результатов опросов и т. д. Это позволяет экономить затраченное на анализ информации время, автоматизировать бизнес-процессы и принимать основанные на данных бизнес-решения.

fastText – популярная библиотека с открытым исходным кодом для классификации текстов, которая была опубликована в 2015 году исследовательской лабораторией искусственного интеллекта Facebook. Компания также предоставляет модели: English word vectors (предварительно обучена английскому webcrawl и Википедии) и Multi-lingual word vectors (обученные модели для 157 различных языков), которые позволяют создать алгоритмы Supervised и Unsupervised learning для получения векторных представлений слов. Библиотеку можно использовать как инструмент командной строки или как пакет Python. В этой статье мы рассмотрим ее применение для классификации новостных заголовков.

Подготовка среды и данных

Загружаем необходимые библиотеки

         import pandas as pd import fasttext from sklearn.model_selection import train_test_split import re from gensim.parsing.preprocessing import STOPWORDS from gensim.parsing.preprocessing import remove_stopwords  pd.options.display.max_colwidth = 1000     

TIP для ознакомления с документацией библиотеки:

         help(fasttext.FastText)     

Данные

Датасет представляет собой коллекцию заголовков новостных статей и их аннотацию как сарказм (статьи из новостного издания The Onion) и не сарказм (из HuffPost). Ссылка на данные: https://www.kaggle.com/rmisra/news-headlines-dataset-for-sarcasm-detection

Переменные

  • is_sarcastic: 1 если заголовок с сарказмом, в противном случае 0
  • headline: заголовок новостной статьи
  • article_link: ссылка на оригинальную статью
         # Загружаем данные df_headline = pd.read_json("Sarcasm_Headlines_Dataset.json", lines=True) # Проверяем количество переменных и наблюдений df_headline.shape (26709, 3) # Отобразим примеры заголовков df_headline.head(3)     
article_link headline is_sarcastic
https://www.huffingtonpost.com/entry/versace-black-code_us_5861fbefe4b0de3a08f600d5 former versace store clerk sues over secret ‘black code’ for minority shoppers 0
https://www.huffingtonpost.com/entry/roseanne-revival-review_us_5ab3a497e4b054d118e04365the the ‘roseanne’ revival catches up to our thorny political mood, for better and worse 0
https://local.theonion.com/mom-starting-to-fear-son-s-web-series-closest-thing-she-1819576697 mom starting to fear son’s web series closest thing she will have to grandchild 1
         # Отобразим количество саркастических и несаркастических статей в датасете и их процентное соотношение df_headline.is_sarcastic.value_counts() 0    14985 1    11724 df_headline.is_sarcastic.value_counts(normalize=True) 0    0.561047 1    0.438953     

Приведем несколько примеров саркастических и не саркастических заголовков:

         df_headline[df_headline['is_sarcastic']==1].head(3)      
article_link headline is_sarcastic
https://local.theonion.com/mom-starting-to-fear-son-s-web-series-closest-thing-she-1819576697 mom starting to fear son’s web series closest thing she will have to grandchild 1
https://politics.theonion.com/boehner-just-wants-wife-to-listen-not-come-up-with-alt-1819574302 boehner just wants wife to listen, not come up with alternative debt-reduction ideas 1
https://politics.theonion.com/top-snake-handler-leaves-sinking-huckabee-campaign-1819578231 top snake handler leaves sinking huckabee campaign 1
         df_headline[df_headline['is_sarcastic']==0].head(3)     
article_link headline is_sarcastic
https://www.huffingtonpost.com/entry/versace-black-code_us_5861fbefe4b0de3a08f600d5 former versace store clerk sues over secret ‘black code’ for minority shoppers 0
https://www.huffingtonpost.com/entry/roseanne-revival-review_us_5ab3a497e4b054d118e04365 the ‘roseanne’ revival catches up to our thorny political mood, for better and worse0 0
https://www.huffingtonpost.com/entry/jk-rowling-wishes-snape-happy-birthday_us_569117c4e4b0cad15e64fdcb j.k. rowling wishes snape happy birthday in the most magical way 0

Подготовка данных

Предварительная обработка текста

Один из первых шагов для повышения производительности модели – применение простой предварительной обработки текста. Прежде чем приступить к построению классификатора, нам необходимо подготовить текст: привести все слова к нижнему регистру, удалить пунктуацию, специальные знаки и цифры. Для этого создадим функцию очистки и применим ее к переменной headline.

         # Создадим функцию очистки текста def clean_text(text):     text = text.lower()     text = re.sub(r'[^sa-zA-Z0-9@[]]',' ',text) # Удаляет пунктцацию     text = re.sub(r'w*d+w*', '', text) # Удаляет цифры     text = re.sub('s{2,}', " ", text) # Удаляет ненужные пробелы     return text  # Применяем ее к заголовку df_headline['headline'] = df_headline['headline'].apply(clean_text)     

Разделение данных на обучающие и тестовые

Прежде чем мы начнем обучение модели, нужно разделить данные так. Чаще всего для обучения модели используется 80% информации (в зависимости от объема данных размер выборки может варьироваться) и 20% – для тестирования (проверки точности).

         # Разделяем данные на обучающие и текстовые train, test = train_test_split(df_headline, test_size = 0.2)      

Создание текстового файла

Далее нам нужно подготовить файлы в формате txt. Формат файла по умолчанию должен включать __label__ <Label> <Text>. Мы можем использовать другой префикс вместо __label__, соответствующим образом изменив параметр во время обучения. В нашем датасете __ label __0 подразумевает отсутствие сарказма, а __label __1 подразумевает сарказм.

         # Создадим текстовые файля для обучения модели с лейблом и текстом with open('train.txt', 'w') as f:     for each_text, each_label in zip(train['headline'], train['is_sarcastic']):         f.writelines(f'__label__{each_label} {each_text}n')          with open('test.txt', 'w') as f:     for each_text, each_label in zip(test['headline'], test['is_sarcastic']):         f.writelines(f'__label__{each_label} {each_text}n')  # Отобразим, как теперь выглядят наши данные для обучения !head -n 10 train.txt  __label__0 singapore airlines flight catches fire no casualties __label__1 area man wins conversation __label__0 stephen colbert explains the conspiracies against donald trump in nsfw diagram __label__1 turkey sandwich given locally relevant name __label__1 quiet riot speaks out against nation s poor metal health care     

Построение модели

Для обучения модели необходимо задать fastText входной файл и ее имя:

         # Первая модель без оптимизации гиперпараметров model1 = fasttext.train_supervised('train.txt')  # Создадим функцую для отображения результатов обучения модели def print_results(sample_size, precision, recall):     precision   = round(precision, 2)     recall      = round(recall, 2)     print(f'{sample_size=}')     print(f'{precision=}')     print(f'{recall=}')  # Применяем функцию print_results(*model1.test('test.txt'))  sample_size=5342 precision=0.85 recall=0.85     

Результаты, хотя и не идеальные, выглядят многообещающими.

Оптимизация гиперпараметров

Поиск наилучших гиперпараметров вручную может занять много времени. По умолчанию модель fastText во время обучения включает каждый обучающий пример только пять раз, что довольно мало, учитывая, что в нашем наборе всего 12 тыс. примеров. Количество просмотров каждого примера (также известное как количество эпох) может быть увеличено с помощью ручной оптимизации epoch:

         # Вторая модель с количеством эпох равной 25 model2 = fasttext.train_supervised('train.txt', epoch=25)  print_results(*model2.test('test.txt'))  sample_size=5342 precision=0.83 recall=0.83      

Как можно заметить, точность модели не возрасла. Еще один способ изменить скорость процесса – увеличить (или уменьшить) скорость обучения алгоритма. Это соответствует тому, насколько сильно меняется модель после обработки каждого примера. Скорость обучения равная 0 будет означать, что модель вообще не меняется и, следовательно, ничему не учится. Хорошие значения скорости обучения находятся в диапазоне 0.1 – 1.0. Мы также можем вручную оптимизировать этот гиперпараметр с помощью аргумента lr:

         # Третья модель с количеством эпох равной 10 и скоростью обучния равной 1 model3 = fasttext.train_supervised('train.txt', epoch=10, lr=1.0)  print_results(*model3.test('test.txt'))  sample_size=5342 precision=0.83 recall=0.83     

Наконец, мы можем улучшить производительность модели, используя биграммы слов, а не просто юниграммы. Это особенно значимо для задач классификации, где важен порядок слов, например, анализ сентиментов, определение критики, сарказма и т. д. Для этого мы включим в модель аргумент wordNgrams равный 2.

         model4 = fasttext.train_supervised('train.txt', epoch=10, lr=1.0, wordNgrams =2)  print_results(*model4.test('test.txt'))  sample_size=5342 precision=0.86 recall=0.86      

Благодаря этой последовательности шагов мы смогли перейти от точности в 86%:

  • предварительная обработка текста;
  • изменение количества эпох (с использованием аргумента epoch, стандартный диапазон [5 – 50]) ;
  • изменение скорости обучения (с использованием аргумента lr, стандартный диапазон [0,1 – 1,0]) ;
  • используя n-граммы слов (используя аргумента wordNgrams, стандартный диапазон [1-5]).

Вы также можете адаптировать поиск гиперпараментров через оценку определенного лейбла, добавив аргумент autotuneMetric:

         model5 = fasttext.train_supervised('train.txt', autotuneValidationFile='test.txt')  print_results(*model5.test('test.txt'))  sample_size=5342 precision=0.87 recall=0.87     

Функция автоматической настройки fastText позволяет оптимизировать гиперпараметры для получения наивысшего показателя F1. Для этого необходимо включить модель аргумент autotuneValidationFile и тестовый датасет:

          model6 = fasttext.train_supervised('train.txt', autotuneValidationFile='test.txt', autotuneMetric="f1:__label__1")  print_results(*model6.test('test.txt'))  sample_size=5342 precision=0.87 recall=0.87     

Сохраним результаты модели и создадим функцию для классификации новых данных:

         # Сохраним модель с оптимизированными гиперпараметрами и самой высокой точностью  model6.save_model('optimized.model')      

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

         model.quantize(input='train.txt', retrain=True)     

Результаты

Мы можем проверить результаты на новых данных, введя любое предложение:

         # Загружаем, сохраненную ранее модель model = fasttext.load_model("optimized.model")  # Пример классификации одного заголовка model.predict("Fed official says weak data caused by weather, should not slow taper")  (('__label__0',), array([0.99874038]))     

Метка результата с максимальной вероятностью равна __label__0. Это означает, что заголовок не является саркастическим. В model.predict() значение k обозначает количество лейблов, которые вы хотите показать вместе с их показателями вероятности. Поскольку мы использовали активацию softmax (по умолчанию в fastText), сумма вероятностей двух меток равна 1.

Мы также можем симулировать новые данные и проверить модели на реальных заголовках. Для этого будет использовать News Aggregator Dataset из Kaggle:

         # Загружаем данные df_headline_test = pd.read_csv('uci-news-aggregator.csv') # Отобразим заголовки  df_headline_test.TITLE.head(3)  0     Fed official says weak data caused by weather, should not slow taper 1       Fed's Charles Plosser sees high bar for change in pace of tapering 2    US open: Stocks fall after Fed official hints at accelerated tapering 3               Fed risks falling 'behind the curve', Charles Plosser says 4                       Fed's Plosser: Nasty Weather Has Curbed Job Growth     

Применим функцию классификацию текста к новым заголовкам и создадим переменные с прогнозируемым лейблом и его вероятностью:

         # Подготовим новые данные для классификации df_headline_test['TITLE'] = df_headline_test['TITLE'].apply(clean_text) # Создадим функцию для классификации текста def predict_sarcasm(text):     return model.predict(text, k=1) # Трансформируем переменные в удобный формат  df_headline_test['predict_score'] = df_headline_test.TITLE.apply(predict_sarcasm) df_headline_test['predict_score'] = df_headline_test['predict_score'].astype(str) df_headline_test[['label','probability']] = df_headline_test.predict_score.str.split(" ",expand=True) df_headline_test['label'] = df_headline_test['label'].str.replace("(", '') df_headline_test['label'] = df_headline_test['label'].str.replace(")", '') df_headline_test['label'] = df_headline_test['label'].str.replace("__", ' ') df_headline_test['label'] = df_headline_test['label'].str.replace(",", '') df_headline_test['label'] = df_headline_test['label'].str.replace("'", '') df_headline_test['label'] = df_headline_test['label'].str.replace("label", '') df_headline_test['probability'] = df_headline_test['probability'].str.replace("array", '') df_headline_test['probability'] = df_headline_test['probability'].str.replace("(", '') df_headline_test['probability'] = df_headline_test['probability'].str.replace(")", '') df_headline_test['probability'] = df_headline_test['probability'].str.replace("[", '') df_headline_test['probability'] = df_headline_test['probability'].str.replace("]", '')  # Удаляем ненужную переменную df_headline_test = df_headline_test.drop(columns=['predict_score'])  # Отобразим количество спрогнозированых саркастических и несаркастических заголовков df_headline_test.label.value_counts(normalize=True)  0    0.710827 1    0.289173     

Мы видим, что 28% заголовков были классифицированы как сарказм.

Заключение

В заключение следует отметить, что fastText не является одной из самых последних разработок классификации текстов (библиотека была опубликована в 2015 году). В то же время это хорошая основа для новичков: при выполнении NLP-классификации текстов любой сложности, модель имеет существенное преимущество из-за простоты ее использования, скорости обучения и автоматической настройки гиперпараметров. Подробнее с документацией fastText можно ознакомится по ссылке.

  • 1 views
  • 0 Comment

Leave a Reply

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.

© Speccy 2020 / All rights reserved

Связаться со мной
Close