One-Hot Encoding, Bag-of-Words, N-граммы и TF-IDF

Обработка естественного языка (NLP) — это подмножество машинного обучения, связанное с языком и семантикой. Машина изучает семантику слов путем обучения, подобно тому, как работает обычное машинное обучение. Проблема возникла, когда мы поняли, что почти все широко используемые модели машинного обучения могут принимать только числовые входные данные. Итак, чтобы обучить машину с использованием текстовых данных, нам нужно найти способ представить текст в виде числового вектора. В этой статье будут продемонстрированы некоторые простые числовые текстовые представления и способы их реализации с помощью Python.

Для этого урока мы будем использовать следующие данные. Контекст этих данных представляет собой обзор университетского предмета. Я провел предварительную обработку данных, а именно удаление стоп-слов, удаление пунктуации и лемматизацию. Все эти тексты вымышлены.

Начнем с нашего самого простого представления. Мы вызываем данные выше, используя Pandas,

df = pd.read_csv("data.csv")

1. Горячее кодирование (OHE)

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

Запустив следующий код,

BagOfWords(df["Comments"])

Вернул бы все уникальные слова в данных,

array(['although', 'amazed', 'bad', 'beautiful', 'bob', 'caution', 'clear', 'concept', 'definitely', 'difficult', 'experience',
'fantastic', 'find', 'first', 'found', 'funny', 'hard',      'however', 'implication', 'interesting', 'jim', 'learned', 'lecturer', 'lot', 'much', 'order', 'people', 'practical', 'really', 'reasonably', 'revision', 'rewarding', 'rubbish', 'scraped', 'spent', 'still', 'subject', 'take', 'taking', 'taught', 'terrible', 'though', 'time', 'trying', 'understand', 'warned', 'way'], dtype='<U32')

Затем мы установили бы каждое из этих слов как столбцы в новом фрейме данных, а затем установили бы значение 1, если слово существует в документе, и 0 в противном случае.

Для этого мы используем следующую функцию:

Строка 7 является сутью этого представления, утверждая, что если слово есть в документе, установите значение как 1 и 0 в противном случае.

Выполнение этих строк кода преобразует df в представление OHE,

BoW = BagOfWords(df["Comments"])
dfOHE = TransformOHE(df, BoW)

Переменная dfOHE теперь представляет собой однократное кодирование data.csv.

2. Мешок слов (BoW)

Текстовое представление BoW похоже на представление OHE. Сначала мы начнем с перечисления каждого слова в корпусе. Мы используем ту же функцию BagOfWords(), что и выше.

В представлении OHE мы устанавливаем значение 1, если слово существует в документе, и 0 в противном случае. В представлении BoW мы подсчитываем количество вхождений слов в документе.

Пример. Для документа «голубое небо, синее море» представление OHE для слова «синий» вернет 1, а представление BoW для слова «синий» вернет 2.

Следующая функция преобразует наш фрейм данных в его представление BoW.

Строка 7 является сутью этого представления, утверждая, что значение записи слова (столбца) является количеством этого слова в записи документа.

Выполнение этих строк кода преобразует df в представление BoW,

BoW = BagOfWords(df["Comments"])
dfBoW = TransformBoW(df, BoW)

Переменная dfBoW теперь является набором слов для представления data.csv.

3. Н-граммы

Существует проблема, возникающая при использовании представления BoW. Использование подсчета слов может иногда игнорировать семантику предложения.

Пример. Предложения «aapple побеждает конкурента» и «cконкурент побеждает Apple» будут иметь точное текстовое представление BoW. Напротив, их значения совершенно противоположны.

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

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

Чтобы продемонстрировать, как это делается, давайте возьмем следующий документ «Отдавать лучше, чем получать».

BoW этого документа,

["giving", "better", "than", "receiving"]

Мешок с 2 граммами этого документа,

["giving better", "better than", "than receiving"]

Мешок 3-граммового мешка этого документа,

["giving better than", "better than receiving"]

Затем мы устанавливаем все уникальные N-граммы в виде столбца и подсчитываем встречаемость фраз в документе. Этот подход теоретически лучше, чем BoW, потому что он сохраняет семантику предложения.

Пример. Чтобы продемонстрировать преимущество этой модели, используя одно и то же предложение «яблоко побеждает конкурента», 2-граммовое представление этого предложения — «яблоко побеждает» и «побеждает конкурента». По сравнению с 2-граммовым представлением «конкурент побеждает яблоко», которые имеют 2-граммовое представление «победа конкурента» и «победа над яблоком». Теперь должно быть очевидно, что эти 2-граммовые представления сохраняют семантику предложения.

Мы используем следующую функцию, чтобы получить мешок с N-граммами.

Запустив следующий код,

BagOfNGrams(df["Comments"], 2)

Выведет следующий массив,

array(['although warned', 'amazed much', 'bad experience', 'bad lecturer', 'beautiful clear', 'bob bad', 'bob terrible', 'caution taking', 'clear practical', 'concept still', 'definitely hard', 'difficult first', 'difficult however', 'difficult subject', 'experience bob', 'fantastic subject', 'find subject', 'first take', 'found reasonably', 'funny lecturer', 'hard rewarding', 'hard spent', 'hard subject', 'however lot', 'however really', 'interesting subject', 'jim funny', 'learned revision', 'lecturer amazed', 'lecturer rubbish', 'lot concept', 'much learned', 'order found', 'people hard', 'practical implication', 'really beautiful', 'really hard', 'reasonably difficult', 'rewarding although', 'rubbish subject', 'scraped though', 'spent time', 'still hard', 'subject however', 'subject jim', 'subject really', 'subject scraped', 'subject taught', 'subject way', 'take caution', 'taking subject','taught difficult', 'terrible lecturer', 'though bad', 'time trying', 'trying understand', 'understand concept', 'warned people', 'way order'], dtype='<U32')

Как и BoW, мы затем устанавливаем каждую из этих N-грамм как столбцы и подсчитываем их появление в документе. Мы можем повторно использовать функцию TransformBoW() для преобразования. Я перепишу функцию ниже,

Выполнение этих строк кода преобразует df в представление N-грамм,

# Your choice of N
N = 2
BoN = BagOfNGrams(df["Comments"], N)
dfBoN = TransformBoN(df, BoN)

Переменная dfBoN теперь является представлением data.csv в N-граммах.

4. ОФ-ЦАХАЛ

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

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

Чтобы решить эту проблему, мы вводим текстовое представление TF-IDF. TF-IDF расшифровывается как «Частота термина и обратная частота документа». Мы вычисляем TF-IDF, умножая два компонента, частоту термина и обратную частоту документа.

Подобно предыдущим представлениям, каждый столбец представления TF-IDF представляет собой каждое слово в наборе слов корпуса.

Для каждого слова t (столбца) в наборе слов мы вычисляем

  • Частота терминов: этот компонент вычисляет появление слова t в документе, аналогично представлению BoW. Затем мы «нормализуем» это, чтобы приспособиться к длине документа.

  • Обратная частота документов. Частота документов вычисляет количество документов, содержащих слово t. Обратная частота документа делится на N(общее количество документов)на частоту документа. Обычно мы берем логарифмическое значение IDF, чтобы уменьшить влияние больших наборов данных на значение IDF.

Приведенная выше формула IDF хороша, если предположить, что каждое слово в наборе слов присутствует по крайней мере в одном документе. Это может быть не так, если вы подгоняете TF-IDF к обучающим данным и используете его для преобразования данных тестирования. Другими словами, вы используете набор слов обучающих данных для вычисления TF-IDF тестовых данных. Следовательно, некоторые слова могут отсутствовать ни в одном из документов. В этом случае мы получим ошибку деления на ноль. Чтобы предотвратить это, мы можем применить сглаживание формулы IDF. Существует множество литературы по различным методам сглаживания. Метод, который я привожу ниже, используется по умолчанию в библиотеке scikit-learn.

Следовательно, чтобы вычислить TF-IDF столбца (слова) i и строки (документа) j, мы используем следующую формулу:

Как я упоминал ранее, нам нужно получить мешок слов из корпуса. Мы можем снова использовать нашу функцию BagOfWords().

Мы вычисляем TF-IDF, используя следующую функцию:

Выполнение этих строк кода преобразует df в представление N-грамм,

BoW = BagOfWords(df["Comments"])
dftf = TFIDF(df, BoW)

Переменная dftf теперь является представлением data.csv в TF-IDF.

Не забудьте указать smoothing = True в функции TFIDF(), если вам нужно применить сглаживание. Вы можете изменить наш код, чтобы использовать n-граммы с TF-IDF.

Поздравления

Мы завершили этот простой учебник по базовым представлениям текста. Я призываю вас изучить более сложные представления, такие как word2vec или doc2vec. Посетите мой репозиторий GitHub, чтобы просмотреть набор данных, выходные данные представления и полный код. Если вам понравилась эта статья, рассмотрите возможность аплодировать и подписаться. Пожалуйста, делитесь любыми отзывами и мыслями в комментариях. Спасибо за чтение!