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

Что такое N-gram?

2.3 Middle🔥 221 комментариев
#NLP и обработка текста#Машинное обучение

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

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

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

N-gram: основы обработки текста

N-gram это последовательность из N элементов из текста. Это один из фундаментальных методов NLP для представления текста и анализа языка.

Определение

N-gram — это последовательность N consecutives элементов:

- 1-gram (unigram): одно слово или символ
- 2-gram (bigram): два consecutives слова/символа
- 3-gram (trigram): три consecutives слова/символа
- N-gram: N consecutives элементов

Пример с текстом

Текст: "The quick brown fox"

1-grams: ["the", "quick", "brown", "fox"]

2-grams: [("the", "quick"), ("quick", "brown"), ("brown", "fox")]
         или по словам: ["the quick", "quick brown", "brown fox"]

3-grams: [("the", "quick", "brown"), ("quick", "brown", "fox")]
         или: ["the quick brown", "quick brown fox"]

На символьном уровне

Текст: "hello"

1-grams: ["h", "e", "l", "l", "o"]

2-grams: [("h", "e"), ("e", "l"), ("l", "l"), ("l", "o")]
         или: ["he", "el", "ll", "lo"]

3-grams: [("h", "e", "l"), ("e", "l", "l"), ("l", "l", "o")]
         или: ["hel", "ell", "llo"]

Python реализация

from collections import Counter
import nltk

# Способ 1: Вручную (слова)
text = "the quick brown fox jumps"
words = text.split()

# 1-grams
unigrams = words
# ['the', 'quick', 'brown', 'fox', 'jumps']

# 2-grams
bigrams = [tuple(words[i:i+2]) for i in range(len(words)-1)]
# [('the', 'quick'), ('quick', 'brown'), ('brown', 'fox'), ('fox', 'jumps')]

# 3-grams
trigrams = [tuple(words[i:i+3]) for i in range(len(words)-2)]
# [('the', 'quick', 'brown'), ('quick', 'brown', 'fox'), ('brown', 'fox', 'jumps')]

# Способ 2: NLTK (встроенные функции)
from nltk.util import ngrams

text_tokens = "the quick brown fox".split()

bigrams = list(ngrams(text_tokens, 2))
trigrams = list(ngrams(text_tokens, 3))
fourgrams = list(ngrams(text_tokens, 4))

# Способ 3: sklearn (векторизация)
from sklearn.feature_extraction.text import CountVectorizer

vectorizer = CountVectorizer(
    analyzer='word',  # или 'char' для символов
    ngram_range=(1, 2),  # unigrams + bigrams
    lowercase=True
)

X = vectorizer.fit_transform(["the quick brown fox"])
print(vectorizer.get_feature_names_out())
# ['brown' 'fox' 'quick' 'the' 'the quick' 'quick brown' 'brown fox']

Счётчик N-grams

from collections import Counter

text = "the cat sat on the mat"
words = text.split()

# Bigrams с частотностью
bigrams = [' '.join(words[i:i+2]) for i in range(len(words)-1)]
bigram_counts = Counter(bigrams)

for bigram, count in bigram_counts.most_common(3):
    print(f"{bigram}: {count}")

# Результат:
# the cat: 1
# cat sat: 1
# sat on: 1
# on the: 1
# the mat: 1

Практические применения

1. Text Classification

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.svm import SVC

# Тексты
docs = [
    "I love this movie",
    "This movie is great",
    "I hate this movie",
    "Terrible and boring"
]
labels = [1, 1, 0, 0]  # 1=positive, 0=negative

# N-grams как features
vectorizer = TfidfVectorizer(ngram_range=(1, 2))
X = vectorizer.fit_transform(docs)

# Classifier
classifier = SVC(kernel='linear')
classifier.fit(X, labels)

# Predict
new_text = "This movie is amazing"
X_new = vectorizer.transform([new_text])
prediction = classifier.predict(X_new)
print(prediction)  # [1] (positive)

2. Language Modeling (Prediction)

# Предсказание следующего слова на основе N-grams
from collections import defaultdict, Counter

def build_ngram_model(text, n=2):
    """Построить N-gram модель для предсказания"""
    words = text.split()
    model = defaultdict(Counter)
    
    for i in range(len(words) - n):
        context = tuple(words[i:i+n-1])  # контекст (n-1 слов)
        next_word = words[i+n-1]  # следующее слово
        model[context][next_word] += 1
    
    return model

text = "the cat sat on the mat and the cat slept"
model = build_ngram_model(text, n=2)

# Предсказать следующее слово после "the"
context = ("the",)
if context in model:
    predictions = model[context].most_common(3)
    print(predictions)  # [('cat', 2), ('mat', 1)]

3. Spell Checking и Autocomplete

# Контекст помогает исправить опечатку
# "I went to the scool" → должно быть "school"

# С bigrams:
# Вероятность "the scool" низкая
# Вероятность "the school" высокая

# Для autocomplete:
# "I am going to" → predict next word
# bigrams: ["to the", "to visit", "to be", ...]
# Выбираем наиболее вероятное

4. Text Similarity

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

# Два текста
text1 = "I love machine learning"
text2 = "I enjoy deep learning"
text3 = "Dogs are animals"

# N-gram vectorization
vectorizer = CountVectorizer(analyzer='char', ngram_range=(2, 3))
X = vectorizer.fit_transform([text1, text2, text3])

# Similarity
similarity_1_2 = cosine_similarity(X[0], X[1])[0][0]
similarity_1_3 = cosine_similarity(X[0], X[2])[0][0]

print(f"Text 1 vs 2: {similarity_1_2:.2f}")  # ~0.8
print(f"Text 1 vs 3: {similarity_1_3:.2f}")  # ~0.1

Character N-grams vs Word N-grams

WORD N-GRAMS (более семантичные):
- Лучше для понимания смысла
- Менше данных (меньше возможных n-grams)
- Требуют tokenization
- Подходят для: classification, similarity

CHARACTER N-GRAMS (более структурные):
- Лучше для морфологии
- Больше данных (много символов)
- Не требуют tokenization
- Подходят для: spell checking, language detection, typos

Проблемы с N-grams

# 1. Sparse features (разреженные признаки)
# Много нулей в матрице признаков
vectorizer = CountVectorizer(ngram_range=(1, 3))
X = vectorizer.fit_transform(docs)
print(X.density)  # ~ 0.05 (95% нулей)

# 2. Curse of dimensionality
# Много признаков → нужно больше данных
# Для 3-grams на 100k словах может быть миллионы признаков

# 3. Потеря контекста
# N-grams игнорируют порядок и дальний контекст
# "John loves Mary" vs "Mary loves John" — одинаковые 1-grams

# 4. Не scalable
# Для больших текстов нужно хранить огромные матрицы

Modern Alternative: Word Embeddings

# Вместо N-grams используют embeddings (Word2Vec, GloVe, BERT)
from gensim.models import Word2Vec

text = [["I", "love", "machine", "learning"],
        ["I", "enjoy", "deep", "learning"]]

# Word2Vec (вместо n-grams)
model = Word2Vec(text, vector_size=100, window=2, min_count=1)

# Получить вектор слова
vector = model.wv['learning']
print(vector.shape)  # (100,)

# Similarity
similarity = model.wv.similarity('learning', 'machine')
print(similarity)  # ~0.8

Когда использовать N-grams

✓ Text classification (простые задачи)
✓ Language detection (какой язык)
✓ Spell checking (опечатки)
✓ Plagiarism detection (копирование)
✓ Autocomplete (предсказание следующего слова)
✓ Когда не нужен глубокий семантический анализ

✗ Когда нужен глубокий смысл (используй BERT, GPT)
✗ Когда текст очень длинный (слишком много n-grams)
✗ Multilingual (n-grams зависят от языка)

Вывод

N-grams это:

  • Простой способ представить текст для ML моделей
  • Последовательность N элементов (слов или символов)
  • Используется в классификации, языковом моделировании, similarity
  • Быстрые и интерпретируемые, но не capture семантику
  • Modern alternative: embeddings (Word2Vec, BERT)

Для интервью помни:

  • N-gram = последовательность N слов/символов
  • Используется для text features
  • Pros: быстро, simple
  • Cons: sparse, не понимает семантику
Что такое N-gram? | PrepBro