Как простые NLP модели видят слова? | NLP | Пишем свой TF-IDF

от автора

Как модели видят наш текст?

Когда начинаешь погружаться в сферу NLP, сразу задумываешься, как модели представляют себе наш текст/наши слова? Ведь не логично бы звучало, если модель обрабатывала наши слова, как обычную последовательность букв. Это было бы не удобно и не понятно(как проводить операции со словами?).

Есть разные методы преобразования слов. Один из самых известных для не самых сложных моделей: TF-IDF.

Как работает TF-IDF?

TF-IDF(Term Frequency-Inverse Document Frequency) — это метод, который преобразует слова в числовые векторы, что делает их более понятными для моделей машинного обучения.

Причем числовые векторы здесь содержат TF-IDF значения, а не просто любые числа.

Значения TF-IDF пытаются показать насколько важно слово для нас в этом документе(наборе текстовых данных).

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

Вот формулы подсчета TF-IDF:

TF(t, d) = \frac{n_t}{\sum_{k} n_k}

t — наше слово
d — наш документ

В формуле мы делим число вхождений нашего слова в данный документ на общее число слов в документе.

TF(Term Frequency) — обозначает частоту нашего слова в документе.

IDF(t, D) = log(\frac{|D|}{|\{ d_i\in D | t \in d_i \}|})

t — наше слово
D — корпус документов(список всех текстовых данных)

В формуле мы берем логарифм от деления общего числа всех документов(длина D) на число документов из корпуса D, которые содержат наше слово.

Логарифм используется для сглаживания значений.

IDF(Inverse Document Frequency) — обозначает обратную частоту, с которой наше слово встречается в документах корпуса.

Умножая TF и IDF, получаем формулу TF-IDF:

TF\_IDF(t, d, D) = TF(t, d) * IDF(t, D)

Большой вес в 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.

Разобьём ее на четыре части:

  • Создаем словарь

  • TF

  • IDF

  • 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


ссылка на оригинал статьи https://habr.com/ru/articles/836706/


Комментарии

Добавить комментарий

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