Polydesk-logotype
Polydesk.ai — Header

N-gram (N-gramme)

Un n-gram est une séquence contiguë de n éléments (mots, caractères ou syllabes) extraits d’un texte ou d’un signal. En NLP, un n-gram de mots capture les co-occurrences locales : un unigram (n=1) est un mot isolé, un bigram (n=2) est une paire de mots consécutifs, un trigram (n=3) est un triplet.

Prenons la phrase « Le chat dort sur le canapé ». Les unigrams sont : « Le », « chat », « dort », « sur », « le », « canapé ». Les bigrams : « Le chat », « chat dort », « dort sur », « sur le », « le canapé ». Les trigrams : « Le chat dort », « chat dort sur », « dort sur le », « sur le canapé ». Plus n augmente, plus le contexte capturé est large, mais plus le nombre de combinaisons possibles explose.

N-gram en bref
Catégorie
Représentation de texte / Modélisation du langage
Types courants
Unigram (n=1), Bigram (n=2), Trigram (n=3), 4-gram, 5-gram
Usage principal
Modèles de langage, feature extraction, prédiction de texte, classification
Librairies
NLTK (ngrams), scikit-learn (CountVectorizer, TfidfVectorizer), spaCy
Successeurs
RNN/LSTM, puis Transformers / LLM

Les types de n-grams

Unigram (n=1)

Un unigram est simplement un mot isolé. C’est la base du bag-of-words : chaque mot est traité indépendamment, sans contexte. Un modèle unigramme prédit la probabilité d’un mot uniquement à partir de sa fréquence globale dans le corpus, sans considérer les mots qui l’entourent. C’est rapide et simple, mais les phrases générées n’ont aucune cohérence syntaxique.

Bigram (n=2)

Un bigram est une paire de mots consécutifs. C’est le premier niveau qui capture du contexte : « intelligence artificielle », « machine learning », « New York » sont des bigrams porteurs de sens que les unigrams seuls ne peuvent pas représenter. Un modèle bigramme prédit le mot suivant en se basant sur le mot précédent : P(artificielle | intelligence). Les phrases générées commencent à montrer une cohérence locale mot-à-mot.

Trigram (n=3)

Un trigram est un triplet de mots consécutifs. Il capture un contexte plus large : « traitement du langage », « réseau de neurones », « taux de conversion ». Un modèle trigramme prédit le mot suivant à partir des deux mots précédents : P(langage | traitement du). Les phrases générées deviennent nettement plus cohérentes. Pour les corpus de grande taille (millions de mots), le trigram est souvent le choix par défaut car il offre un bon compromis entre contexte et stabilité statistique.

N-grams d’ordre supérieur (4-gram, 5-gram…)

Plus n augmente, plus le modèle capture de contexte. Un 4-gram utilise les 3 mots précédents, un 5-gram les 4 mots précédents. Mais le nombre de combinaisons possibles croît exponentiellement. Avec un vocabulaire de 30 000 mots, les bigrams possibles sont 30 000² = 900 millions, les trigrams 30 000³ = 27 billions. La plupart de ces combinaisons n’apparaissent jamais dans le corpus d’entraînement, créant un problème de parcimonie des données (data sparsity). C’est pourquoi en pratique, on dépasse rarement n=5.

N-grams comme modèles de langage

Historiquement, les modèles de langage n-gram ont été les premiers modèles probabilistes du langage naturel. Leur principe est simple : estimer la probabilité d’un mot en fonction des n-1 mots précédents. C’est l’hypothèse markovienne : le futur ne dépend que du passé récent.

Pour un modèle bigramme, la probabilité d’une phrase complète est approximée par le produit des probabilités conditionnelles de chaque bigram :

P("Le chat dort") ≈ P(Le|<s>) × P(chat|Le) × P(dort|chat) × P(</s>|dort)

<s> et </s> sont des tokens spéciaux marquant le début et la fin de la phrase. Les probabilités sont estimées par maximum de vraisemblance (MLE) sur un corpus d’entraînement :

P(chat|Le) = count("Le chat") / count("Le")

Le problème fondamental de cette approche est la parcimonie : de nombreux n-grams valides n’apparaissent jamais dans le corpus d’entraînement et reçoivent une probabilité de zéro. Plusieurs techniques de lissage (smoothing) existent pour y remédier : le lissage add-one (Laplace), le lissage Good-Turing, l’interpolation linéaire (moyenne pondérée des unigrams, bigrams et trigrams), et le backoff (recul vers un n-gram d’ordre inférieur quand le n-gram d’ordre supérieur n’est pas observé).

Du n-gram au transformer Les modèles de langage n-gram ont été largement supplanté par les réseaux de neurones récurrents (RNN/LSTM), eux-mêmes remplacés par les transformers. Les LLM modernes comme GPT ou Claude n’utilisent plus d’hypothèse markovienne : leur mécanisme d’attention leur permet de considérer l’intégralité du contexte disponible, pas seulement les n-1 mots précédents. Cependant, les concepts fondamentaux des n-grams (probabilités conditionnelles, perplexité, lissage) restent au coeur de la théorie des modèles de langage.

N-grams comme features en machine learning

L’usage le plus courant des n-grams aujourd’hui n’est pas la modélisation du langage mais l’extraction de features pour la classification de texte. En ajoutant des bigrams et trigrams au vocabulaire du bag-of-words ou de TF-IDF, vous capturez des expressions composées que les unigrams seuls ne voient pas.

Avec scikit-learn

from sklearn.feature_extraction.text import TfidfVectorizer

corpus = [
    "L'intelligence artificielle transforme le monde",
    "Le machine learning est une branche de l'IA",
    "Les réseaux de neurones sont puissants"
]

# Unigrams seulement
vec_uni = TfidfVectorizer(ngram_range=(1, 1))
X_uni = vec_uni.fit_transform(corpus)
print(f"Unigrams : {X_uni.shape[1]} features")

# Unigrams + bigrams
vec_bi = TfidfVectorizer(ngram_range=(1, 2))
X_bi = vec_bi.fit_transform(corpus)
print(f"Uni+Bigrams : {X_bi.shape[1]} features")

# Unigrams + bigrams + trigrams
vec_tri = TfidfVectorizer(ngram_range=(1, 3))
X_tri = vec_tri.fit_transform(corpus)
print(f"Uni+Bi+Trigrams : {X_tri.shape[1]} features")

Le paramètre ngram_range=(1, 2) génère tous les unigrams ET tous les bigrams. Le bigram « intelligence artificielle » devient un feature unique avec son propre score TF-IDF, ce qui permet au classifieur de reconnaître cette expression composée comme un concept distinct des mots « intelligence » et « artificielle » pris séparément.

Attention à l’explosion du vocabulaire Passer de (1,1) à (1,2) peut multiplier le nombre de features par 10 ou plus. Passer à (1,3) l’explose encore davantage. Utilisez max_features pour limiter la taille du vocabulaire, et min_df pour éliminer les n-grams très rares qui n’apportent rien à la classification.

Avec NLTK

from nltk import ngrams
from nltk.tokenize import word_tokenize

phrase = "Le traitement du langage naturel est fascinant"
tokens = word_tokenize(phrase, language='french')

# Générer des bigrams
bigrams = list(ngrams(tokens, 2))
print("Bigrams :", bigrams)
# [('Le', 'traitement'), ('traitement', 'du'), ('du', 'langage'),
#  ('langage', 'naturel'), ('naturel', 'est'), ('est', 'fascinant')]

# Générer des trigrams
trigrams = list(ngrams(tokens, 3))
print("Trigrams :", trigrams)
# [('Le', 'traitement', 'du'), ('traitement', 'du', 'langage'),
#  ('du', 'langage', 'naturel'), ('langage', 'naturel', 'est'),
#  ('naturel', 'est', 'fascinant')]

Cas d’usage

Prédiction de texte et autocomplétion

Les claviers de smartphones utilisent des modèles n-gram pour prédire le mot suivant. Si vous tapez « bonjour, comment », un modèle trigramme calcule P(mot | bonjour, comment) pour tous les mots du vocabulaire et propose les plus probables : « allez », « vas-tu », « ça ». Les LLM modernes ont pris le relais pour les systèmes avancés, mais les modèles n-gram restent utilisés dans les systèmes embarqués à faibles ressources.

Classification de texte améliorée

Ajouter des bigrams à un modèle TF-IDF améliore la classification de texte en capturant les expressions composées. La recherche montre que les trigrams et 4-grams sont particulièrement efficaces pour la détection de spam, où des expressions comme « gagnez maintenant », « offre limitée » ou « cliquez ici » sont des indicateurs forts.

Correction orthographique et détection de fautes

Les n-grams de caractères (et non de mots) sont utilisés pour la correction orthographique. Si le bigram de caractères « xz » a une probabilité très faible dans la langue française, le mot qui le contient est probablement mal orthographié. Cette approche est aussi utilisée pour la détection de langue : chaque langue a une distribution de n-grams de caractères unique.

Recherche d’information

Les moteurs de recherche utilisent les n-grams pour le matching de phrases. Quand un utilisateur recherche « intelligence artificielle », le moteur doit reconnaître cette expression comme un concept unique, pas comme deux mots séparés. L’indexation de bigrams dans Elasticsearch ou Solr permet ce type de matching.

Reconnaissance vocale

Les systèmes de reconnaissance vocale utilisent des modèles n-gram pour désambiguïser les mots acoustiquement similaires. Si le signal audio est ambigu entre « verre » et « vert », un modèle trigramme peut trancher en utilisant le contexte des mots précédents.

N-grams de caractères

Les n-grams ne se limitent pas aux mots. Les n-grams de caractères découpent le texte en séquences de caractères consécutifs. Pour le mot « bonjour », les trigrams de caractères sont : « bon », « onj », « njo », « jou », « our ».

Cette approche est particulièrement utile pour la détection de langue (chaque langue a une signature de n-grams de caractères unique), le matching approximatif (les fautes d’orthographe partagent souvent des n-grams de caractères avec le mot correct), et les langues agglutinantes (turc, finnois) où les mots peuvent être très longs et les approches par mots moins efficaces.

scikit-learn supporte les n-grams de caractères via le paramètre analyzer='char' ou analyzer='char_wb' (qui ne traverse pas les frontières de mots) :

from sklearn.feature_extraction.text import TfidfVectorizer

# N-grams de caractères (traversant les mots)
vec = TfidfVectorizer(analyzer='char', ngram_range=(2, 4))

# N-grams de caractères (respectant les frontières de mots)
vec_wb = TfidfVectorizer(analyzer='char_wb', ngram_range=(2, 4))

Limites des n-grams

Parcimonie des données (data sparsity)

C’est le problème majeur. Avec un vocabulaire de V mots, le nombre de n-grams possibles est V^n. Pour V = 30 000 et n = 3, on obtient 27 × 10¹² trigrams possibles. L’immense majorité n’apparaîtra jamais dans aucun corpus d’entraînement réaliste. Les techniques de lissage atténuent le problème mais ne le résolvent pas fondamentalement.

Contexte limité

Un n-gram ne capture que le contexte local de n mots consécutifs. Les dépendances à longue distance (par exemple, un sujet en début de phrase lié à un verbe en fin de phrase) sont invisibles pour les modèles n-gram. C’est précisément ce que les transformers résolvent avec le mécanisme d’attention qui considère toute la séquence.

Mots hors vocabulaire (OOV)

Un n-gram contenant un mot absent du corpus d’entraînement reçoit une probabilité de zéro (sans lissage). Les techniques de BPE (Byte Pair Encoding) utilisées par les tokenizers modernes résolvent ce problème en découpant les mots inconnus en sous-unités connues.

Explosion de la dimensionnalité

En feature extraction, passer des unigrams aux bigrams puis aux trigrams multiplie le nombre de features de manière exponentielle. Un corpus qui génère 10 000 unigrams peut facilement produire 100 000 bigrams et 500 000 trigrams. Les paramètres max_features, max_df et min_df de scikit-learn sont indispensables pour contrôler cette explosion.

Bonnes pratiques en production

Commencez toujours par des unigrams + bigrams (ngram_range=(1,2)). C’est le ratio coût/bénéfice optimal pour la plupart des tâches de classification. N’ajoutez des trigrams que si vos données contiennent beaucoup d’expressions à trois mots porteuses de sens dans votre domaine (par exemple « taux de change », « intelligence artificielle générale », « deep reinforcement learning »).

Filtrez systématiquement les n-grams rares avec min_df=2 ou min_df=5. Un bigram qui n’apparaît que dans un seul document n’apporte aucune information de classification et gonfle le vocabulaire inutilement. Inversement, max_df=0.95 élimine les n-grams omniprésents qui ne discriminent rien.

Combinez les n-grams avec le prétraitement. Appliquez le stemming ou la lemmatisation avant la génération de n-grams pour regrouper les variantes morphologiques. « réseau neuronal » et « réseaux neuronaux » deviendront le même bigram si vous lemmatisez au préalable.

Pour les n-grams de caractères, utilisez analyzer='char_wb' plutôt que analyzer='char' : la variante char_wb ne traverse pas les frontières de mots, ce qui évite de créer des n-grams artificiels à la jonction de deux mots. Les n-grams de caractères sont particulièrement utiles comme features complémentaires aux n-grams de mots, surtout pour les textes bruités (fautes d’orthographe, abréviations, langage SMS).

Évaluez systématiquement l’impact de chaque configuration. Lancez votre pipeline avec (1,1), (1,2) et (1,3), mesurez la précision, le rappel et le F1-score sur un jeu de test. Dans beaucoup de cas, le gain entre (1,2) et (1,3) est marginal tandis que le temps de calcul et la mémoire augmentent considérablement.

N-grams dans l’évaluation des modèles de langage

Les n-grams jouent un rôle central dans les métriques d’évaluation des modèles de génération de texte. La métrique BLEU (Bilingual Evaluation Understudy), standard pour la traduction automatique, compare les n-grams du texte généré avec ceux du texte de référence. Un score BLEU-4 par exemple mesure la proportion de 4-grams du texte généré qui se retrouvent dans la référence.

La perplexité (perplexity) est une autre métrique fondamentale qui quantifie à quel point un modèle de langage est « surpris » par un texte de test. Plus la perplexité est basse, mieux le modèle prédit la séquence. Cette métrique reste utilisée pour évaluer les LLM modernes, même si les modèles sous-jacents ne sont plus des n-grams.

Le skip-gram : variante des n-grams

Le skip-gram, rendu célèbre par Word2Vec, est une extension des n-grams qui autorise des « trous » dans la séquence. Un k-skip-n-gram est une sous-séquence de longueur n dont les éléments peuvent être séparés par au plus k positions. Cela permet de capturer des relations entre mots non adjacents.

Dans Word2Vec, le modèle Skip-Gram prédit les mots du contexte à partir d’un mot central, produisant les célèbres word embeddings où les relations sémantiques sont encodées par des opérations vectorielles (roi – homme + femme ≈ reine). C’est le pont entre les n-grams classiques et les représentations denses modernes.


Questions fréquentes sur les n-grams

Qu’est-ce qu’un n-gram en NLP ?

Un n-gram est une séquence contiguë de n éléments extraits d’un texte. Avec n=1, c’est un unigram (un mot). Avec n=2, c’est un bigram (deux mots consécutifs, comme « machine learning »). Avec n=3, c’est un trigram (trois mots, comme « traitement du langage »). Les n-grams servent à capturer le contexte local dans les modèles de langage, la classification de texte, la prédiction de mots et la recherche d’information.

Quelle valeur de n choisir ?

Pour la classification de texte avec TF-IDF, ngram_range=(1,2) (unigrams + bigrams) est le choix le plus courant. Les trigrams apportent parfois un gain marginal au prix d’une forte augmentation de la dimensionnalité. Pour les modèles de langage probabilistes, les trigrams sont le standard avec de grands corpus (millions de mots), les bigrams pour les corpus plus petits. Pour la détection de spam, les trigrams et 4-grams sont particulièrement efficaces. Testez toujours plusieurs configurations sur vos données.

Quelle est la différence entre n-gram et bag-of-words ?

Le bag-of-words standard utilise des unigrams (n=1) : chaque mot est traité indépendamment. Les n-grams étendent cette approche en ajoutant des séquences de mots. Un bag-of-words avec ngram_range=(1,2) inclut à la fois les mots individuels ET les paires de mots consécutifs. C’est une version enrichie du bag-of-words qui capture partiellement l’ordre des mots.

Les n-grams sont-ils encore utilisés avec les LLM ?

Les modèles de langage n-gram ont été remplacés par les transformers et les LLM pour la génération de texte et la modélisation du langage. Cependant, les n-grams restent utilisés comme features pour la classification de texte (TF-IDF avec bigrams), pour l’évaluation des LLM (métriques comme BLEU utilisent des n-grams), dans les systèmes embarqués à faibles ressources (autocomplétion sur mobile), et pour la détection de langue ou la correction orthographique.

Comment implémenter les n-grams en Python ?

Deux approches principales. Avec NLTK : from nltk import ngrams, puis bigrams = list(ngrams(tokens, 2)). Avec scikit-learn pour la classification : TfidfVectorizer(ngram_range=(1, 2)) génère automatiquement les unigrams et bigrams comme features TF-IDF. scikit-learn supporte aussi les n-grams de caractères avec analyzer='char'. Limitez toujours la taille du vocabulaire avec max_features pour éviter l’explosion de la dimensionnalité.

Polydesk.ai — Footer