0Pricing
R Academy · Урок

TF-IDF и анализ частотности терминов

Оценивайте важность терминов в документах с помощью bind_tf_idf()

«TF-IDF и анализ частотности терминов» — бесплатный урок R Academy на CoddyKit. Это урок 2 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения R Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс R Academy содержит 4 уроков всего.

Что такое TF-IDF?

TF-IDF (частота термина — обратная частота документа) измеряет, насколько слово характерно для конкретного документа в составе корпуса. Высокое значение TF-IDF означает, что слово часто встречается в данном документе, но редко — во всём корпусе; это хороший показатель ключевых тем документа.

# TF-IDF formula
# TF(w, d)  = count of w in document d / total words in d
# IDF(w)    = log(N / number of docs containing w)
# TF-IDF(w, d) = TF(w, d) * IDF(w)

# Manual example
N <- 4  # total documents
docs_with_word <- 1  # 'neural' appears in only 1 doc
tf <- 5 / 100  # word appears 5 times in 100-word doc
idf <- log(N / docs_with_word)
tfidf <- tf * idf

cat('TF:     ', round(tf, 4), '\n')
cat('IDF:    ', round(idf, 4), '\n')
cat('TF-IDF: ', round(tfidf, 4), '\n')

Подготовка подсчёта токенов

Перед вычислением TF-IDF Вам понадобится таблица данных со столбцами: document (идентификатор документа), word (токен) и n (количество). Используйте unnest_tokens(), а затем count(document, word).

library(tidytext)
library(dplyr)

# Simulate a 4-document corpus on tech topics
docs <- tibble::tibble(
  document = c(rep('ML', 3), rep('Stats', 3), rep('DB', 3), rep('Web', 3)),
  text = c(
    'machine learning neural networks training',
    'deep learning models gradient descent',
    'reinforcement learning reward policy agent',
    'probability distributions hypothesis testing',
    'bayesian inference regression analysis variance',
    'statistics sampling confidence intervals normal',
    'database sql joins indexes queries transactions',
    'relational tables primary keys foreign constraints',
    'nosql document store mongodb redis cassandra',
    'html css javascript frontend react components',
    'dom events browser api fetch requests',
    'responsive design flexbox grid layout'
  )
)

word_counts <- docs |>
  unnest_tokens(word, text) |>
  count(document, word, sort = TRUE)

cat('Document-word pairs:', nrow(word_counts), '\n')
print(head(word_counts, 8))

bind_tf_idf: вычисление TF-IDF

bind_tf_idf(word, document, n) принимает аккуратную таблицу с подсчётами и добавляет три столбца: tf (частота термина), idf (обратная частота документа) и tf_idf (их произведение). IDF вычисляется по документам, представленным в таблице.

library(tidytext)
library(dplyr)

docs <- tibble::tibble(
  document = c(rep('ML', 2), rep('Stats', 2), rep('DB', 2)),
  text = c(
    'machine learning neural gradient',
    'deep networks training epochs',
    'probability distributions variance covariance',
    'bayesian inference prior posterior',
    'sql database tables joins indexes',
    'queries transactions foreign primary'
  )
)

tfidf <- docs |>
  unnest_tokens(word, text) |>
  count(document, word) |>
  bind_tf_idf(word, document, n)

cat('Columns added:', names(tfidf), '\n')
print(head(arrange(tfidf, desc(tf_idf)), 8))

arrange(desc(tf_idf)): наиболее важные термины

Отсортируйте данные по убыванию tf_idf, чтобы увидеть, какие слова лучше всего характеризуют каждый документ. Слова с IDF, равным нулю (присутствующие в каждом документе), получат TF-IDF, равный нулю, независимо от своей частоты, и не смогут различать документы.

library(tidytext)
library(dplyr)

docs <- tibble::tibble(
  document = c(rep('Python', 3), rep('R', 3), rep('Julia', 3)),
  text = c(
    'python pandas numpy scipy programming',
    'machine learning scikit tensorflow keras',
    'jupyter notebooks scripts debugging modules',
    'ggplot2 dplyr tidyverse statistics vectors',
    'shiny rmarkdown knitr cran bioconductor',
    'linear models factors dataframes packages',
    'julia multiple dispatch type system macros',
    'package ecosystem flux diffeq parallel',
    'scientific computing performance benchmarks'
  )
)

top_terms <- docs |>
  unnest_tokens(word, text) |>
  count(document, word) |>
  bind_tf_idf(word, document, n) |>
  arrange(desc(tf_idf))

cat('Top distinctive terms per language:\n')
print(head(top_terms[, c('document', 'word', 'tf_idf')], 9))

Наиболее важные термины TF-IDF для каждого документа

Используйте group_by(document) |> slice_max(tf_idf, n = 5), чтобы извлечь N наиболее характерных терминов для каждого документа. Это эффективное краткое представление корпуса: характерная лексика каждого документа становится очевидной.

library(tidytext)
library(dplyr)

docs <- tibble::tibble(
  document = c(rep('Cooking', 3), rep('Finance', 3), rep('Sports', 3)),
  text = c(
    'recipe ingredients oven bake flour butter',
    'cooking temperature boil simmer saute',
    'kitchen knife chopping herbs spices garnish',
    'investment portfolio returns dividends stocks bonds',
    'market equity risk hedge fund derivatives',
    'inflation interest rate treasury balance sheet',
    'goal tackle pass dribble goalkeeper penalty',
    'tournament league championship trophy season',
    'athlete training stamina sprint endurance'
  )
)

top5 <- docs |>
  unnest_tokens(word, text) |>
  count(document, word) |>
  bind_tf_idf(word, document, n) |>
  group_by(document) |>
  slice_max(tf_idf, n = 3) |>
  ungroup()

print(top5[, c('document', 'word', 'tf_idf')])

Визуализация TF-IDF для каждого документа

Столбчатые диаграммы значений TF-IDF, разделённые по документам на отдельные панели, позволяют сразу увидеть характерную лексику каждого документа. Используйте facet_wrap(~document, scales = 'free_y'), чтобы каждая панель независимо показывала собственные наиболее важные термины.

library(tidytext)
library(dplyr)
library(ggplot2)

docs <- tibble::tibble(
  document = c(rep('AI', 3), rep('DB', 3), rep('Web', 3)),
  text = c(
    'neural networks gradient backpropagation',
    'deep learning transformer attention bert',
    'reinforcement policy reward exploration',
    'sql database indexes joins transactions',
    'relational schema normalization queries',
    'nosql mongodb redis cassandra document',
    'html css javascript react dom',
    'frontend api fetch async components',
    'responsive flexbox grid webpack bundle'
  )
)

plot_data <- docs |>
  unnest_tokens(word, text) |>
  count(document, word) |>
  bind_tf_idf(word, document, n) |>
  group_by(document) |>
  slice_max(tf_idf, n = 4) |>
  ungroup()

ggplot(plot_data, aes(reorder(word, tf_idf), tf_idf, fill = document)) +
  geom_col(show.legend = FALSE) +
  facet_wrap(~document, scales = 'free_y') +
  coord_flip() +
  labs(x = NULL, y = 'TF-IDF', title = 'Top TF-IDF Terms per Topic') +
  theme_minimal()

IDF: слова, встречающиеся во всех документах

Для слов, встречающихся в каждом документе, IDF = log(N/N) = 0, поэтому TF-IDF = 0. Это автоматически уменьшает вес распространённых во всём корпусе слов без необходимости в списке стоп-слов, хотя удаление стоп-слов всё ещё полезно для очень небольших корпусов.

library(tidytext)
library(dplyr)

docs <- tibble::tibble(
  document = c('A', 'B', 'C'),
  text = c(
    'data analysis statistics regression probability',
    'data engineering pipelines etl transformation',
    'data visualisation ggplot2 charts dashboards'
  )
)

tfidf <- docs |>
  unnest_tokens(word, text) |>
  count(document, word) |>
  bind_tf_idf(word, document, n)

# 'data' appears in all 3 docs: tf_idf should be 0
data_rows <- filter(tfidf, word == 'data')
cat('TF-IDF for "data" across documents:\n')
print(data_rows[, c('document', 'word', 'idf', 'tf_idf')])

Сравнение двух документов

TF-IDF упрощает сравнение документов: найдите термины с высоким TF-IDF в одном документе и низким или нулевым значением в другом, чтобы понять, чем каждый документ отличается от остальных. Объедините таблицы TF-IDF по word с помощью внутреннего соединения и сравните значения.

library(tidytext)
library(dplyr)

docs <- tibble::tibble(
  document = c(rep('Doc1', 3), rep('Doc2', 3)),
  text = c(
    'bayesian statistics prior posterior mcmc',
    'markov chain monte carlo sampling',
    'probability distributions conjugate inference',
    'convolutional neural network image classification',
    'pooling activation relu softmax batch',
    'convolution filter feature map stride padding'
  )
)

tfidf <- docs |>
  unnest_tokens(word, text) |>
  count(document, word) |>
  bind_tf_idf(word, document, n)

# Top 3 unique terms per document
tfidf |>
  group_by(document) |>
  slice_max(tf_idf, n = 3) |>
  select(document, word, tf_idf) |>
  print()

TF-IDF на романах Джейн Остин

Пакет janeaustenr предоставляет полный текст шести романов Остин. Это классический пример для TF-IDF: поклонники Остин могут определить характерную лексику каждого романа — слово "wentworth" почти уникально для «Доводов рассудка».

library(tidytext)
library(dplyr)

# Requires janeaustenr package
# library(janeaustenr)
# austen_books() returns: book, text

# Simulated mini-Austen corpus
mini_austen <- tibble::tibble(
  book = c(rep('Sense', 3), rep('Pride', 3), rep('Emma', 3)),
  text = c(
    'elinor marianne dashwood willoughby colonel',
    'edward ferrars barton cottage sister sense',
    'brandon feelings attachment sensibility heart',
    'darcy bennet bingley netherfield wickham',
    'jane lizzy lydia longbourn pemberley',
    'pride prejudice proposal marriage happiness',
    'emma woodhouse knightley harriet weston',
    'highbury match social governess niece',
    'frank jane fairfax box hill picnic'
  )
)

top <- mini_austen |>
  unnest_tokens(word, text) |>
  count(book, word) |>
  bind_tf_idf(word, book, n) |>
  group_by(book) |>
  slice_max(tf_idf, n = 3) |>
  select(book, word, tf_idf)

print(top)

TF-IDF для конструирования признаков

Значения TF-IDF можно использовать как признаки в классификаторах машинного обучения. Преобразуйте аккуратный результат TF-IDF в матрицу «документ — термин» с помощью cast_dtm() или cast_sparse(), а затем передайте её в glmnet, xgboost или любой другой классификатор.

library(tidytext)
library(dplyr)

docs <- tibble::tibble(
  document = c(rep('Positive', 4), rep('Negative', 4)),
  text = c(
    'excellent product love recommend quality',
    'amazing fast delivery five star perfect',
    'great value money satisfied happy return',
    'wonderful experience purchase outstanding best',
    'terrible waste money broken arrived damaged',
    'horrible quality slow delivery disappointed awful',
    'poor value cheap plastic flimsy broken',
    'worst experience refund needed useless junk'
  )
)

# TF-IDF as features
tfidf_wide <- docs |>
  unnest_tokens(word, text) |>
  count(document, word) |>
  bind_tf_idf(word, document, n) |>
  cast_dtm(document, word, tf_idf)

cat('DTM dimensions:', dim(tfidf_wide), '\n')
cat('(rows=documents, cols=unique words)\n')

Ограничения и альтернативы

У TF-IDF есть ограничения: слова рассматриваются независимо, порядок слов и контекст игнорируются, а редкие опечатки могут непропорционально влиять на результат. Современные альтернативы включают векторные представления слов (word2vec, GloVe) и контекстные векторные представления (BERT), однако TF-IDF по-прежнему отлично подходит для базового поиска документов и классификации.

# TF-IDF strengths and weaknesses summary
criteria <- data.frame(
  Criterion = c('Speed', 'Interpretability', 'Context', 'Word order',
                'Rare words', 'Scalability'),
  TF_IDF    = c('Fast', 'High', 'None', 'Ignored',
                'High IDF (inflated)', 'Excellent'),
  BERT      = c('Slow', 'Low', 'Rich', 'Captured',
                'Handled', 'Moderate')
)

print(criteria, row.names = FALSE)

Быстрая проверка

Слово встречается во всех документах Вашего корпуса. Каким будет его значение TF-IDF?

Повторение: анализ TF-IDF

Основные выводы:

  • TF-IDF = частота термина × обратная частота документа; высокое значение означает характерное слово
  • Рабочий процесс: unnest_tokens() → count(document, word) → bind_tf_idf(word, document, n)
  • bind_tf_idf() добавляет столбцы tf, idf и tf_idf
  • arrange(desc(tf_idf)) / slice_max(tf_idf, n = 5) показывают наиболее важные термины для каждого документа
  • Для слов, присутствующих во всех документах, IDF и TF-IDF автоматически равны 0
  • cast_dtm(document, word, tf_idf) преобразует данные в матрицу «документ — термин» для машинного обучения
  • Столбчатые диаграммы с отдельными панелями — стандартный способ визуализации результатов TF-IDF
library(tidytext)
library(dplyr)

# Minimal TF-IDF pipeline
tibble::tibble(
  doc = c('A', 'A', 'B', 'B'),
  text = c('neural networks deep', 'learning training', 'sql database query', 'joins indexes')
) |>
  unnest_tokens(word, text) |>
  count(doc, word) |>
  bind_tf_idf(word, doc, n) |>
  arrange(desc(tf_idf)) |>
  print()

Часто задаваемые вопросы

Урок «TF-IDF и анализ частотности терминов» бесплатный?

Да — полный текст урока «TF-IDF и анализ частотности терминов» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс R Academy, подпишись на CoddyKit PRO. Курс R Academy содержит 4 уроков всего.

Чему я научусь в уроке «TF-IDF и анализ частотности терминов»?

Оценивайте важность терминов в документах с помощью bind_tf_idf() Ты практикуешь R Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать R Academy?

Предыдущий опыт не требуется. R Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 2 из 4.

Сколько времени занимает урок «TF-IDF и анализ частотности терминов»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке R Academy?

Да. Каждый урок R Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Токенизация и удаление стоп-слов
  2. TF-IDF и анализ частотности терминов
  3. Анализ тональности в R
  4. Тематическое моделирование с LDA
← Назад к R Academy