🚀 SpaCy – Le NLP "Industriel" en Python
Guide complet IDEO-Lab : Pipeline, Doc, Token, NER, Matcher & Vecteurs.
Vue d'ensemble
NLP "Industriel" (Production). Rapide (Cython), "Opinionated".
NLP Python CythonPourquoi SpaCy ?
Production (vs NLTK) & Léger (vs Transformers). API simple.
Production PerformanceInstallation (pip)
pip install spacy (librairie) + spacy download (modèles).
Les Modèles (Pipelines)
en_core_web_sm (small), _md (medium), _lg (large), _trf (Transformer).
Concept N°1 : nlp (Le Pipeline)
L'objet nlp (chargé via spacy.load()) est le pipeline.
Concept N°2 : Le Doc
Le conteneur (doc = nlp(text)). N'est PAS un string.
Concept N°3 : Token
Les objets dans le Doc (mots, ponctuation). Attributs riches.
Concept N°4 : Span
Un "slice" (tranche) du Doc. doc[2:5]. (Les Entités sont des Spans).
Tokenization
Gère les exceptions ("U.S.", "c'est"). doc[i].
POS Tagging (Grammaire)
token.pos_ (simple: 'VERB'), token.tag_ (détaillé: 'VBG').
Lemmatization
token.lemma_ ("running" -> "run"). (Racine du mot).
NER (Named Entity Recognition)
doc.ents (PERSON, ORG, GPE). ent.label_.
Dependency Parsing (Syntaxe)
token.head (parent), token.dep_ (relation, ex: 'nsubj').
Vecteurs & Similarité
(Modèles md/lg). doc1.similarity(doc2). (Word2Vec).
Matcher (Rule-based)
Trouver des "patterns" (basés sur les Tokens, ex: {'LOWER': 'hello'}).
PhraseMatcher (Texte)
Trouver des listes de mots (dictionnaires). Rapide.
PhraseMatcher DictionaryPipeline (Custom)
nlp.add_pipe("mon_etape"). Modifier le pipeline.
Vitrine (Qui l'utilise ?)
Hugging Face (Tokenizers), Entreprises Tech (Chatbots, Parsing).
Hugging Face ChatbotsLiens Utiles & Formation
spacy.io (Docs), course.spacy.io (Cours gratuit).
Cheat-sheet
Workflow (Load, nlp(text), doc.ents, token.pos_).
cheat WorkflowQu'est-ce que SpaCy ?
SpaCy est une bibliothèque **Python** (avec des modules C/Cython) pour le **Natural Language Processing (NLP)**.
Elle est conçue pour être **rapide, efficace et prête pour la production**. On parle de NLP "Industriel".
Contrairement à NLTK (académique/flexible), SpaCy est **"opinionated"** (dogmatique) : elle fournit *une* seule (la meilleure/plus rapide) implémentation pour chaque tâche (ex: 1 Tagger, 1 Parser).
Diagramme : L'Écosystème NLP
+-------------------------+
| NLTK (Academic) |
| (Recherche, Flexibilité) |
+-------------------------+
| (Alternative)
▼
+-------------------------+
| SpaCy (Production) | <-- (Base/Tokenizer pour)
| (Vitesse, Efficacité) |
+-------------------------+
| (Alternative)
▼
+-------------------------+
| Hugging Face Transformers |
| (SOTA, Lourd, DL) |
+-------------------------+
Le choix de l'outil NLP dépend de la tâche.
| Critère | SpaCy | NLTK (Legacy) | Hugging Face Transformers |
|---|---|---|---|
| Objectif | Production (API, Web apps) | Éducation (Recherche, exploration) | State-of-the-Art (SOTA) (Deep Learning) |
| Performance | Très rapide (Optimisé C/Cython) | Lent (Python pur) | Lourd (Nécessite PyTorch/TF, GPU) |
| Philosophie | "Opinionated" (1 meilleur algo) | Flexible (Accès à tous les algos) | Flexible (basé sur DL) |
| Cas d'usage | Parsing, NER, Chatbots, Extraction. | Apprentissage, prototypage d'algos. | Traduction, Résumé, Question/Answering. |
L'installation se fait en deux étapes : 1. Installer la bibliothèque. 2. Télécharger les modèles (pipelines) entraînés.
1. Installer SpaCy
# (Recommandé: dans un venv) pip install spacy
2. Télécharger les Modèles
Les modèles contiennent les "poids" (neurones) pour le Tagger, le NER, etc. (Voir 1.4 pour les tailles).
# (Ex: Télécharger le petit modèle anglais) python -m spacy download en_core_web_sm # (Ex: Télécharger le petit modèle français) python -m spacy download fr_core_news_sm
3. Charger (en Python)
import spacy
# (Charge le modèle. C'est l'objet "pipeline")
nlp = spacy.load("en_core_web_sm")
Les modèles (ex: en_core_web_sm) sont des pipelines pré-entraînés. La convention de nommage est : [lang]_[type]_[genre]_[taille].
| Suffixe | Taille | Vecteurs (Word2Vec) ? | Usage |
|---|---|---|---|
_sm (small) | ~10-20 MB | Non (Context-vectors) | Dev, Test, NER/POS basique. |
_md (medium) | ~40-90 MB | Oui (Inclus) | Standard. (Permet .similarity()). |
_lg (large) | ~500-700 MB | Oui (Plus grands) | Meilleure précision, similarité. |
_trf (transformer) | ~400+ MB | Non (Contextuel/BERT) | State-of-the-art (SOTA), mais plus lent. |
# (Français, Core (Général), News, Medium)
nlp_fr = spacy.load("fr_core_news_md")
# (Anglais, Core (Général), Web, Transformer)
nlp_en_trf = spacy.load("en_core_web_trf")
nlpL'objet nlp (chargé via spacy.load()) n'est pas "juste" un modèle, c'est un **pipeline** (une chaîne) de composants de traitement.
Quand vous appelez doc = nlp(text), le texte traverse ce pipeline.
Diagramme (Pipeline _sm typique)
(Votre texte: "Apple is looking...")
|
▼
+-------------------------+
| nlp("...") |
+-------------------------+
|
▼
+-------------------------+
| 1. tokenizer | (Sépare en Tokens: "Apple", "is", ...)
+-------------------------+
|
▼
+-------------------------+
| 2. tagger | (POS Tagging: PROPN, VERB, ...)
+-------------------------+
|
▼
+-------------------------+
| 3. parser | (Dependency Parsing: nsubj, aux, ...)
+-------------------------+
|
▼
+-------------------------+
| 4. ner | (Named Entity: "Apple" -> ORG)
+-------------------------+
|
▼
+-------------------------+
| (Autres: lemmatizer...) |
+-------------------------+
|
▼
(Votre objet "Doc")
DocL'objet Doc est le conteneur central de SpaCy. Il est retourné par nlp(text).
Un Doc n'est **PAS** un string. C'est un objet (type Séquence) qui contient les Tokens et toutes leurs annotations (POS, NER, ...).
nlp = spacy.load("en_core_web_sm")
text = "Apple is looking at buying U.K. startup for $1 billion."
# (Le pipeline tourne ici)
doc = nlp(text)
# 1. Itérer sur les Tokens
for token in doc:
print(token.text)
# 2. Accéder aux Entités (NER)
for ent in doc.ents:
print(ent.text, ent.label_)
# 3. Accéder aux Phrases
for sent in doc.sents:
print(sent.text)
TokenLe Token est l'objet qui représente un mot, un signe de ponctuation, etc. C'est là que se trouvent 90% des informations.
Attributs (Note : Le _ (ex: .lemma_) signifie que l'attribut est un "hash" (entier) et que SpaCy retourne le string (lookup).
| Attribut | Description | Exemple (pour "running") |
|---|---|---|
.text | Texte (String) verbatim. | "running" |
.lemma_ | Lemme (base) du mot. (Voir 3.3) | "run" |
.pos_ | POS Tag (Simple, UDS). (Voir 3.2) | "VERB" |
.tag_ | POS Tag (Détaillé, Treebank). (Voir 3.2) | "VBG" |
.dep_ | Dépendance syntaxique. (Voir 4.1) | "nsubj" (sujet) |
.head | Le "parent" syntaxique (Token). (Voir 4.1) | (ex: Token(is)) |
.is_alpha | Bool: Est-ce alphabétique ? | True |
.is_stop | Bool: Est-ce un "stop word" (mot vide) ? | False |
.is_punct | Bool: Est-ce une ponctuation ? | False |
SpanUn Span est un "slice" (une tranche) d'un Doc (une vue sur un ou plusieurs Tokens). C'est plus efficace qu'une liste de tokens.
doc.ents (Entités) et doc.sents (Phrases) sont des générateurs de Spans.
doc = nlp("Apple is looking at buying U.K. startup.")
// 1. Span manuel (slice du Doc)
span = doc[2:5] // "looking at buying"
print(span.text)
// 2. Spans (via .ents)
for ent in doc.ents:
// (ent est un objet Span)
print(ent.text, ent.label_)
// Apple ORG
// U.K. GPE
// 3. Spans (via .sents)
for sent in doc.sents:
print(sent.text)
La tokenization (étape 1 du pipeline) est la séparation du texte en Tokens. C'est plus complexe qu'un simple .split(' ').
SpaCy utilise des règles (spécifiques à la langue) pour gérer les exceptions (ponctuation, abréviations, contractions...).
// Python simple (Mauvais)
text = "It's $10. U.S.A."
print(text.split(' '))
// ['It's', '$10.', 'U.S.A.'] (3 tokens)
// SpaCy (Correct)
doc = nlp(text)
print([token.text for token in doc])
// ['It', "'s", '$', '10', '.', 'U.S.A.'] (6 tokens)
Le Part-of-Speech Tagging assigne un rôle grammatical (Verbe, Nom, Adjectif...) à chaque Token.
token.pos_: Tag simple (Universal Dependencies).token.tag_: Tag détaillé (Spécifique au modèle, ex: Penn Treebank).
doc = nlp("She is running fast.")
// (text, lemma, pos_, tag_)
for token in doc:
print(f"{token.text:<10} {token.lemma_:<10} {token.pos_:<10} {token.tag_:<10}")
// (Output:)
// She she PRON PRP
// is be AUX VBZ
// running run VERB VBG (<- tag_ est plus précis)
// fast fast ADV RB
// . . PUNCT .
La Lemmatization réduit un mot à sa "racine" (lemme), en utilisant le contexte grammatical (POS).
(C'est plus "intelligent" que le **Stemming** (ex: PorterStemmer), qui coupe juste la fin des mots (ex: "running" -> "runn")).
doc = nlp("I saw two mice. He is running.")
for token in doc:
print(f"{token.text} -> {token.lemma_}")
// (Output:)
// I -> I
// saw -> see (Utilise le contexte VERB)
// two -> two
// mice -> mouse (Utilise le dictionnaire)
// . -> .
// He -> he
// is -> be
// running -> run
// . -> .
Le NER est un des cas d'usage majeurs. Il extrait les "Entités Nommées" (Personnes, Lieux, Organisations...) du texte.
Les entités sont accessibles via doc.ents (ce sont des Spans).
text = "Apple is looking at buying U.K. startup (DeepMind) for $1 billion."
doc = nlp(text)
for ent in doc.ents:
print(f"Texte: {ent.text:<10} | Label: {ent.label_:<8} | Start: {ent.start_char:<3} | End: {ent.end_char:<3}")
// (Output:)
// Texte: Apple | Label: ORG | Start: 0 | End: 5
// Texte: U.K. | Label: GPE | Start: 27 | End: 31
// Texte: DeepMind | Label: ORG | Start: 41 | End: 49
// Texte: $1 billion | Label: MONEY | Start: 55 | End: 65
// (Visualisation rapide dans Jupyter/Notebook)
from spacy import displacy
displacy.render(doc, style="ent")
Le "Parser" (analyseur syntaxique) établit les relations grammaticales entre les mots. (Ex: Quel est le sujet du verbe ?).
token.head: Le "parent" (leTokendont ce mot dépend).token.dep_: Le type de relation (ex:nsubj(sujet nominal),dobj(objet direct)).
Diagramme (Texte)
doc = nlp("I saw a cat.")
// (Texte, Dépendance, Parent)
for token in doc:
print(f"{token.text:<10} {token.dep_:<8} {token.head.text:<10}")
// (Output:)
// I nsubj saw
// saw ROOT saw
// a det cat
// cat dobj saw
// . punct saw
// (Diagramme :)
// (saw) <-- (I) [nsubj]
// |
// (saw) --> (cat) [dobj]
// |
// (cat) <-- (a) [det]
Les modèles _md (medium) et _lg (large) incluent des **Word Vectors** (ex: Word2Vec).
SpaCy utilise ces vecteurs (des ndarray NumPy) pour calculer la **similarité sémantique** (similarité cosinus).
// (IMPORTANT: Charger un modèle MD ou LG)
nlp = spacy.load("en_core_web_md")
doc1 = nlp("The cat eats fish.")
doc2 = nlp("My dog likes meat.")
doc3 = nlp("I play guitar.")
// 1. Similarité (Doc vs Doc)
// (Moyenne des vecteurs des mots)
print(doc1.similarity(doc2)) // (Haut, ex: ~0.8)
print(doc1.similarity(doc3)) // (Bas, ex: ~0.3)
// 2. Similarité (Token vs Token)
token_cat = doc1[1] // "cat"
token_dog = doc2[1] // "dog"
print(token_cat.similarity(token_dog)) // (Haut, ex: ~0.85)
// 3. Accéder au Vecteur (NumPy array)
print(token_cat.vector.shape) // (300,)
Le Matcher (basé sur les règles) est plus puissant qu'un Regex. Il permet de trouver des "patterns" (motifs) basés sur les **attributs des Tokens** (LOWER, POS, IS_PUNCT...).
from spacy.matcher import Matcher
nlp = spacy.load("en_core_web_sm")
matcher = Matcher(nlp.vocab) // (Initialiser avec le vocabulaire)
// 1. Définir le "pattern" (motif)
// (Ex: "Hello", suivi d'une virgule (optionnelle),
// suivi d'un Nom Propre (PROPN))
pattern = [
{'LOWER': 'hello'},
{'IS_PUNCT': True, 'OP': '?'}, // ('OP': '?' = optionnel)
{'POS': 'PROPN'}
]
// 2. Ajouter le pattern au Matcher
matcher.add("GREETING_PATTERN", [pattern])
// 3. Appliquer
doc = nlp("I said: Hello, Bob! and Hello Alice.")
matches = matcher(doc)
// 4. Résultats
for match_id, start, end in matches:
span = doc[start:end] // (C'est un Span)
print(span.text)
// (Output:)
// Hello, Bob
// Hello Alice
Pour trouver des listes (dictionnaires) de mots/phrases exactes. C'est beaucoup plus rapide que le Matcher si vous n'avez pas besoin d'attributs (POS, etc.).
from spacy.matcher import PhraseMatcher
nlp = spacy.load("en_core_web_sm")
matcher = PhraseMatcher(nlp.vocab)
// 1. Définir les termes (le dictionnaire)
// (Doivent être des objets 'Doc')
terms = ["Elon Musk", "Tesla", "SpaceX"]
patterns = [nlp(text) for text in terms]
// 2. Ajouter les patterns
matcher.add("TECH_COMPANIES", patterns)
// 3. Appliquer
doc = nlp("Elon Musk is the CEO of Tesla and SpaceX.")
matches = matcher(doc)
for match_id, start, end in matches:
span = doc[start:end]
print(span.text)
// (Output:)
// Elon Musk
// Tesla
// SpaceX
On peut (et on doit) modifier le pipeline pour l'optimiser (ex: désactiver le ner si inutile) ou pour ajouter nos propres étapes (ex: un classifieur de sentiment).
1. Désactiver (Pour la vitesse)
// (Ex: On ne veut que la Tokenization + Lemmatization)
nlp = spacy.load(
"en_core_web_sm",
disable=["parser", "ner"] // (Désactive ces étapes)
)
// (Liste des étapes actives)
print(nlp.pipe_names) // ['tok2vec', 'tagger', 'attribute_ruler', 'lemmatizer']
2. Ajouter (Custom)
// (Une fonction simple qui prend le 'doc')
@spacy.Language.factory("mon_composant")
def mon_composant_func(nlp, name):
def process_doc(doc):
print(f"Doc a {len(doc)} tokens.")
return doc
return process_doc
// (Ajouter à la fin du pipeline)
nlp.add_pipe("mon_composant", last=True)
// (ou first=True, or before="ner", after="tagger")
doc = nlp("Test.") // (Affiche: "Doc a 2 tokens.")
SpaCy est le standard "de facto" pour le NLP en production (hors SOTA Transformers).
| Entreprise / Projet | Cas d'usage |
|---|---|
| Hugging Face 🤗 | Utilise (ou intègre) souvent le tokenizer de SpaCy comme "tokenizer pré-processing" rapide avant leurs modèles Transformers. |
| Entreprises Tech (Chatbots) | Utilisé pour le "Intent Recognition" (Matcher) et l'extraction d'entités (NER) dans les chatbots (ex: Rasa). |
| Analyse Média / Finance | Parsing de millions d'articles (News) pour extraire (NER) les noms d'entreprises (ORG), les personnes (PERSON) et les lieux (GPE). |
| Analyse de CV (HR Tech) | Utilise le Matcher et le NER pour extraire les compétences, les diplômes et les entreprises (parsing de PDF/Docx). |
Ressources pour apprendre et travailler avec SpaCy.
| Site | Description |
|---|---|
| spacy.io | Le site officiel. Documentation excellente, claire et moderne. |
| spacy.io/usage/models | Tableau de bord des modèles (langues, tailles, performances). |
| course.spacy.io | Le **Cours Avancé NLP** (gratuit) par les créateurs (Ines Montani). Hautement recommandé. |
| spacy.io (Docs API) | La documentation de référence (ex: attributs de Token). |
1. Setup
import spacy
from spacy.matcher import Matcher
# 1. Charger le pipeline
nlp = spacy.load("en_core_web_sm")
2. Traiter
text = "Apple Inc. (Steve Jobs) is a U.S. company." doc = nlp(text)
3. Extraire (Token & Entités)
// A. Itérer sur les Tokens
for token in doc:
print(
f"{token.text:<10} | "
f"{token.lemma_:<10} | "
f"{token.pos_:<6} | "
f"{token.is_stop}"
)
// (Ex: Apple | Apple | PROPN | False)
// B. Extraire les Entités (NER)
for ent in doc.ents:
print(
f"{ent.text:<15} | "
f"{ent.label_}"
)
// (Ex: Apple Inc. | ORG)
// (Ex: Steve Jobs | PERSON)
// (Ex: U.S. | GPE)
4. Matcher (Règles)
matcher = Matcher(nlp.vocab)
pattern = [{'TEXT': 'Apple'}, {'IS_PUNCT': True, 'OP': '?'}]
matcher.add("APPLE_PATTERN", [pattern])
matches = matcher(doc)
