Как простые NLP модели видят слова? | NLP | Пишем свой TF-IDF
Как модели видят наш текст?
Когда начинаешь погружаться в сферу NLP, сразу задумываешься, как модели представляют себе наш текст/наши слова? Ведь не логично бы звучало, если модель обрабатывала наши слова, как обычную последовательность букв. Это было бы не удобно и не понятно(как проводить операции со словами?).
Есть разные методы преобразования слов. Один из самых известных для не самых сложных моделей: TF-IDF.
Как работает TF-IDF?
TF-IDF(Term Frequency-Inverse Document Frequency) — это метод, который преобразует слова в числовые векторы, что делает их более понятными для моделей машинного обучения.
Причем числовые векторы здесь содержат TF-IDF значения, а не просто любые числа.
Значения TF-IDF пытаются показать насколько важно слово для нас в этом документе (наборе текстовых данных).
Когда мы имеем текстовые данные, нам нужно разбить их на куски. Это можно сделать по предложениям, смысловым абзацам, целым текстам или как-то по-другому.
Вот формулы подсчета TF-IDF:
t — наше слово
d — наш документ
В формуле мы делим число вхождений нашего слова в данный документ на общее число слов в документе.
TF(Term Frequency) — обозначает частоту нашего слова в документе.
t — наше слово
D — корпус документов (список всех текстовых данных)
В формуле мы берем логарифм от деления общего числа всех документов (длина D) на число документов из корпуса D, которые содержат наше слово.
Логарифм используется для сглаживания значений.
IDF(Inverse Document Frequency) — обозначает обратную частоту, с которой наше слово встречается в документах корпуса.
Умножая TF и IDF, получаем формулу TF-IDF:
Большой вес в TF-IDF получат слова с высокой частотой в пределах конкретного документа и с низкой частотой употреблений в других документах.
План написания своего TF-IDF.
Для закрепления и лучшего понимания напишем TF-IDF сами.
План:
договоримся в каком формате будут приходить текстовые данные
посчитаем TF-IDF
вернем нужную информацию
Данные будем получать в формате списка документов (в нашем случае список предложений).
Возвращать будет матрицу значений TF-IDF для каждого слова/документ.
Код
Сначала импортируем нужные библиотеки.
import numpy as np
import pandas as pd
Получим данные, приведем их в нужный формат — каждый новый документ (у нас предложение) будет с новой строки, поэтому разделим их по »\n
», получим список.
(Текст взяли из случайной статьи на Википедиа.)
with open('data.txt', 'r') as file:
content = file.read()
print(content)
data = content.split("\\n")
Сейчас самое сложное — напишем функцию tf-idf
.
Разобьём ее на четыре части:
#1
vocab = [] # cоздаем список всех слов.
for text in texts: # проходимся по каждому документу(преложению)
words = text.split() # разбиваем его на слова
for word in words: # проходимся по каждому слову
if not word in vocab: # если такого слова еще нет в нашем списке
vocab.append(word) # добавлем новое слово
Так мы заполняем список уникальными словами.
#2
# наш словарь TF в формате: "слово": [tf_в_документе1, tf_в_документе2, tf_в_документеN]
tf_dict = {}
for word in vocab: # проходимся по каждому слову из списка всех слов
tf_dict_this_word = [] # список всех tf(для каждого документа ) для данного слова
for text in texts: # проходимся по всем документам
if word in text: # если слово в документе
count_word = text.split().count(word) # считаем сколько его в этом документе
# считаем tf для данного документа и добавляем в список всех tf для этого слова
# tf = кол-во слова в документе / длина документа
tf_dict_this_word.append(count_word/len(text.split()))
else:
tf_dict_this_word.append(0) # если слова в этом документе нет - добавляем 0
tf_dict[word] = tf_dict_this_word # добавлем новую запись в наш словарь в нужно формате
У нас уже есть таблица TF для всех слов ко всем документам.
#3
idf_dict = {} # словарь IDF в формате: "слово" : его_idf
for word in vocab: # проходимся по всем словам
# считаем во скольки документах есть данное слово
count_word = sum(1 for text in texts if word in text.split())
# считаем idf и записывем в словарь
# idf = log( кол-во всех документов / кол-во документов содержащих наше слово )
idf_dict[word] = np.log(len(texts) / count_word)
IDF посчитали, осталось перемножить и вернуть.
#4
# словарь посчитанных tf-idf( "слово" : [tf-idf_в_док1, tf-idf_в_док2, tf-idf_в_докN] )
tf_idf = {}
for word in vocab: # проходимся по каждому слову
# по элементно умножаем idf слова на список tf для этого слова
# tf-idf = tf * idf
tf_idf[word] = np.array(tf_dict[word])*idf_dict[word]
Собираем в одну функцию и возвращаем:
def tf_idf(texts: list):
#vocab
vocab = []
for text in texts:
words = text.split()
for word in words:
if not word in vocab:
vocab.append(word)
#tf
tf_dict = {}
for word in vocab:
tf_dict_this_word = []
for text in texts:
if word in text:
count_word = text.split().count(word)
tf_dict_this_word.append(count_word/len(text.split()))
else:
tf_dict_this_word.append(0)
tf_dict[word] = tf_dict_this_word
#idf
idf_dict = {}
for word in vocab:
count_word = sum(1 for text in texts if word in text.split())
idf_dict[word] = np.log(len(texts) / count_word)
#tf-idf
tf_idf = {}
for word in vocab:
tf_idf[word] = np.array(tf_dict[word])*idf_dict[word]
return tf_idf
Пример использования
(Взяли текст из этой статьи)
Наши текстовые данные(data.txt):
Произведения Альтова исполняли Геннадий Хазанов («Геракл», «Вобла», «Хор в посольстве», «Волки и овцы», «Плавки»), Клара Новикова («Кармен»), Ефим Шифрин («Кающаяся Мария Магдалина», «Покушение», «Блуждающая грудь», «Золушка», «Оазис», «Сексонфу», «Бычара», «Личный пример»), Владимир Винокур («Кувырок судьбы»).
Кроме того, свои произведения исполняет и автор.
Семён Альтов выделяется среди прочих выступающих писателей-юмористов своеобразной исполнительской манерой — Альтов читает свои монологи с непроницаемым и даже мрачным выражением лица, однообразным низким голосом со своеобразным акцентом, даже не улыбаясь.
Манера произношения Альтова пародируется многими эстрадными артистами (Братья Пономаренко, Игорь Христенко и т. д.).
my_tf_idf = tf_idf(data) # используем нашу функцию, передавая наши данные
# для визуала создаем DataFrame и транспонируем его(для красоты, опять же)
tfidf_table = pd.DataFrame(my_tf_idf).T
print(tfidf_table) # смотрим результат
Видим такую таблицу значений TF-IDF:
Ура, у нас получилось — мы написали свой TF-IDF.
Спасибо♥
Ресурсы
Код на Google Colab
Википедиа
Статья, которую мы использовали
TF_IDF
Github
Kaggle
Я на Github
Я на Kaggle
Мой Датасет на Kaggle