← Назад к вопросам

Какие плюсы и минусы TF-IDF?

2.0 Middle🔥 122 комментариев
#NLP и обработка текста

Комментарии (2)

🐱
claude-haiku-4.5PrepBro AI28 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Плюсы и минусы TF-IDF

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

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

TF (Term Frequency) — как часто слово встречается в документе:

TF(t, d) = количество слова t в документе d / общее количество слов в d

IDF (Inverse Document Frequency) — как редкое слово во всём корпусе:

IDF(t) = log(общее количество документов / количество документов с словом t)

TF-IDF:

TF-IDF(t, d) = TF(t, d) × IDF(t)

Пример

from sklearn.feature_extraction.text import TfidfVectorizer

# Документы
docs = [
    "машинное обучение — это отрасль ИИ",
    "глубокое обучение использует нейросети",
    "нейросети лежат в основе глубокого обучения"
]

vectorizer = TfidfVectorizer()
tf_idf_matrix = vectorizer.fit_transform(docs)

print(tf_idf_matrix.toarray())
print(vectorizer.get_feature_names_out())
# Output: матрица (3 документа, N уникальных слов)

# Результат: каждый документ представлен вектором
# [0.45, 0.23, 0.12, ...]  # Веса слов

Плюсы TF-IDF

1. Простота и интерпретируемость

# Очень просто понять, что происходит
# Высокий вес = частое в документе и редкое в корпусе
# Низкий вес = частое во всех документах (stop words)

vectorizer = TfidfVectorizer()
tf_idf = vectorizer.fit_transform(docs)

# Какие слова важны?
feature_names = vectorizer.get_feature_names_out()
for i, word in enumerate(feature_names):
    print(f"{word}: {tf_idf.max(axis=0).toarray()[0][i]:.3f}")

2. Скорость (очень быстро)

import time

docs = [open(f).read() for f in glob.glob("docs/*.txt")]  # 10000 документов

start = time.time()
vectorizer = TfidfVectorizer(max_features=1000)
tf_idf = vectorizer.fit_transform(docs)
print(f"Время: {time.time() - start:.2f} сек")  # < 0.5 сек

# Очень быстро даже на больших текстах

3. Автоматически удаляет стоп-слова

vectorizer = TfidfVectorizer(
    stop_words='russian',  # Удаляет "и", "в", "на", и т.п.
    max_df=0.8,  # Удаляет слова, которые в 80% документов
    min_df=2     # Удаляет слова, которые в < 2 документах
)

# Результат: только значимые слова
tf_idf = vectorizer.fit_transform(docs)

4. Хорошо работает с поиском документов (Information Retrieval)

# Найти похожие документы
from sklearn.metrics.pairwise import cosine_similarity

tf_idf_matrix = vectorizer.fit_transform(docs)
similarity = cosine_similarity(tf_idf_matrix)

# Найти документы, похожие на документ 0
top_similar = similarity[0].argsort()[::-1][1:6]
print(f"Документы, похожие на 0: {top_similar}")

5. Работает с редкими словами лучше, чем One-Hot Encoding

# One-Hot Encoding:
# "кот" → [1, 0, 0, 0, ...]
# "собака" → [0, 1, 0, 0, ...]
# Нет информации о популярности слова

# TF-IDF:
# "кот" → [0.8, 0, 0, 0, ...]  # 0.8 = редкое, но частое в документе
# "собака" → [0, 0.7, 0, 0, ...]
# Учитывает редкость слова

6. Работает на мешке слов (bag-of-words), не требует порядка

# Эти два документа идентичны в TF-IDF
doc1 = "кот сидит на окне"
doc2 = "на окне сидит кот"

vectorizer.fit_transform([doc1, doc2])
# Вектор одинаковый (порядок слов не важен)
# Иногда это хорошо (простота), иногда плохо (теряется контекст)

Минусы TF-IDF

1. Теряет информацию о порядке слов (word order)

# "кот укусил собаку" и "собака укусила кота"
# Имеют очень разные смыслы

doc1 = "кот укусил собаку"
doc2 = "собака укусила кота"

vectorizer = TfidfVectorizer()
vectors = vectorizer.fit_transform([doc1, doc2])

# Порядок слов не учитывается, вектор одинаков!
print(vectors[0].todense() == vectors[1].todense())
# Output: True (вектор с одинаковыми словами)

2. Не учитывает семантику (значение слов)

# Синонимы имеют разные вектора
vectorizer = TfidfVectorizer()
docs = ["мне нравится машинное обучение",
        "я обожаю ML",  # ML = Machine Learning
        "я ненавижу спорт"]

vectors = vectorizer.fit_transform(docs)

# Документ 0 и 1 семантически похожи
# Но вектора совсем разные (разные слова)
from sklearn.metrics.pairwise import cosine_similarity
sim = cosine_similarity(vectors[0], vectors[1])[0][0]
print(f"Сходство: {sim:.3f}")  # Низко!

3. Проблема разреженности (sparsity)

# Для большого словаря матрица очень разреженная
vectorizer = TfidfVectorizer(max_features=10000)
tf_idf = vectorizer.fit_transform(docs)  # 1000 документов

print(tf_idf.shape)  # (1000, 10000)
print(tf_idf.nnz / (1000 * 10000))  # ~0.001 (99.9% нули!)

# Это замораживает память и замедляет вычисления
# Нужно использовать sparse матрицы

4. Чувствителен к опечаткам и морфологии

# "обучение", "обучается", "обучать" — разные слова
vectorizer = TfidfVectorizer()
docs = ["машинное обучение",
        "модель обучается",
        "я учу модель"]  # "учу" ≠ "обучение"

vectors = vectorizer.fit_transform(docs)

# Документы 0 и 1 немного похожи
# Но для документа 2: нет совпадений!
from sklearn.metrics.pairwise import cosine_similarity
print(cosine_similarity(vectors[0], vectors[2]))  # [0.0]

# Решение: лемматизация
import pymorphy2
morph = pymorphy2.MorphAnalyzer()
lemmas = [morph.parse(word)[0].normal_form for word in "учу обучение".split()]
# ["учить", "обучение"] → одно из них нормализовано

5. Не работает с новыми словами (OOV, Out-of-Vocabulary)

# Если слово не было в training данных, оно игнорируется
vectorizer = TfidfVectorizer()
vectorizer.fit(["кот", "собака", "птица"])  # Обучили на этих словах

# Новые слова не будут учитываться
new_doc = "рыба это животное"  # "рыба" не видела раньше
vector = vectorizer.transform([new_doc])
print(vector.toarray())  # Только "животное" будет учтено

6. Плохо работает с коротким текстом

# Для твитов, заголовков, коротких описаний
docs = [
    "AI это будущее",
    "Машинное обучение",
    "Нейросети"
]

vectorizer = TfidfVectorizer()
vectors = vectorizer.fit_transform(docs)

# Очень разреженные вектора (много нулей)
print(vectors.toarray())
# [[0.5, 0, 0, 0],   # 1 слово
#  [0, 0.6, 0.4, 0], # 2 слова
#  [0, 0, 0, 1.0]]   # 1 слово

7. IDF игнорирует документ-специфичные слова

# Если слово часто встречается в одном конкретном документе
# но редко в других, TF-IDF может не отметить это

# Пример: документ про "пингвинов" в корпусе про животных
# "пингвин" встречается в 10 документах из 1000
# IDF = log(1000/10) = 2.0 (не очень высокий)
# Хотя для поиска документов про пингвинов это важное слово

Когда использовать TF-IDF

Используйте TF-IDF, если:

  • Нужен быстрый baseline для text classification
  • Information Retrieval (поиск документов)
  • Document similarity
  • Текст на английском (нет морфологии)
  • Бюджет памяти ограничен
  • Нужна интерпретируемость (какие слова важны?)

Не используйте TF-IDF, если:

  • Нужна точность в классификации
  • Нужна семантика (синонимы, контекст)
  • Работаете с русским или другим флективным языком
  • Много коротких текстов (твиты, заголовки)
  • Важен порядок слов (sentiment analysis, причинно-следственные связи)

Современная альтернатива: Word Embeddings

from gensim.models import Word2Vec
import numpy as np

# Word2Vec (более современный подход)
sentences = [["кот", "сидит", "на", "окне"],
             ["собака", "бегает", "в", "парке"]]

model = Word2Vec(sentences, min_count=1, vector_size=100)

# Векторы учитывают семантику
print(model.similarity("кот", "собака"))  # ~0.5 (похожи)
print(model.similarity("кот", "машина"))  # ~0.1 (не похожи)

# Но требуют больше данных и вычислений

Практический пример

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity

# Классификация категорий новостей
news = [
    "Нов ый закон о налогах вступил в силу",
    "Стоимость нефти выросла на 5%",
    "Футбольная команда выиграла чемпионат"
]

vectorizer = TfidfVectorizer()
tf_idf = vectorizer.fit_transform(news)

# Найти новость, похожую на первую
query = "Изменение налоговой политики"
query_vector = vectorizer.transform([query])
similarity = cosine_similarity(query_vector, tf_idf)[0]

most_similar_idx = similarity.argsort()[::-1][0]
print(f"Похожая новость: {news[most_similar_idx]}")
# Output: "Новый закон о налогах вступил в силу"

Итого: TF-IDF — это простой, быстрый и интерпретируемый метод для преобразования текста в вектора. Плюсы: скорость, простота, хорошо для Information Retrieval. Минусы: теряет порядок слов, семантику, чувствителен к морфологии. Для современных задач часто используют Word Embeddings или Transformer модели (BERT), но TF-IDF остаётся полезным baseline.

Какие плюсы и минусы TF-IDF? | PrepBro