Основы TD-IDF и токенизации с помощью scikit-learn

1. Введение и импорт данных

В этой статье я буду использовать набор данных обзоров фильмов IMDB для этого исследования. Набор данных содержит 50 000 отзывов - 25 000 положительных и 25 000 отрицательных. Пример отзыва можно увидеть на рис. 1, где пользователь поставил оценку 10/10 и письменный отзыв на оскароносный фильм «Паразит» (2020).

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

  • Не менее 7 звезд из 10 = ›положительно (метка = 1)
  • Не более 4 звезд из 10 = ›отрицательный (ярлык = 0)

К счастью для нас, исследователи из Стэнфордского университета проделали «тяжелую работу» по сентиментальной классификации наборов данных обзоров (дополнительную информацию см. В Цитаты и ссылки). Вот фрагмент того, как выглядит набор данных:

Для обучения наша матрица признаков очень разреженная, что означает, что в этой матрице много нулей, так как в ней 25 000 строк и примерно 75 000 столбцов. Итак, что мы собираемся сделать, так это найти вес каждой функции и умножить их на соответствующие значения TD-IDF; суммируем все значения, передаем его через сигмовидную функцию активации, и вот как мы в итоге получаем модель логистической регрессии. Преимущества применения логистической функции в этом случае: модель очень хорошо обрабатывает разреженные матрицы, а веса можно интерпретировать как вероятность настроений.

2. Преобразование документов в векторы признаков

Ниже мы вызовем метод fit_transform в CountVectorizer. Это создаст словарный запас модели «мешок слов» и преобразует приведенный ниже пример предложения в разреженный вектор признаков.

import numpy as np
from sklearn.feature_extraction.text import CountVectorizer
count = CountVectorizer()
docs = ([‘The sun is shining’,
‘The weather is sweet’,
‘The sun is shining, the weather is sweet, and one and one is two’])
bag = count.fit_transform(docs)
print(count.vocabulary_)
print(bag.toarray())

Обратите внимание, как словари теперь хранятся в словаре Python, где каждому уникальному слову сопоставлены уникальные целочисленные индексы. В массиве отображается частота термина для каждого уникального слова.

3. Релевантность слов с использованием термина "частота-обратная частота документа" (TD-IDF)

TD-IDF можно использовать для уменьшения веса часто встречающихся слов в векторах признаков, например, слова «есть» в приведенном выше примере предложения. TD-IDF можно рассчитать как произведение частоты термина на обратную частоту документа. Формула для расчета TD-IDF:

Теперь мы преобразуем необработанные входные данные частоты из предыдущего раздела, чтобы получить наши значения TD-IDF, создав экземпляр метода TdidfTransformer .

from sklearn.feature_extraction.text import TfidfTransformer
np.set_printoptions(precision=2)
tfidf = TfidfTransformer(use_idf=True, norm=’l2', smooth_idf=True)
print(tfidf.fit_transform(bag).toarray())

Как видно из приведенного в примере предложения, слово «есть» наиболее часто встречается в третьем предложении документа. Что вы заметите после преобразования значения в значение TD-IDF, так это то, что вместо завышенного значения 3 теперь оно равно 0,45. Это потому, что слово «is» также содержится в предложениях 1 и 2 в документе; и поэтому вряд ли будет содержать какую-либо полезную или дискриминационную информацию для использования нашей моделью.

Итак, это основная идея значений TD-IDF - они преобразуют текстовые данные в числовые значения, а также взвешивают слова соответствующим образом в соответствии с частотой слова в нашем корпусе текстовых данных.

4. Подготовка данных: предварительная обработка

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

import re
def preprocessor(text):
text =re.sub(‘<[^>]*>’, ‘’, text)
emoticons = re.findall(‘(?::|;|=)(?:-)?(?:\)|\(|D|P)’, text)
text = re.sub(‘[\W]+’, ‘ ‘, text.lower()) + ‘ ‘.join(emoticons).replace(‘-’, ‘’)
return text
preprocessor(“This is a :) test :-( !”)

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

5. Токенизация документов

В этом разделе мы представим наши данные как набор слов или токенов ; мы также будем выполнять задачи предварительной обработки на уровне слов, такие как выделение корней. Для этого мы будем использовать инструментарий естественного языка, или nltk.

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

from nltk.stem.porter import PorterStemmer
porter = PorterStemmer()
def tokenizer(text):
return text.split()
tokenizer('runners like running thus they run')

def tokenizer_stemmer(text):
return[porter.stem(word) for word in text.split()]
tokenizer_stemmer(‘runners like running thus they run’)

6. Преобразование текстовых данных в векторы TD-IDF.

Мы уже выполнили это преобразование TD-IDF в наших предыдущих примерах документов, но теперь мы заполняем fit_transform наш набор данных обзора фильма значениями TD-IDF. Однако вместо того, чтобы разбивать процесс на несколько этапов - разбиение документов на частоту терминов, а затем преобразование их в значения TD-IDF - мы реализуем метод TfidfVectorizer , который выполняет все вышеперечисленные шаги в один-единственный шаг.

from sklearn.feature_extraction.text import TfidfVectorizer
tfidf = TfidfVectorizer(strip_accents=None,
lowercase=True,
preprocessor=preprocessor, # defined preprocessor in Data Cleaning
tokenizer=tokenizer_stemmer,
use_idf=True,
norm=’l2',
smooth_idf=True)
y = df.sentiment.values
X = tfidf.fit_transform(df.review)

7. Классификация документов с использованием логистической регрессии

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

Обратите внимание, что вместо того, чтобы вручную настраивать гиперпараметры нашей модели, мы используем LogisticRegressionCV, чтобы указать количество сверток перекрестной проверки, которые мы хотим сделать для настройки гиперпараметра, то есть пятикратной перекрестной проверки.

from sklearn.model_selection import train_test_split
import pickle
from sklearn.linear_model import LogisticRegressionCV
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=1, test_size=0.5, shuffle=False)
clf = LogisticRegressionCV(cv=5,
scoring=’accuracy’,
random_state=0,
n_jobs=-1,
verbose=3,
max_iter=300).fit(X_train, y_train)

8. Оценка модели

Наконец, мы передадим наши тестовые данные - данные, которые наша модель не видела раньше, - чтобы сделать вывод о том, насколько хороша наша модель.

89,6% - это неплохо, учитывая, что мы используем относительно простую модель для нашего исследования!

Другой способ проверить точность нашего классификатора - использовать матрицу неточностей.

Обратите внимание на первый ряд. Первая строка предназначена для отзывов, фактическое значение тональности которых в тестовом наборе равно 1. Как вы можете подсчитать, из 25 000 отзывов значение тональности 12 473 из них равно 1; и из этих 12 473 классификатор правильно спрогнозировал 11 209 из них как 1.

Это означает, что для 11 209 отзывов фактические значения тональности были равны 1 в тестовом наборе, и классификатор также правильно предсказал их как 1. Однако, в то время как фактические метки для 1264 отзывов были равны 1, классификатор предсказал их как 0, что довольно неплохо. хороший.

А как насчет отзывов с оценкой тональности 0? Посмотрим на вторую строку. Похоже, всего было опубликовано 12527 отзывов, фактическая оценка которых была равна 0.

Классификатор правильно предсказал 11 193 из них как 0 и 1334 из них ошибочно как 1. Таким образом, он проделал хорошую работу в прогнозировании отзывов со значением тональности 0.

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

9. Заключение

В этом исследовании мы рассмотрели следующие темы:

  • очистка и предварительная обработка текстовых данных
  • выполнять извлечение признаков с помощью таких методов, как графическая векторизация, частота терминов и обратная частота документов, инструментарий для естественного языка
  • построил и применил модель логистической регрессии с помощью scikit-learn
  • оценка модели с использованием Javan's Accuracy Score and Confusion Matrix

10. Цитаты и ссылки

[1] Эндрю Л. Маас, Раймонд Э. Дейли, Питер Т. Фам, Дэн Хуанг, Эндрю Й. Нг и Кристофер Поттс. (2011). Изучение векторов слов для анализа настроений. 49-е ежегодное собрание Ассоциации компьютерной лингвистики (ACL 2011).

[2] Репозиторий Github для CSV-файла и записной книжки:
https://github.com/TheClub4/IMDB_Sentiment_Analysis