Условие
Классифицируем тексты отзывов (negative/positive). Когда TF-IDF, когда BERT?
Решение
Подход
| TF-IDF | BERT | |
|---|---|---|
| Семантика | Bag-of-words, нет контекста | Контекстуальная |
| Скорость train | Очень быстро | Медленно (GPU) |
| Inference | Быстро | Медленно (~50-100ms на CPU) |
| Малая выборка | Лучше | Overfit |
| Длинные тексты | OK | 512 токенов лимит (default) |
| Out-of-vocab | Нет (только seen) | BPE справляется |
| Интерпретация | Веса слов | SHAP / attention |
TF-IDF pipeline
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.linear_model import LogisticRegression
from sklearn.pipeline import Pipeline
pipe = Pipeline([
('tfidf', TfidfVectorizer(
ngram_range=(1,2),
max_features=50_000,
min_df=5, max_df=0.95,
sublinear_tf=True,
strip_accents='unicode',
lowercase=True,
)),
('clf', LogisticRegression(C=1.0, max_iter=1000))
])
pipe.fit(X_train, y_train)С N=10k текстов TF-IDF + LR обычно даёт baseline 80-85% accuracy.
BERT embeddings
from transformers import AutoTokenizer, AutoModel
import torch
tokenizer = AutoTokenizer.from_pretrained("DeepPavlov/rubert-base-cased")
model = AutoModel.from_pretrained("DeepPavlov/rubert-base-cased").eval()
def bert_embed(texts, max_len=128):
enc = tokenizer(texts, padding=True, truncation=True,
max_length=max_len, return_tensors='pt')
with torch.no_grad():
out = model(**enc)
# Стратегии: CLS токен, mean pooling, max pooling
mask = enc.attention_mask.unsqueeze(-1).float()
pooled = (out.last_hidden_state * mask).sum(1) / mask.sum(1)
return pooled.numpy()Затем над эмбеддингами — любой classifier (LR, XGB).
Fine-tuning BERT vs frozen embeddings
- Frozen + classifier head: быстро, baseline.
- Full fine-tuning: лучший accuracy, но требует данных (5k+ примеров) и GPU.
- LoRA / adapters: компромисс — обучаем малый адаптер.
Когда что
- TF-IDF: классификация тем, поиск ключевых слов, малая выборка, low-latency требования.
- BERT frozen + LR: средний размер данных, нужна семантика, latency не критична.
- BERT fine-tune: достаточно данных, важно качество, есть GPU.
- Sentence-BERT: для сравнения текстов через cosine similarity.
Подводные камни
- TF-IDF без min_df → шум из редких опечаток. min_df=5 минимум.
- BERT 512 токенов default — длинные тексты обрезаются. Альтернативы: Longformer, Sliding window, chunking.
- Domain mismatch: BERT-base обучен на Wikipedia/news; на медицинских / юридических текстах хуже. Используйте domain-specific (BioBERT, LegalBERT).
- CLS токен из non-fine-tuned BERT — слабый sentence embedding. Лучше mean pooling или fine-tuned SBERT.
- На малой выборке (n<500) BERT fine-tune overfit. Stick to TF-IDF.
Эталонный ответ
TF-IDF: быстрый baseline, bag-of-words, отличный при малой выборке и low-latency. BERT: контекстуальная семантика, фron мер для средних/больших данных и важного качества. Fine-tune BERT при n>5k и GPU; frozen BERT + LR для baseline; SBERT для сравнения текстов.