Основы 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